diff --git a/.azure-pipelines/client.yml b/.azure-pipelines/client.yml index fc977f4e85253..4f0b8f0df83c1 100644 --- a/.azure-pipelines/client.yml +++ b/.azure-pipelines/client.yml @@ -26,6 +26,11 @@ jobs: JavaVersion: '1.11' steps: + - script: | + echo "##vso[build.addbuildtag]Scheduled" + displayName: 'Tag scheduled builds' + condition: and(eq(variables['Build.SourceBranchName'],'master'),eq(variables['Build.Reason'],'Schedule')) + - task: Maven@3 displayName: 'Build and Package' inputs: @@ -73,7 +78,7 @@ jobs: displayName: 'Install reporting tools' inputs: mavenPomFile: pom.client.xml - options: '$(DefaultOptions) -Dinclude-non-shipping-modules -DskipTests -Dgpg.skip' + options: '$(DefaultOptions) -Djava-lts -Dinclude-non-shipping-modules -DskipTests -Dgpg.skip' mavenOptions: '$(LoggingOptions)' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' @@ -85,7 +90,7 @@ jobs: displayName: 'Generate Maven project site, including JavaDocs, SpotBugs, and CheckStyle reports' inputs: mavenPomFile: pom.client.xml - options: '$(DefaultOptions) -DskipTests -Dgpg.skip' + options: '$(DefaultOptions) -Djava-lts -DskipTests -Dgpg.skip' mavenOptions: '$(LoggingOptions)' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' diff --git a/.azure-pipelines/docs.yml b/.azure-pipelines/docs.yml new file mode 100644 index 0000000000000..f83f220ff14dc --- /dev/null +++ b/.azure-pipelines/docs.yml @@ -0,0 +1,133 @@ +trigger: + - master + +variables: + DefaultOptions: '--batch-mode -Dmaven.wagon.http.pool=false' + LoggingOptions: '-Dorg.slf4j.simpleLogger.defaultLogLevel=error -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn' + +jobs: + - job: 'Generate_Track_2' + variables: + skipComponentGovernanceDetection: true + timeoutInMinutes: 120 + pool: + vmImage: 'vs2017-win2016' + + steps: + - powershell: | + copy eng/repo-docs/index.html $(Build.ArtifactStagingDirectory) + displayName: 'Copy index to artifact staging' + + - task: PublishPipelineArtifact@0 + condition: succeededOrFailed() + displayName: 'Publish index artifact' + inputs: + artifactName: index + targetPath: $(Build.ArtifactStagingDirectory) + + # We `install` separately from running `site:site site:stage` so that the `install` brings in the non-shipping-modules, + # but we don't include them in the Maven site commands (so that we don't generate reports for the non-shipping modules). + - task: Maven@3 + displayName: 'Install reporting tools' + inputs: + mavenPomFile: pom.client.xml + options: '$(DefaultOptions) -Djava-lts -Dinclude-non-shipping-modules -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'install' + + - task: Maven@3 + displayName: 'Generate Doc Site' + inputs: + mavenPomFile: pom.client.xml + options: '$(DefaultOptions) -Djava-lts -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'site:site site:stage' + + - task: Maven@3 + displayName: 'Install azure-sdk-parent' + inputs: + mavenPomFile: parent/pom.xml + options: '$(DefaultOptions) -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.11' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'install' + + - powershell: | + copy -r target/staging/apidocs $(Build.ArtifactStagingDirectory)/client + displayName: 'Copy reports to artifact staging' + + - task: PublishPipelineArtifact@0 + condition: succeededOrFailed() + displayName: 'Publish reports artifact' + inputs: + artifactName: track2reports + targetPath: $(Build.ArtifactStagingDirectory)/client + + - job: 'Generate_Track_1' + variables: + skipComponentGovernanceDetection: true + timeoutInMinutes: 120 + pool: + vmImage: 'vs2017-win2016' + + steps: + # We `install` separately from running `site:site site:stage` so that the `install` brings in the non-shipping-modules, + # but we don't include them in the Maven site commands (so that we don't generate reports for the non-shipping modules). + - task: Maven@3 + displayName: 'Install client.xml to get spotbugs reporting' + inputs: + mavenPomFile: pom.client.xml + options: '$(DefaultOptions) -Dinclude-non-shipping-modules -Dmaven.javadoc.skip=true -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'install' + + - task: Maven@3 + displayName: 'Install Data Packages' + inputs: + mavenPomFile: pom.data.xml + options: '$(DefaultOptions) -Dinclude-non-shipping-modules -Dmaven.javadoc.skip=true -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'install' + + - task: Maven@3 + displayName: 'Generate Doc Site' + inputs: + mavenPomFile: pom.data.xml + options: '$(DefaultOptions) -DskipTests -Dgpg.skip' + mavenOptions: '$(LoggingOptions)' + javaHomeOption: 'JDKVersion' + jdkVersionOption: '1.8' + jdkArchitectureOption: 'x64' + publishJUnitResults: false + goals: 'site:site' + + - powershell: | + copy -r target/site/apidocs $(Build.ArtifactStagingDirectory)/data + displayName: 'Copy reports to artifact staging' + + - task: PublishPipelineArtifact@0 + condition: succeededOrFailed() + displayName: 'Publish reports artifact' + inputs: + artifactName: track1reports + targetPath: $(Build.ArtifactStagingDirectory)/data + diff --git a/README.md b/README.md index 27b268ef33dac..02243f5344921 100644 --- a/README.md +++ b/README.md @@ -1,145 +1,57 @@ -> :warning: *NOTE: The **Azure Libraries for Java** project (resource management APIs with fluent interface design pattern) has moved to http://github.com/azure/azure-libraries-for-java, so please log issues for that project in that new repository. This repository is now dedicated to other, auto-generated, non-management Azure SDKs only.* - -# Azure SDKs for Java - -| Component | Build Status | -| --------- | ------------ | -| Management Libraries | [![Build Status](https://travis-ci.org/Azure/azure-sdk-for-java.svg?branch=master)](https://travis-ci.org/Azure/azure-sdk-for-java) | -| Client Libraries | [![Build Status](https://dev.azure.com/azure-sdk/public/_apis/build/status/17?branchName=master)](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=17)
[![Build Documentation](https://img.shields.io/badge/documentation-published-blue.svg)](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/index.html)| - -:+1: [Try Azure for FREE](http://go.microsoft.com/fwlink/?LinkId=330212) - -This repository contains Azure SDKs enabling the programmatic *consumption* of miscellaneous Azure services (i.e. *not management* - for that see http://github.com/azure/azure-libraries-for-java) - -Currently, this repository contains the following Azure SDKs: - -* [Media Services](#media-services) -* [Cognitive Services](#cognitive-services) - * [Search](#search) - * [Entity Search](#entity-search) - * [Language](#language) - * [Text Analytics](#text-analytics) - * [Vision](#vision) - * [Face API](#face-api) -* [Azure Event Grid](#azure-event-grid) - -## Other Azure SDKs - -These other Azure SDKs for Java, that are not currently in this repository, can be found as follows: - -* [Azure ActiveDirectory Authentication Library (ADAL)](https://github.com/AzureAD/azure-activedirectory-library-for-java) -* [Azure Batch SDK for Java](https://github.com/azure/azure-batch-sdk-for-java) -* [Azure Data Lake Store Client for Java](https://github.com/Azure/azure-data-lake-store-java) -* [Azure DocumentDB (CosmosDB) SDK for Java](https://github.com/Azure/azure-documentdb-java) -* [Azure CosmosDB Async SDK for Java](https://github.com/Azure/azure-cosmosdb-java) -* [Azure Key Vault SDK for Java](https://github.com/Azure/azure-keyvault-java) -* [Azure Service Bus SDK for Java](https://github.com/Azure/azure-service-bus-java) -* [Azure Storage SDK for Java](https://github.com/Azure/azure-storage-java) -* [Azure Storage SDK Async for Java](https://github.com/Azure/azure-storage-java-async) -* [Azure Functions SDK for Java](https://github.com/Azure/azure-functions-java-worker) -* [Azure IoT SDK for Java](https://github.com/Azure/azure-iot-sdk-java) -* [Azure Event Hub SDK for Java]() -* [Azure Notification Hubs for Java](https://github.com/Azure/azure-notificationhubs-java-backend) -* [Azure Management Libraries for Java](https://github.com/azure/azure-libraries-for-java) - -Other libraries: -* [Microsoft JDBC Driver for SQL Server](https://github.com/Microsoft/mssql-jdbc) - -## General Information -* [Prerequisites](#prerequisites) -* [Help and issues](#help-and-issues) -* [Contribute code](#contribute-code) - -## Cognitive Services - -The following projects provide Java APIs for [Azure Cognitive Services](https://azure.microsoft.com/en-us/services/cognitive-services/), empowering your applications with intelligent algorithms that enable them to see, hear, speak and understand. - -* *Language* - * **Spell Check** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-spellcheck) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-spellcheck%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3ASpellCheck) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/spell-check/) | - | --- | --- | --- | --- | --- | - * **Text Analytics** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-textanalytics) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-language%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/TextAnalytics) | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3ATextAnalytics) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/text-analytics/) | - | --- | --- | --- | --- | --- | - -* *Search* - * **Custom Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-customsearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-customsearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3ACustomSearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-custom-search-api/) | - | --- | --- | --- | --- | --- | - * **Entity Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-entitysearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-entitysearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AEntitySearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-entity-search-api/) | - | --- | --- | --- | --- | --- | - * **Image Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-imagesearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-imagesearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AImageSearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-image-search-api/) | - | --- | --- | --- | --- | --- | - * **News Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-newssearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-newssearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3ANewsSearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-news-search-api/) | - | --- | --- | --- | --- | --- | - * **Video Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-videosearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-videosearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7)| [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AVideoSearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-video-search-api/) | - | --- | --- | --- | --- | --- | - * **Web Search** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-websearch) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-websearch%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/BingSearchV7) | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AWebSearch) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/bing-web-search-api/) | - | --- | --- | --- | --- | --- | - -* *Vision* - * **Computer Vision** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-computervision) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-computervision%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/ComputerVision) | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AComputerVision) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/computer-vision) | - | --- | --- | --- | --- | --- | - * **Content Moderator** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-contentmoderator) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-cognitiveservices-contentmoderator%22) | [:pencil: Samples](https://github.com/Azure-Samples/cognitive-services-java-sdk-samples/tree/master/ContentModerator) | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AContentModerator) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/content-moderator) | - | --- | --- | --- | --- | --- | - * **Face API** - - | [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/cognitiveservices/azure-vision) | [:arrow_down: Download](https://search.maven.org/#search%7Cga%7C1%7Ca%3A%22azure-faceapi%22) | :pencil: Samples | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AFaceAPI) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/cognitive-services/face/) | - | --- | --- | --- | --- | --- | - -## Media Services - -This project provides Java APIs for Azure Media Services, enabling you to share media content through premium video workflows: - -| [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/0.9/services/azure-media) | [:arrow_down: Download](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.microsoft.azure%22%20AND%20a%3A%22azure-media%22) | [:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AMediaServices) | [:book: Learn more...](https://azure.microsoft.com/en-us/services/media-services/) | -| --- | --- | --- | --- | - -## Azure Event Grid - -This project provides Java APIs for [Azure Event Grid](https://azure.com/eventgrid), enabling you to build reactive programs and applications in the cloud: - -| [:page_facing_up: Sources...](https://github.com/Azure/azure-sdk-for-java/tree/master/azure-eventgrid) | :arrow_down: Download | :pencil: Samples |[:triangular_flag_on_post: Issues](https://github.com/azure/azure-sdk-for-java/issues?q=is%3Aopen+is%3Aissue+label%3AEventGrid) | [:book: Learn more...](https://azure.microsoft.com/services/event-grid/) | -| --- | --- | --- | --- | --- | - -## Prerequisites - -- A Java Developer Kit (JDK), v 1.7 or later -- Maven - -## Help and Issues - -If you encounter any bugs with these SDKs, please file issues via [Issues](https://github.com/Azure/azure-sdk-for-java/issues) or checkout [StackOverflow for Azure Java SDK](http://stackoverflow.com/questions/tagged/azure-java-sdk). - -## Contribute Code - -If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html). - -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request - ---- - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +# Azure SDK for Java +[![Build Status](https://dev.azure.com/azure-sdk/public/_apis/build/status/17?branchName=master)](https://dev.azure.com/azure-sdk/public/_build/latest?definitionId=17) [![Build Documentation](https://img.shields.io/badge/documentation-published-blue.svg)](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/index.html) [![Dependencies](https://img.shields.io/badge/dependencies-analyzed-blue.svg)](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/staging/dependencies.html) [![SpotBugs](https://img.shields.io/badge/SpotBugs-Clean-success.svg)](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/staging/spotbugsXml.html) [![CheckStyle](https://img.shields.io/badge/CheckStyle-Clean-success.svg)](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/staging/checkstyle-aggregate.html) + + +This repository contains official Java libraries for Azure services. For reference documentation go to [Azure SDK for Java documentation](http://aka.ms/java-docs), and tutorials, samples, quick starts and other documentation, go to [Azure for Java Developers](https://docs.microsoft.com/java/azure/). + +You can find a complete list of all the packages for these libraries [here](packages.md). + +## Getting started + +To get started with a specific library, see the **README.md** file located in the library's project folder. You can find service libraries in the `/sdk` directory. + +For tutorials, samples, quick starts and other documentation, visit [Azure for Java Developers](https://docs.microsoft.com/java/azure/). + +### Prerequisites +Java 8 or later is required to use the July 2019 client preview libraries, otherwise Java 7 or later is required. + +## Packages available +Each service might have a number of libraries available from each of the following categories: + +* [Client - July 2019 Preview](#Client-July-2019-Preview) +* [Client - Stable](#Client-Stable) +* [Management](#Management) + +### Client: July 2019 Preview +New wave of packages that we are currently releasing in **preview**. These libraries follow the [Azure SDK Design Guidelines for Java](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html) and share a number of core features such as HTTP retries, logging, transport protocols, authentication protocols, etc., so that once you learn how to use these features in one client library, you will know how to use them in other client libraries. You can learn about these shared features [here](core). + +These preview libraries can be easily identified by their folder, package, and namespaces names starting with `azure-`, e.g. `azure-keyvault`. + +The libraries released in the July 2019 preview: +- [App Configuration](appconfiguration/client/README.md) +- [Event Hubs](eventhubs/client/README.md) +- [Identity](sdk/identity/azure-identity) +- [Key Vault Keys](keyvault/client/keys/README.md) +- [Key Vault Secrets](keyvault/client/secrets/README.md) +- [Storage Blobs](storage/client/README.md) + +>NOTE: If you need to ensure your code is ready for production, use one of the stable libraries. + +### Client: Stable +Last stable versions of packages that have been provided for usage with Azure and are production-ready. These libraries provide similar functionalities to the preview libraries, as they allow you to use and consume existing resources and interact with them, for example: upload a blob. Stable library directories start with `microsoft-azure-`, e.g. `microsoft-azure-keyvault`. + +### Management +Libraries which enable you to provision specific resources. They are responsible for directly mirroring and consuming Azure service's REST endpoints. Management library directories contain `-mgmt-`, e.g. `azure-mgmt-keyvault`. + +## Need help? +* For reference documentation visit the [Azure SDK for Java documentation](http://aka.ms/java-docs). +* For tutorials, samples, quick starts and other documentation, visit [Azure for Java Developers](https://docs.microsoft.com/java/azure/). +* For build reports on code quality, test coverage, etc, visit [Azure Java SDK](https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/index.html). +* File an issue via [Github Issues](https://github.com/Azure/azure-sdk-for-java/issues/new/choose). +* Check [previous questions](https://stackoverflow.com/questions/tagged/azure-java-sdk) or ask new ones on StackOverflow using `azure-java-sdk` tag. + +## Contributing +For details on contributing to this repository, see the [contributing guide](CONTRIBUTING.md). ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-java%2FREADME.png) diff --git a/api-specs.json b/api-specs.json index 3f5745dc8f28c..059bfafbe5eba 100644 --- a/api-specs.json +++ b/api-specs.json @@ -206,6 +206,10 @@ "source": "specification/recoveryservicesbackup/resource-manager/readme.md", "args": "--multiapi --fluent" }, + "recoveryservicessiterecovery/resource-manager": { + "source": "specification/recoveryservicessiterecovery/resource-manager/readme.md", + "args": "--multiapi --fluent" + }, "redis/resource-manager": { "source": "specification/redis/resource-manager/readme.md", "args": "--multiapi --fluent", @@ -256,6 +260,10 @@ "source": "specification/sql/resource-manager/readme.md", "args": "--multiapi --fluent" }, + "sqlvirtualmachine/resource-manager": { + "source": "specification/sqlvirtualmachine/resource-manager/readme.md", + "args": "--multiapi --fluent" + }, "storage/resource-manager": { "source": "specification/storage/resource-manager/readme.md", "args": "--multiapi --fluent" diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java b/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java deleted file mode 100644 index fc45c56722434..0000000000000 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.data.appconfiguration; - -import com.azure.core.implementation.annotation.ServiceClientBuilder; -import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; -import com.azure.data.appconfiguration.models.ConfigurationSetting; -import com.azure.core.util.configuration.Configuration; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.policy.HttpLogDetailLevel; -import com.azure.core.http.policy.HttpPipelinePolicy; - -import java.net.MalformedURLException; - -/** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link ConfigurationClient}, - * calling {@link ConfigurationClientBuilder#build() build} constructs an instance of the client. - * - *

The client needs the service endpoint of the Azure App Configuration store and access credentials. - * {@link ConfigurationClientCredentials} gives the builder the service endpoint and access credentials it requires to - * construct a client, set the ConfigurationClientCredentials with {@link ConfigurationAsyncClientBuilder#credentials(ConfigurationClientCredentials) this}.

- * - *
- * ConfigurationAsyncClient client = ConfigurationAsyncClient.builder()
- *     .credentials(new ConfigurationClientCredentials(connectionString))
- *     .build();
- * 
- * - *

Another way to construct the client is using a {@link HttpPipeline}. The pipeline gives the client an authenticated - * way to communicate with the service but it doesn't contain the service endpoint. Set the pipeline with - * {@link ConfigurationClientBuilder#pipeline(HttpPipeline) this}, additionally set the service endpoint with - * {@link ConfigurationClientBuilder#serviceEndpoint(String) this}. Using a pipeline requires additional setup but - * allows for finer control on how the ConfigurationClient it built.

- * - *
- * ConfigurationAsyncClient.builder()
- *     .pipeline(new HttpPipeline(policies))
- *     .serviceEndpoint(serviceEndpoint)
- *     .build();
- * 
- * - * @see ConfigurationClient - * @see ConfigurationClientCredentials - */ -@ServiceClientBuilder(serviceClients = ConfigurationClient.class) -public final class ConfigurationClientBuilder { - private final ConfigurationAsyncClientBuilder builder; - - ConfigurationClientBuilder() { - builder = ConfigurationAsyncClient.builder(); - } - - /** - * Creates a {@link ConfigurationClient} based on options set in the Builder. Every time {@code build()} is - * called, a new instance of {@link ConfigurationClient} is created. - * - *

- * If {@link ConfigurationClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} are used to create the - * {@link ConfigurationClient client}. All other builder settings are ignored.

- * - * @return A ConfigurationClient with the options set from the builder. - * @throws NullPointerException If {@code serviceEndpoint} has not been set. This setting is automatically set when - * {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials) credentials} are set through - * the builder. Or can be set explicitly by calling {@link ConfigurationClientBuilder#serviceEndpoint(String)}. - * @throws IllegalStateException If {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials)} - * has not been set. - */ - public ConfigurationClient build() { - return new ConfigurationClient(builder.build()); - } - - /** - * Sets the service endpoint for the Azure App Configuration instance. - * - * @param serviceEndpoint The URL of the Azure App Configuration instance to send {@link ConfigurationSetting} - * service requests to and receive responses from. - * @return The updated ConfigurationClientBuilder object. - * @throws MalformedURLException if {@code serviceEndpoint} is null or it cannot be parsed into a valid URL. - */ - public ConfigurationClientBuilder serviceEndpoint(String serviceEndpoint) throws MalformedURLException { - builder.serviceEndpoint(serviceEndpoint); - return this; - } - - /** - * Sets the credentials to use when authenticating HTTP requests. Also, sets the - * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} for this ConfigurationClientBuilder. - * - * @param credentials The credentials to use for authenticating HTTP requests. - * @return The updated ConfigurationClientBuilder object. - * @throws NullPointerException If {@code credentials} is {@code null}. - */ - public ConfigurationClientBuilder credentials(ConfigurationClientCredentials credentials) { - builder.credentials(credentials); - return this; - } - - /** - * Sets the logging level for HTTP requests and responses. - * - * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return The updated ConfigurationClientBuilder object. - */ - public ConfigurationClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { - builder.httpLogDetailLevel(logLevel); - return this; - } - - /** - * Adds a policy to the set of existing policies that are executed after - * {@link ConfigurationClient} required policies. - * - * @param policy The retry policy for service requests. - * @return The updated ConfigurationClientBuilder object. - * @throws NullPointerException If {@code policy} is {@code null}. - */ - public ConfigurationClientBuilder addPolicy(HttpPipelinePolicy policy) { - builder.addPolicy(policy); - return this; - } - - /** - * Sets the HTTP client to use for sending and receiving requests to and from the service. - * - * @param client The HTTP client to use for requests. - * @return The updated ConfigurationClientBuilder object. - * @throws NullPointerException If {@code client} is {@code null}. - */ - public ConfigurationClientBuilder httpClient(HttpClient client) { - builder.httpClient(client); - return this; - } - - /** - * Sets the HTTP pipeline to use for the service client. - * - * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} to build {@link ConfigurationClient}. - * - * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return The updated ConfigurationClientBuilder object. - */ - public ConfigurationClientBuilder pipeline(HttpPipeline pipeline) { - builder.pipeline(pipeline); - return this; - } - - /** - * Sets the configuration store that is used during construction of the service client. - * - * Use {@link Configuration#NONE} to bypass using configuration settings during construction. - * - * @param configuration The configuration store used to - * @return The updated ConfigurationClientBuilder object. - */ - public ConfigurationClientBuilder configuration(Configuration configuration) { - builder.configuration(configuration); - return this; - } -} diff --git a/appconfiguration/client/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java b/appconfiguration/client/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java deleted file mode 100644 index be9d79875adaa..0000000000000 --- a/appconfiguration/client/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.data.appconfiguration; - -import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; -import com.azure.data.appconfiguration.models.ConfigurationSetting; -import java.security.GeneralSecurityException; - -/** - * This class contains code samples for generating javadocs through doclets for {@link ConfigurationClient} - */ -public final class ConfigurationClientJavaDocCodeSnippets { - - /** - * Generates code sample for creating a {@link ConfigurationClient} - * @return An instance of {@link ConfigurationClient} - * @throws IllegalStateException If configuration credentials cannot be created - */ - public ConfigurationClient createConfigurationClient() { - try { - String connectionString = getConnectionString(); - // BEGIN: com.azure.applicationconfig.configurationclient.instantiation - ConfigurationClient configurationClient = ConfigurationClient.builder() - .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); - // END: com.azure.applicationconfig.configurationclient.instantiation - return configurationClient; - } catch (GeneralSecurityException ex) { - throw new IllegalStateException("Failed to create configuration client credentials", ex); - } - } - - /** - * Generates code sample for using {@link ConfigurationClient#addSetting(String, String)} - */ - public void addSetting() { - ConfigurationClient configurationClient = createConfigurationClient(); - // BEGIN: com.azure.applicationconfig.configurationclient.addSetting#string-string - ConfigurationSetting configurationSetting = configurationClient - .addSetting("prodDBConnection", "db_connection").value(); - System.out.printf("Key: %s, Value: %s %n", configurationSetting.key(), configurationSetting.value()); - // END: com.azure.applicationconfig.configurationclient.addSetting#string-string - } - - /** - * Implementation not provided for this method - * @return {@code null} - */ - private String getConnectionString() { - return null; - } -} diff --git a/appconfiguration/client/tests.yml b/appconfiguration/client/tests.yml deleted file mode 100644 index 77ddb5a0671f3..0000000000000 --- a/appconfiguration/client/tests.yml +++ /dev/null @@ -1,10 +0,0 @@ -trigger: none - -jobs: - # When migrating change path to ../../eng/pipelines/templates/jobs/archetype-sdk-tests.yml - - template: ../../eng/pipelines/templates/jobs/archetype-sdk-tests-pre-sdk.yml - parameters: - # When migrating use ServiceDirectory - PomFilePath: './applicationconfig/client/pom.xml' - EnvVars: - AZCONFIG_CONNECTION_STRING: $(java-azconfig-test-connection-string) \ No newline at end of file diff --git a/appconfiguration/resource-manager/v2019_02_01_preview/pom.xml b/appconfiguration/resource-manager/v2019_02_01_preview/pom.xml index a6044c1e69bc5..b9182f0b2edb1 100644 --- a/appconfiguration/resource-manager/v2019_02_01_preview/pom.xml +++ b/appconfiguration/resource-manager/v2019_02_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/authorization/resource-manager/v2015_06_01/pom.xml b/authorization/resource-manager/v2015_06_01/pom.xml index deb7668262fb2..e19beddcc02bf 100644 --- a/authorization/resource-manager/v2015_06_01/pom.xml +++ b/authorization/resource-manager/v2015_06_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/authorization/resource-manager/v2018_07_01_preview/pom.xml b/authorization/resource-manager/v2018_07_01_preview/pom.xml index 3a6fcf1ee50e0..e29abe1d0dff8 100644 --- a/authorization/resource-manager/v2018_07_01_preview/pom.xml +++ b/authorization/resource-manager/v2018_07_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/authorization/resource-manager/v2018_09_01_preview/pom.xml b/authorization/resource-manager/v2018_09_01_preview/pom.xml index 7fdb6a3da763f..eb6c3404737f0 100644 --- a/authorization/resource-manager/v2018_09_01_preview/pom.xml +++ b/authorization/resource-manager/v2018_09_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/compute/resource-manager/v2018_09_30/pom.xml b/compute/resource-manager/v2018_09_30/pom.xml index 2da22f6cf4958..cd4e19cb2711d 100644 --- a/compute/resource-manager/v2018_09_30/pom.xml +++ b/compute/resource-manager/v2018_09_30/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/containerregistry/resource-manager/v2019_06_01_preview/pom.xml b/containerregistry/resource-manager/v2019_06_01_preview/pom.xml index 4e2f42f32b290..3c7e9344faaf4 100644 --- a/containerregistry/resource-manager/v2019_06_01_preview/pom.xml +++ b/containerregistry/resource-manager/v2019_06_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/RunsImpl.java b/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/RunsImpl.java index be070d16d75ad..48890a2610864 100644 --- a/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/RunsImpl.java +++ b/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/RunsImpl.java @@ -74,10 +74,14 @@ public Run call(RunInner inner) { public Observable getAsync(String resourceGroupName, String registryName, String runId) { RunsInner client = this.inner(); return client.getAsync(resourceGroupName, registryName, runId) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public Run call(RunInner inner) { - return wrapModel(inner); + public Observable call(RunInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((Run)wrapModel(inner)); + } } }); } diff --git a/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/TasksImpl.java b/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/TasksImpl.java index d8ca2fd2f9a23..10a2d87819955 100644 --- a/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/TasksImpl.java +++ b/containerregistry/resource-manager/v2019_06_01_preview/src/main/java/com/microsoft/azure/management/containerregistry/v2019_06_01_preview/implementation/TasksImpl.java @@ -76,10 +76,14 @@ public Task call(TaskInner inner) { public Observable getAsync(String resourceGroupName, String registryName, String taskName) { TasksInner client = this.inner(); return client.getAsync(resourceGroupName, registryName, taskName) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public Task call(TaskInner inner) { - return wrapModel(inner); + public Observable call(TaskInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((Task)wrapModel(inner)); + } } }); } diff --git a/core/README.md b/core/README.md index ce52d05ef7290..ec88ce9e1a077 100644 --- a/core/README.md +++ b/core/README.md @@ -1,124 +1,27 @@ -[![Build Status](https://travis-ci.org/Azure/autorest-clientruntime-for-java.svg?branch=v2)](https://travis-ci.org/Azure/autorest-clientruntime-for-java) +# Azure Core shared library for Java -# AutoRest Client Runtimes for Java -The runtime libraries for [AutoRest](https://github.com/azure/autorest) generated Java clients. +[![Build Documentation](https://img.shields.io/badge/documentation-published-blue.svg)](https://azure.github.io/azure-sdk-for-java/track2reports/index.html) -## Usage +Azure Core provides shared primitives, abstractions, and helpers for modern Java Azure SDK client libraries. These libraries follow the [Azure SDK Design Guidelines for JavaT](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html) and can be easily identified by package names starting with `com.azure` and module names starting with `azure-`, e.g. `com.azure.storage.blobs` would be found within the `/sdk/storage/azure-storage-blob` directory. A more complete list of client libraries using Azure Core can be found [here](https://github.com/Azure/azure-sdk-for-java). -### Prerequisites +Azure Core allows client libraries to expose common functionality in a consistent fashion, so that once you learn how to use these APIs in one client library, you will know how to use them in other client libraries. -- JDK 1.8 +The main shared concepts of Azure Core (and therefore all Azure client libraries using Azure Core) include: -### Download +- Configuring service clients, e.g. configuring retries, logging, etc. +- Accessing HTTP response details (`Response`). +- Calling long running operations (`Poller`). +- Paging and asynchronous streams (`PagedFlux`). +- Exceptions for reporting errors from service requests in a consistent fashion. +- Abstractions for representing Azure SDK credentials. -```xml - - - - com.microsoft.rest.v3 - client-runtime - 2.0.0-beta4 - - - - - com.microsoft.azure.v3 - azure-client-runtime - 2.0.0-beta4 - - - - com.microsoft.azure.v3 - azure-client-authentication - 2.0.0-beta4 - - - +## Sub-projects - - - io.netty - netty-tcnative-boringssl-static - 2.0.8.Final - ${os.detected.classifier} - +Azure Core is split into a number of sub-components: - - - io.netty - netty-transport-native-epoll - 4.1.23.Final - ${os.detected.classifier} - +* [azure-core](azure-core) is the primary library, used by all client libraries to offer the functionality outlined above. +* [azure-core-amqp](azure-core-amqp) provides functionality related to AMQP (Advanced Message Queuing Protocol). +* [azure-core-management](azure-core-management) provides APIs used by the Azure management libraries, but which are redundant to client libraries. +* [azure-core-test](azure-core-test) provides utilities and API to make writing tests for Azure Core simpler and consistent. - - - io.netty - netty-transport-native-kqueue - 4.1.23.Final - ${os.detected.classifier} - - - - - - - - kr.motd.maven - os-maven-plugin - 1.6.0 - - - -``` - -### Usage - -Non-Azure generated clients will have a constructor that takes no arguments for simple scenarios, while Azure generated clients will require a `ServiceClientCredentials` argument at a minimum. - -If you want to have more control over configuration, consider using HttpPipeline. This enables performing transformations on all HTTP messages sent by a client, similar to interceptors or filters in other HTTP clients. - -You can build an HttpPipeline out of a sequence of RequestPolicyFactories. These policies will get applied in-order to outgoing requests, and then in reverse order for incoming responses. HttpPipelineBuilder includes convenience methods for adding several built-in RequestPolicyFactories, including policies for credentials, logging, response decoding (deserialization), cookies support, and several others. - -```java -// For Java generator -HttpPipeline pipeline = new HttpPipelineBuilder() - .withHostPolicy("http://localhost") - .withDecodingPolicy() - .build(); -AutoRestJavaClient client = new AutoRestJavaClientImpl(pipeline); - -// For Azure.Java generator -HttpPipeline azurePipeline = new HttpPipelineBuilder() - .withCredentialsPolicy(AzureCliCredentials.create()) - .withHttpLoggingPolicy(HttpLogDetailLevel.HEADERS) - .withDecodingPolicy() - .build(); -FooServiceClient azureClient = new FooServiceClientImpl(azurePipeline); -``` - -## Components - -### client-runtime -This is the generic runtime. Add this package as a dependency if you are using `Java` generator in AutoRest. This package depends on [Netty](https://github.com/netty/netty), [Jackson](http://wiki.fasterxml.com/JacksonHome), and [RxJava](https://github.com/ReactiveX/RxJava) for making and processing REST requests. - -### azure-client-runtime -This is the runtime with Azure Resource Management customizations. Add this package as a dependency if you are using `--azure-arm` or `--azure-arm --fluent` generator flags in AutoRest. - -This combination provides a set of Azure specific behaviors, including long running operations, special handling of HEAD operations, and paginated `list()` calls. - -### azure-client-authentication (beta) -This package provides access to Active Directory authentication on JDK using OrgId or application ID / secret combinations. There are currently 3 types of authentication provided: - -- Service principal authentication: `ApplicationTokenCredentials` -- Username / password login without multi-factor auth: `UserTokenCredentials` -- Use the credentials logged in [Azure CLI](https://github.com/azure/azure-cli): `AzureCliCredentials` - -### azure-android-client-authentication (beta) -This package provides access to Active Directory authentication on Android. You can login with Microsoft accounts, OrgId, with or without multi-factor auth. - -## Build -To build this repository, you will need maven 2.0+ and gradle 1.6+. - -## Contributing -This repository is for runtime & authentication specifically. For issues in the generated code, please report in [AutoRest](https://github.com/Azure/autorest). For bugs in the Azure SDK, please report in [Azure SDK for Java](https://github.com/Azure/azure-sdk-for-java). If you are unsure, please file here and state that clearly in the issue. Pull requests are welcomed with clear Javadocs. +For documentation on using Azure Core, refer to the [azure-core readme](azure-core). diff --git a/core/azure-core-amqp/pom.xml b/core/azure-core-amqp/pom.xml index acfe076ba804c..acdcb042d4c27 100644 --- a/core/azure-core-amqp/pom.xml +++ b/core/azure-core-amqp/pom.xml @@ -7,13 +7,13 @@ com.azure azure-core-parent - 1.0.0-preview.1 + 1.0.0-preview.3 ../pom.xml com.azure azure-core-amqp - 1.0.0-preview.1 + 1.0.0-preview.3 jar Microsoft Azure Java Core AMQP Library @@ -39,9 +39,8 @@ https://github.com/Azure/azure-sdk-for-java scm:git:https://github.com/Azure/azure-sdk-for-java.git scm:git:https://github.com/Azure/azure-sdk-for-java.git - v1.0.0-preview.1 - + UTF-8 @@ -58,7 +57,7 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 diff --git a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/AmqpExceptionHandler.java b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/AmqpExceptionHandler.java index 876c4b46713b0..c451bdc2439fb 100644 --- a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/AmqpExceptionHandler.java +++ b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/AmqpExceptionHandler.java @@ -23,7 +23,7 @@ protected AmqpExceptionHandler() { * @param exception The exception that caused the connection error. */ public void onConnectionError(Throwable exception) { - logger.asWarning().log("Connection exception encountered: " + exception.toString(), exception); + logger.warning("Connection exception encountered: " + exception.toString(), exception); } /** @@ -32,6 +32,6 @@ public void onConnectionError(Throwable exception) { * @param shutdownSignal The shutdown signal that was received. */ public void onConnectionShutdown(AmqpShutdownSignal shutdownSignal) { - logger.asInfo().log("Shutdown received: {}", shutdownSignal); + logger.info("Shutdown received: {}", shutdownSignal); } } diff --git a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/ExponentialRetry.java b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/ExponentialRetry.java index 3e86faa719c82..87e136690bc08 100644 --- a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/ExponentialRetry.java +++ b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/ExponentialRetry.java @@ -4,10 +4,11 @@ package com.azure.core.amqp; import java.time.Duration; +import java.util.Objects; /** - * A policy to govern retrying of messaging operations in which the delay between retries - * will grow in an exponential manner, allowing more time to recover as the number of retries increases. + * A policy to govern retrying of messaging operations in which the delay between retries will grow in an exponential + * manner, allowing more time to recover as the number of retries increases. */ public final class ExponentialRetry extends Retry { private static final Duration TIMER_TOLERANCE = Duration.ofSeconds(1); @@ -22,9 +23,13 @@ public final class ExponentialRetry extends Retry { * @param minBackoff The minimum time period permissible for backing off between retries. * @param maxBackoff The maximum time period permissible for backing off between retries. * @param maxRetryCount The maximum number of retries allowed. + * @throws NullPointerException if {@code minBackoff} or {@code maxBackoff} is {@code null}. */ public ExponentialRetry(Duration minBackoff, Duration maxBackoff, int maxRetryCount) { super(maxRetryCount); + Objects.requireNonNull(minBackoff); + Objects.requireNonNull(maxBackoff); + this.minBackoff = minBackoff; this.maxBackoff = maxBackoff; @@ -58,4 +63,41 @@ private double computeRetryFactor() { } return Math.log(deltaBackoff) / Math.log(super.getMaxRetryCount()); } + + @Override + public int hashCode() { + return Objects.hash(maxBackoff, minBackoff, getMaxRetryCount(), getRetryCount()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof ExponentialRetry)) { + return false; + } + + ExponentialRetry other = (ExponentialRetry) obj; + + return this.maxBackoff.equals(other.maxBackoff) + && this.minBackoff.equals(other.minBackoff) + && this.getMaxRetryCount() == other.getMaxRetryCount() + && this.getRetryCount() == other.getRetryCount(); + } + + /** + * Creates a clone of this instance. + * + * The {@code minBackoff}, {@code maxBackoff}, and {@code maxRetryCount} are not cloned, but these objects are + * immutable and not subject to change. + * + * @return A clone of the {@link ExponentialRetry} instance. + */ + @SuppressWarnings("CloneDoesntCallSuperClone") + @Override + public Object clone() { + return new ExponentialRetry(minBackoff, maxBackoff, getMaxRetryCount()); + } } diff --git a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/MessageConstant.java b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/MessageConstant.java index 2f769d5cf5acd..a5be2f82d6e23 100644 --- a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/MessageConstant.java +++ b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/MessageConstant.java @@ -57,7 +57,7 @@ public enum MessageConstant { /** * An absolute time when this message is considered to be expired. */ - ABSOLUTE_EXPRITY_TIME("absolute-expiry-time"), + ABSOLUTE_EXPIRY_TIME("absolute-expiry-time"), /** * An absolute time when this message was created. */ diff --git a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/Retry.java b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/Retry.java index 39f969e8bdd7a..f88968c8341f7 100644 --- a/core/azure-core-amqp/src/main/java/com/azure/core/amqp/Retry.java +++ b/core/azure-core-amqp/src/main/java/com/azure/core/amqp/Retry.java @@ -12,7 +12,7 @@ /** * An abstract representation of a policy to govern retrying of messaging operations. */ -public abstract class Retry { +public abstract class Retry implements Cloneable { /** * Default for the minimum time between retry attempts. */ @@ -132,6 +132,11 @@ public Duration getNextRetryInterval(Exception lastException, Duration remaining return this.calculateNextRetryInterval(lastException, remainingTime, baseWaitTime, this.getRetryCount()); } + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + /** * Allows a concrete retry policy implementation to offer a base retry interval to be used in * the calculations performed by 'Retry.GetNextRetryInterval'. diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/AmqpShutdownSignalTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/AmqpShutdownSignalTest.java new file mode 100644 index 0000000000000..400e467549bb3 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/AmqpShutdownSignalTest.java @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp; + +import org.junit.Assert; +import org.junit.Test; + +public class AmqpShutdownSignalTest { + + /** + * Verifies that the correct properties are set when we create an AmqpShutdownSignal. + */ + @Test + public void constructor() { + boolean isTransient = true; + boolean isInitiatedByClient = true; + String message = "Some message."; + + AmqpShutdownSignal shutdownSignal = new AmqpShutdownSignal(isTransient, isInitiatedByClient, message); + + Assert.assertTrue(shutdownSignal.isTransient()); + Assert.assertTrue(shutdownSignal.isInitiatedByClient()); + + String contents = shutdownSignal.toString(); + Assert.assertNotNull(contents); + Assert.assertTrue(contents.contains(message)); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/ExponentialRetryTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/ExponentialRetryTest.java new file mode 100644 index 0000000000000..1bf45032e0905 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/ExponentialRetryTest.java @@ -0,0 +1,95 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp; + +import com.azure.core.amqp.exception.AmqpException; +import com.azure.core.amqp.exception.ErrorCondition; +import com.azure.core.amqp.exception.ErrorContext; +import org.junit.Assert; +import org.junit.Test; + +import java.time.Duration; + +public class ExponentialRetryTest { + private final ErrorContext errorContext = new ErrorContext("test-namespace"); + private final AmqpException exception = new AmqpException(true, ErrorCondition.SERVER_BUSY_ERROR, "error message", errorContext); + private final Duration minBackoff = Duration.ofSeconds(15); + private final Duration maxBackoff = Duration.ofSeconds(45); + private final int retryAttempts = 4; + + /** + * Verifies that when the service is busy and we retry an exception multiple times, the retry duration gets longer. + */ + @Test + public void retryDurationIncreases() { + // Arrange + final ExponentialRetry retry = new ExponentialRetry(minBackoff, maxBackoff, retryAttempts); + final Duration remainingTime = Duration.ofSeconds(60); + + // Act + retry.incrementRetryCount(); + final Duration firstRetryInterval = retry.getNextRetryInterval(exception, remainingTime); + Assert.assertNotNull(firstRetryInterval); + + retry.incrementRetryCount(); + final Duration leftoverTime = remainingTime.minus(firstRetryInterval); + final Duration secondRetryInterval = retry.getNextRetryInterval(exception, leftoverTime); + + // Assert + Assert.assertNotNull(secondRetryInterval); + Assert.assertTrue(secondRetryInterval.toNanos() > firstRetryInterval.toNanos()); + } + + /** + * Verifies that we can clone the retry instance and it behaves the same as its original. + */ + @Test + public void retryCloneBehavesSame() { + // Arrange + final ExponentialRetry retry = new ExponentialRetry(minBackoff, maxBackoff, retryAttempts); + final ExponentialRetry clone = (ExponentialRetry) retry.clone(); + + final Duration remainingTime = Duration.ofSeconds(60); + + retry.incrementRetryCount(); + final Duration retryInterval = retry.getNextRetryInterval(exception, remainingTime); + + clone.incrementRetryCount(); + clone.incrementRetryCount(); + clone.incrementRetryCount(); + final Duration cloneRetryInterval = clone.getNextRetryInterval(exception, remainingTime); + + // Assert + Assert.assertNotNull(retryInterval); + Assert.assertNotNull(cloneRetryInterval); + + // The retry interval for the clone will be larger because we've incremented the retry count, so it should + // calculate a longer waiting period. + Assert.assertTrue(cloneRetryInterval.toNanos() > retryInterval.toNanos()); + } + + @Test + public void retryClone() { + // Arrange + final ExponentialRetry retry = new ExponentialRetry(minBackoff, maxBackoff, retryAttempts); + final ExponentialRetry clone = (ExponentialRetry) retry.clone(); + + final Duration remainingTime = Duration.ofSeconds(60); + + retry.incrementRetryCount(); + final Duration retryInterval = retry.getNextRetryInterval(exception, remainingTime); + + clone.incrementRetryCount(); + final Duration cloneRetryInterval = clone.getNextRetryInterval(exception, remainingTime); + + // Assert + Assert.assertNotSame(retry, clone); + Assert.assertEquals(retry, clone); + Assert.assertEquals(retry.hashCode(), clone.hashCode()); + + Assert.assertNotNull(retryInterval); + Assert.assertNotNull(cloneRetryInterval); + Assert.assertEquals(retryInterval, cloneRetryInterval); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/MessageConstantTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/MessageConstantTest.java new file mode 100644 index 0000000000000..e08bb10ee5617 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/MessageConstantTest.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp; + +import org.junit.Assert; +import org.junit.Test; + +public class MessageConstantTest { + + /** + * Verifies we correctly parse the enumeration value from a string. + */ + @Test + public void createFromString() { + String header = "absolute-expiry-time"; + MessageConstant actual = MessageConstant.fromString(header); + + Assert.assertEquals(MessageConstant.ABSOLUTE_EXPIRY_TIME, actual); + } + + /** + * Verifies we correctly get the header value from a {@link MessageConstant}. + */ + @Test + public void getHeaderValue() { + String expected = "x-opt-enqueued-time"; + String actual = MessageConstant.ENQUEUED_TIME_UTC_ANNOTATION_NAME.getValue(); + + Assert.assertEquals(expected, actual); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/TransportTypeTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/TransportTypeTest.java new file mode 100644 index 0000000000000..01f798dfa22d8 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/TransportTypeTest.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp; + +import org.junit.Assert; +import org.junit.Test; + +public class TransportTypeTest { + + /** + * Verifies that we can parse the transport type from string + */ + @Test + public void createFromString() { + String socketString = "Amqpwebsockets"; + TransportType actual = TransportType.fromString(socketString); + + Assert.assertEquals(TransportType.AMQP_WEB_SOCKETS, actual); + } + + /** + * Verifies that an exception is thrown when an unknown transport type string is passed. + */ + @Test(expected = IllegalArgumentException.class) + public void illegalTransportTypeString() { + String socketString = "AmqpNonExistent"; + + TransportType actual = TransportType.fromString(socketString); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpExceptionTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpExceptionTest.java new file mode 100644 index 0000000000000..c61fad1028c3c --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpExceptionTest.java @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class AmqpExceptionTest { + private final SessionErrorContext context = new SessionErrorContext("namespace-test", "entity-path-test"); + private final String message = "Some test message."; + + /** + * Verifies that the exception's properties are correctly set. + */ + @Test + public void constructor() { + // Act + AmqpException exception = new AmqpException(true, message, context); + + // Assert + Assert.assertTrue(exception.isTransient()); + Assert.assertNotNull(exception.getMessage()); + Assert.assertTrue(exception.getMessage().contains(message)); + + Assert.assertTrue(exception.getContext() instanceof SessionErrorContext); + + SessionErrorContext actualContext = (SessionErrorContext) exception.getContext(); + Assert.assertEquals(context.getNamespace(), actualContext.getNamespace()); + Assert.assertEquals(context.getEntityPath(), actualContext.getEntityPath()); + + Assert.assertNull(exception.getErrorCondition()); + } + + /** + * Verifies the exception's properties when creating with an ErrorCondition. + */ + @Test + public void constructorErrorCondition() { + // Arrange + IllegalArgumentException innerException = new IllegalArgumentException("Some parameter"); + ErrorCondition condition = ErrorCondition.ILLEGAL_STATE; + + // Act + AmqpException exception = new AmqpException(false, condition, message, innerException, context); + + // Assert + Assert.assertEquals(condition, exception.getErrorCondition()); + + Assert.assertTrue(exception.getContext() instanceof SessionErrorContext); + + SessionErrorContext actualContext = (SessionErrorContext) exception.getContext(); + Assert.assertEquals(context.getNamespace(), actualContext.getNamespace()); + Assert.assertEquals(context.getEntityPath(), actualContext.getEntityPath()); + + Assert.assertSame(innerException, exception.getCause()); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpResponseCodeTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpResponseCodeTest.java new file mode 100644 index 0000000000000..5675f493027f3 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/AmqpResponseCodeTest.java @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class AmqpResponseCodeTest { + /** + * Verifies that we can parse the AmqpResponseCode an integer. + */ + @Test + public void createFromInteger() { + int forbidden = 403; + AmqpResponseCode expected = AmqpResponseCode.FORBIDDEN; + + AmqpResponseCode actual = AmqpResponseCode.fromValue(forbidden); + + Assert.assertEquals(expected, actual); + } + + /** + * Verifies that we can parse the AmqpResponseCode an integer. + */ + @Test + public void returnsCorrectValue() { + int expected = 404; + AmqpResponseCode forbidden = AmqpResponseCode.NOT_FOUND; + + Assert.assertEquals(expected, forbidden.getValue()); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ErrorContextTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ErrorContextTest.java new file mode 100644 index 0000000000000..8fad41ea9296b --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ErrorContextTest.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class ErrorContextTest { + /** + * Verifies properties set correctly. + */ + @Test + public void constructor() { + // Arrange + String namespace = "an-namespace-test"; + + // Act + ErrorContext context = new ErrorContext(namespace); + + // Assert + Assert.assertEquals(namespace, context.getNamespace()); + } + + /** + * Verifies an exception is thrown if namespace is an empty string. + */ + @Test(expected = IllegalArgumentException.class) + public void constructorEmptyString() { + // Act + ErrorContext context = new ErrorContext(""); + } + + /** + * Verifies an exception is thrown if namespace is null. + */ + @Test(expected = IllegalArgumentException.class) + public void constructorNull() { + // Act + ErrorContext context = new ErrorContext(null); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ExceptionUtilTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ExceptionUtilTest.java new file mode 100644 index 0000000000000..77568cf5f5637 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/ExceptionUtilTest.java @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class ExceptionUtilTest { + private final ErrorContext context = new ErrorContext("test-namespace"); + private final String message = "an-error-message"; + + /** + * Verifies correct exception is created from an error condition. + */ + @Test + public void createsCorrectException() { + // Arrange + ErrorCondition condition = ErrorCondition.ARGUMENT_OUT_OF_RANGE_ERROR; + + // Act + Exception exception = ExceptionUtil.toException(condition.getErrorCondition(), message, context); + + // Assert + Assert.assertTrue(exception instanceof AmqpException); + + AmqpException amqpException = (AmqpException) exception; + + Assert.assertEquals(condition, amqpException.getErrorCondition()); + Assert.assertFalse(amqpException.isTransient()); + Assert.assertSame(context, amqpException.getContext()); + Assert.assertTrue(amqpException.getMessage().startsWith(message)); + } + + /** + * Creates correct exception from not found exception that matches the expected service string. + */ + @Test + public void createsNotFoundException() { + // Arrange + AmqpResponseCode notFound = AmqpResponseCode.NOT_FOUND; + ErrorCondition condition = ErrorCondition.NOT_FOUND; + String entityName = "some-name"; + String message = "The messaging entity " + entityName + " could not be found"; + + // Act + Exception exception = ExceptionUtil.amqpResponseCodeToException(notFound.getValue(), message, context); + + // Assert + Assert.assertTrue(exception instanceof AmqpException); + + AmqpException amqpException = (AmqpException) exception; + + Assert.assertEquals(condition, amqpException.getErrorCondition()); + Assert.assertFalse(amqpException.isTransient()); + Assert.assertSame(context, amqpException.getContext()); + Assert.assertTrue(amqpException.getMessage().contains(message)); + } + + + /** + * Creates correct exception from not found exception. + */ + @Test + public void createsNotFoundExceptionNotMatches() { + // Arrange + AmqpResponseCode notFound = AmqpResponseCode.NOT_FOUND; + ErrorCondition condition = ErrorCondition.NOT_FOUND; + String message = "An entity was not found."; + + // Act + Exception exception = ExceptionUtil.amqpResponseCodeToException(notFound.getValue(), message, context); + + // Assert + Assert.assertTrue(exception instanceof AmqpException); + + AmqpException amqpException = (AmqpException) exception; + + Assert.assertEquals(condition, amqpException.getErrorCondition()); + Assert.assertTrue(amqpException.isTransient()); + Assert.assertSame(context, amqpException.getContext()); + Assert.assertTrue(amqpException.getMessage().contains(message)); + } + + /** + * Verifies AmqpException created from an integer. + */ + @Test + public void createsFromStatusCode() { + // Arrange + AmqpResponseCode responseCode = AmqpResponseCode.FORBIDDEN; + ErrorCondition actualCondition = ErrorCondition.RESOURCE_LIMIT_EXCEEDED; + + // Act + Exception exception = ExceptionUtil.amqpResponseCodeToException(responseCode.getValue(), message, context); + + // Assert + Assert.assertTrue(exception instanceof AmqpException); + + AmqpException amqpException = (AmqpException) exception; + Assert.assertEquals(actualCondition, amqpException.getErrorCondition()); + Assert.assertFalse(amqpException.isTransient()); + Assert.assertSame(context, amqpException.getContext()); + + Assert.assertTrue(amqpException.getMessage().contains(message)); + } + + /** + * Verifies AmqpException created from a non-existent status code. + */ + @Test + public void createsFromNonExistentStatusCode() { + // Arrange + int unknownCode = 202; + + // Act + Exception exception = ExceptionUtil.amqpResponseCodeToException(unknownCode, message, context); + + // Assert + Assert.assertTrue(exception instanceof AmqpException); + + AmqpException amqpException = (AmqpException) exception; + Assert.assertNull(amqpException.getErrorCondition()); + Assert.assertTrue(amqpException.isTransient()); + Assert.assertSame(context, amqpException.getContext()); + + Assert.assertTrue(amqpException.getMessage().contains(message)); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/LinkErrorContextTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/LinkErrorContextTest.java new file mode 100644 index 0000000000000..13f39bf159bd5 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/LinkErrorContextTest.java @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class LinkErrorContextTest { + /** + * Verifies properties set correctly. + */ + @Test + public void constructor() { + // Arrange + String namespace = "an-namespace-test"; + String entity = "an-entity-name"; + String trackingId = "a-tracking-id"; + Integer credits = -10; + + // Act + LinkErrorContext context = new LinkErrorContext(namespace, entity, trackingId, credits); + + // Assert + Assert.assertEquals(namespace, context.getNamespace()); + Assert.assertEquals(entity, context.getEntityPath()); + Assert.assertEquals(trackingId, context.getTrackingId()); + Assert.assertEquals(credits, context.getLinkCredit()); + } +} diff --git a/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/SessionErrorContextTest.java b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/SessionErrorContextTest.java new file mode 100644 index 0000000000000..5d3355a7ee9c7 --- /dev/null +++ b/core/azure-core-amqp/src/test/java/com/azure/core/amqp/exception/SessionErrorContextTest.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.amqp.exception; + +import org.junit.Assert; +import org.junit.Test; + +public class SessionErrorContextTest { + /** + * Verifies properties set correctly. + */ + @Test + public void constructor() { + // Arrange + String namespace = "an-namespace-test"; + String entity = "an-entity-name"; + + // Act + SessionErrorContext context = new SessionErrorContext(namespace, entity); + + // Assert + Assert.assertEquals(namespace, context.getNamespace()); + Assert.assertEquals(entity, context.getEntityPath()); + } +} diff --git a/core/azure-core-management/pom.xml b/core/azure-core-management/pom.xml index 6a08d646434e5..19accb8aaa850 100644 --- a/core/azure-core-management/pom.xml +++ b/core/azure-core-management/pom.xml @@ -7,13 +7,13 @@ com.azure azure-core-parent - 1.0.0-preview.1 + 1.0.0-preview.3 ../pom.xml com.azure azure-core-management - 1.0.0-preview.1 + 1.0.0-preview.3 jar Microsoft Azure Management Java Core Library @@ -39,7 +39,6 @@ https://github.com/Azure/azure-sdk-for-java scm:git:https://github.com/Azure/azure-sdk-for-java.git scm:git:https://github.com/Azure/azure-sdk-for-java.git - v1.0.0-preview.1 @@ -58,7 +57,7 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 @@ -70,7 +69,7 @@ com.azure azure-core-test - 1.0.0-preview.1 + 1.0.0-preview.3 test diff --git a/core/azure-core-management/src/main/java/com/azure/core/management/implementation/AzureProxy.java b/core/azure-core-management/src/main/java/com/azure/core/management/implementation/AzureProxy.java index 7b93f338b33c7..a60817b69fdda 100644 --- a/core/azure-core-management/src/main/java/com/azure/core/management/implementation/AzureProxy.java +++ b/core/azure-core-management/src/main/java/com/azure/core/management/implementation/AzureProxy.java @@ -217,7 +217,7 @@ public static A create(Class swaggerInterface, AzureEnvironment azureEnvi final SwaggerInterfaceParser interfaceParser = new SwaggerInterfaceParser(swaggerInterface, createDefaultSerializer(), baseUrl); final AzureProxy azureProxy = new AzureProxy(httpPipeline, interfaceParser); - return (A) Proxy.newProxyInstance(swaggerInterface.getClassLoader(), new Class[]{swaggerInterface}, azureProxy); + return (A) Proxy.newProxyInstance(swaggerInterface.getClassLoader(), new Class[]{swaggerInterface}, azureProxy); } @Override diff --git a/core/azure-core-management/src/test/java/com/azure/core/management/AzureProxyToRestProxyTests.java b/core/azure-core-management/src/test/java/com/azure/core/management/AzureProxyToRestProxyTests.java index 0ade3f21f5027..8e6e63c015b66 100644 --- a/core/azure-core-management/src/test/java/com/azure/core/management/AzureProxyToRestProxyTests.java +++ b/core/azure-core-management/src/test/java/com/azure/core/management/AzureProxyToRestProxyTests.java @@ -407,6 +407,7 @@ public void syncPutRequestWithUnexpectedResponse() { assertNotNull(e.value()); assertTrue(e.value() instanceof LinkedHashMap); + @SuppressWarnings("unchecked") final LinkedHashMap expectedBody = (LinkedHashMap) e.value(); assertEquals("I'm the body!", expectedBody.get("data")); } diff --git a/core/azure-core-test/README.md b/core/azure-core-test/README.md index b84ede075f345..9fbc3c45c3f64 100644 --- a/core/azure-core-test/README.md +++ b/core/azure-core-test/README.md @@ -1,6 +1,6 @@ -# Azure common test client library for Java +# Azure core test client library for Java -Library containing common classes used to test Azure SDK client libraries. +Library containing core classes used to test Azure SDK client libraries. * Create live or playback JUnit tests using [TestBase][TestBase.java] and leveraging [InterceptorManager][InterceptorManager.java] to keep track of @@ -13,11 +13,11 @@ Library containing common classes used to test Azure SDK client libraries. To use this package, add the following to your _pom.xml_. ```xml - - com.azure - azure-common-test - 1.0.0-SNAPSHOT - + + com.azure + azure-core-test + 1.0.0-preview.1 + ``` ## Key concepts @@ -98,8 +98,7 @@ If you encounter any bugs with these SDKs, please file issues via ## Next steps Other useful packages are: -* [azure-common](../azure-common): Contains common classes and functionality used by all client libraries. -* [azure-common-auth](../azure-common-auth): Contains common classes for authenticating with Azure. +* [azure-core](../azure-core): Contains core classes and functionality used by all client libraries. ## Contributing @@ -112,8 +111,8 @@ If you would like to become an active contributor to this project please follow 1. Push to the branch (`git push origin my-new-feature`) 1. Create new Pull Request -[InterceptorManager.java]: ./src/main/java/com/azure/common/test/InterceptorManager.java -[PlaybackClient.java]: ./src/main/java/com/azure/common/test/http/PlaybackClient.java -[RecordedData.java]: ./src/main/java/com/azure/common/test/models/RecordedData.java -[RecordNetworkCallPolicy.java]: ./src/main/java/com/azure/common/test/policy/RecordNetworkCallPolicy.java -[TestBase.java]: ./src/main/java/com/azure/common/test/TestBase.java +[InterceptorManager.java]: ./src/main/java/com/azure/core/test/InterceptorManager.java +[PlaybackClient.java]: ./src/main/java/com/azure/core/test/http/PlaybackClient.java +[RecordedData.java]: ./src/main/java/com/azure/core/test/models/RecordedData.java +[RecordNetworkCallPolicy.java]: ./src/main/java/com/azure/core/test/policy/RecordNetworkCallPolicy.java +[TestBase.java]: ./src/main/java/com/azure/core/test/TestBase.java diff --git a/core/azure-core-test/pom.xml b/core/azure-core-test/pom.xml index d19277735ba2b..7dd327ef2b29f 100644 --- a/core/azure-core-test/pom.xml +++ b/core/azure-core-test/pom.xml @@ -1,18 +1,19 @@ - + 4.0.0 com.azure azure-core-parent - 1.0.0-preview.1 + 1.0.0-preview.3 ../pom.xml com.azure azure-core-test jar - 1.0.0-preview.1 + 1.0.0-preview.3 Microsoft Azure Java Core Test Library This package contains core test types for Azure Java clients. @@ -29,14 +30,13 @@ https://github.com/Azure/azure-sdk-for-java scm:git:https://github.com/Azure/azure-sdk-for-java.git scm:git:https://github.com/Azure/azure-sdk-for-java.git - v1.0.0-preview.1 com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 diff --git a/core/azure-core/README.md b/core/azure-core/README.md new file mode 100644 index 0000000000000..5323106dd8d0f --- /dev/null +++ b/core/azure-core/README.md @@ -0,0 +1,77 @@ +# Azure Core client library for Java + +[![Build Documentation](https://img.shields.io/badge/documentation-published-blue.svg)](https://azure.github.io/azure-sdk-for-java/track2reports/index.html) + +Azure Core provides shared primitives, abstractions, and helpers for modern Java Azure SDK client libraries. These libraries follow the [Azure SDK Design Guidelines for JavaT](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html) and can be easily identified by package names starting with `com.azure` and module names starting with `azure-`, e.g. `com.azure.storage.blobs` would be found within the `/sdk/storage/azure-storage-blob` directory. A more complete list of client libraries using Azure Core can be found [here](https://github.com/Azure/azure-sdk-for-java). + +Azure Core allows client libraries to expose common functionality in a consistent fashion, so that once you learn how to use these APIs in one client library, you will know how to use them in other client libraries. + +## Getting started + +Typically, you will not need to install or specifically depend on Azure Core, instead it will be transitively downloaded by your build tool when you depend on of the client libraries using it. In case you want to depend on it explicitly (to implement your own client library, for example), include the following Maven dependency: + +```xml + + com.azure + azure-core + 1.0.0-preview.2 + +``` + +For details on including this dependency in other build tools (Gradle, SBT, etc), refer [here](https://search.maven.org/artifact/com.azure/azure-core). + +## Key concepts + +The key concepts of Azure Core (and therefore all Azure client libraries using Azure Core) include: + +- Configuring service clients, e.g. configuring retries, logging, etc. +- Accessing HTTP response details (`Response`). +- Calling long running operations (`Poller`). +- Paging and asynchronous streams (`PagedFlux`). +- Exceptions for reporting errors from service requests in a consistent fashion. +- Abstractions for representing Azure SDK credentials. + +These will be introduced by way of the examples presented below. + +## Examples + +### Accessing HTTP Response Details Using `Response` + +_Service clients_ have methods that can be used to call Azure services. We refer to these client methods _service methods_. +_Service methods_ return a shared Azure Core type `Response`. This type provides access to both the deserialized result of the service call, and to the details of the HTTP response returned from the server. + +### HTTP pipelines with `HttpPipeline` + +Coming soon ... + +### Exception Hierarchy with `AzureException` + +Coming soon ... + +### Pagination with `PagedFlux` + +Coming soon ... + +### Long Running Operations with `Poller` + +Coming soon ... + +## Next steps + +Get started with some of the Azure libraries that are [built using Azure Core](https://github.com/Azure/azure-sdk-for-java). + +## Troubleshooting + +If you encounter any bugs, please file issues via [GitHub Issues](https://github.com/Azure/azure-sdk-for-java/issues) or checkout +[StackOverflow for Azure Java SDK](http://stackoverflow.com/questions/tagged/azure-java-sdk). + +## Contributing + +If you would like to become an active contributor to this project please follow the instructions provided in +[Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html). + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request diff --git a/core/azure-core/pom.xml b/core/azure-core/pom.xml index c6f6712cb578e..33deba0573e12 100644 --- a/core/azure-core/pom.xml +++ b/core/azure-core/pom.xml @@ -7,13 +7,14 @@ com.azure azure-core-parent - 1.0.0-preview.1 + 1.0.0-preview.3 ../pom.xml com.azure azure-core jar + 1.0.0-preview.3 Microsoft Azure Java Core Library This package contains core types for Azure Java clients. @@ -38,9 +39,8 @@ https://github.com/Azure/azure-sdk-for-java scm:git:https://github.com/Azure/azure-sdk-for-java.git scm:git:https://github.com/Azure/azure-sdk-for-java.git - v1.0.0-preview.1 - + UTF-8 diff --git a/core/azure-core/src/main/java/com/azure/core/http/HttpResponse.java b/core/azure-core/src/main/java/com/azure/core/http/HttpResponse.java index bb57fcf5f3da6..1761b6bbbc0d5 100644 --- a/core/azure-core/src/main/java/com/azure/core/http/HttpResponse.java +++ b/core/azure-core/src/main/java/com/azure/core/http/HttpResponse.java @@ -58,7 +58,7 @@ public abstract class HttpResponse implements Closeable { * .reduce((x,y) -> x + y) * .subscribeOn(Schedulers.io()) * .observeOn(Schedulers.io()) - * .blockingGet(); + * ; * } * *

diff --git a/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java b/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java index 9ca980855fc8d..7668f1e1d5c80 100644 --- a/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java +++ b/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java @@ -65,17 +65,17 @@ public Mono process(HttpPipelineCallContext context, HttpPipelineN Function> logResponseDelegate = logResponseDelegate(logger, context.httpRequest().url(), startNs); // return logRequest.then(next.process()).flatMap(logResponseDelegate) - .doOnError(throwable -> logger.asWarning().log("<-- HTTP FAILED: ", throwable)); + .doOnError(throwable -> logger.warning("<-- HTTP FAILED: ", throwable)); } private Mono logRequest(final ClientLogger logger, final HttpRequest request) { if (detailLevel.shouldLogURL()) { - logger.asInfo().log("--> {} {}", request.httpMethod(), request.url()); + logger.info("--> {} {}", request.httpMethod(), request.url()); } if (detailLevel.shouldLogHeaders()) { for (HttpHeader header : request.headers()) { - logger.asInfo().log(header.toString()); + logger.info(header.toString()); } } // @@ -83,8 +83,8 @@ private Mono logRequest(final ClientLogger logger, final HttpRequest reque // if (detailLevel.shouldLogBody()) { if (request.body() == null) { - logger.asInfo().log("(empty body)"); - logger.asInfo().log("--> END {}", request.httpMethod()); + logger.info("(empty body)"); + logger.info("--> END {}", request.httpMethod()); } else { boolean isHumanReadableContentType = !"application/octet-stream".equalsIgnoreCase(request.headers().value("Content-Type")); final long contentLength = getContentLength(request.headers()); @@ -95,16 +95,16 @@ private Mono logRequest(final ClientLogger logger, final HttpRequest reque reqBodyLoggingMono = collectedBytes.flatMap(bytes -> { String bodyString = new String(bytes, StandardCharsets.UTF_8); bodyString = prettyPrintIfNeeded(logger, request.headers().value("Content-Type"), bodyString); - logger.asInfo().log("{}-byte body:%n{}", contentLength, bodyString); - logger.asInfo().log("--> END {}", request.httpMethod()); + logger.info("{}-byte body:%n{}", contentLength, bodyString); + logger.info("--> END {}", request.httpMethod()); return Mono.empty(); }); } catch (Exception e) { reqBodyLoggingMono = Mono.error(e); } } else { - logger.asInfo().log("{}-byte body: (content not logged)", contentLength); - logger.asInfo().log("--> END {}", request.httpMethod()); + logger.info("{}-byte body: (content not logged)", contentLength); + logger.info("--> END {}", request.httpMethod()); } } } @@ -125,12 +125,12 @@ private Function> logResponseDelegate(final Cli HttpResponseStatus responseStatus = HttpResponseStatus.valueOf(response.statusCode()); if (detailLevel.shouldLogURL()) { - logger.asInfo().log("<-- {} {} {} ({} ms, {} body)", response.statusCode(), responseStatus.reasonPhrase(), url, tookMs, bodySize); + logger.info("<-- {} {} {} ({} ms, {} body)", response.statusCode(), responseStatus.reasonPhrase(), url, tookMs, bodySize); } if (detailLevel.shouldLogHeaders()) { for (HttpHeader header : response.headers()) { - logger.asInfo().log(header.toString()); + logger.info(header.toString()); } } @@ -142,16 +142,16 @@ private Function> logResponseDelegate(final Cli final HttpResponse bufferedResponse = response.buffer(); return bufferedResponse.bodyAsString().map(bodyStr -> { bodyStr = prettyPrintIfNeeded(logger, contentTypeHeader, bodyStr); - logger.asInfo().log("Response body:\n{}", bodyStr); - logger.asInfo().log("<-- END HTTP"); + logger.info("Response body:\n{}", bodyStr); + logger.info("<-- END HTTP"); return bufferedResponse; - }); + }).switchIfEmpty(Mono.defer(() -> Mono.just(bufferedResponse))); } else { - logger.asInfo().log("(body content not logged)"); - logger.asInfo().log("<-- END HTTP"); + logger.info("(body content not logged)"); + logger.info("<-- END HTTP"); } } else { - logger.asInfo().log("<-- END HTTP"); + logger.info("<-- END HTTP"); } return Mono.just(response); }; @@ -164,7 +164,7 @@ private String prettyPrintIfNeeded(ClientLogger logger, String contentType, Stri final Object deserialized = PRETTY_PRINTER.readTree(body); result = PRETTY_PRINTER.writeValueAsString(deserialized); } catch (Exception e) { - logger.asWarning().log("Failed to pretty print JSON: {}", e.getMessage()); + logger.warning("Failed to pretty print JSON: {}", e.getMessage()); } } return result; diff --git a/core/azure-core/src/main/java/com/azure/core/http/rest/VoidResponse.java b/core/azure-core/src/main/java/com/azure/core/http/rest/VoidResponse.java index bd232781e7214..355cc01321fb0 100644 --- a/core/azure-core/src/main/java/com/azure/core/http/rest/VoidResponse.java +++ b/core/azure-core/src/main/java/com/azure/core/http/rest/VoidResponse.java @@ -25,7 +25,7 @@ public VoidResponse(HttpRequest request, int statusCode, HttpHeaders headers) { * * @param response a response used to construct the void response. */ - public VoidResponse(Response response) { + public VoidResponse(Response response) { super(response.request(), response.statusCode(), response.headers(), null); } } diff --git a/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java b/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java index 6babb71d6f49e..d61885ce272b3 100644 --- a/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java +++ b/core/azure-core/src/main/java/com/azure/core/implementation/RestProxy.java @@ -440,7 +440,7 @@ private Response createResponse(HttpDecodedResponse response, Type entityType } // try to create an instance using our list of potential candidates - for (Constructor constructor : constructors) { + for (Constructor constructor : constructors) { final Constructor> ctor = (Constructor>) constructor; try { @@ -667,6 +667,6 @@ public static A create(Class swaggerInterface, HttpPipeline httpPipeline) public static A create(Class swaggerInterface, HttpPipeline httpPipeline, SerializerAdapter serializer) { final SwaggerInterfaceParser interfaceParser = new SwaggerInterfaceParser(swaggerInterface, serializer); final RestProxy restProxy = new RestProxy(httpPipeline, serializer, interfaceParser); - return (A) Proxy.newProxyInstance(swaggerInterface.getClassLoader(), new Class[]{swaggerInterface}, restProxy); + return (A) Proxy.newProxyInstance(swaggerInterface.getClassLoader(), new Class[]{swaggerInterface}, restProxy); } } diff --git a/core/azure-core/src/main/java/com/azure/core/implementation/SwaggerMethodParser.java b/core/azure-core/src/main/java/com/azure/core/implementation/SwaggerMethodParser.java index f1844be9687f3..1fd98ca0298ca 100644 --- a/core/azure-core/src/main/java/com/azure/core/implementation/SwaggerMethodParser.java +++ b/core/azure-core/src/main/java/com/azure/core/implementation/SwaggerMethodParser.java @@ -309,6 +309,7 @@ public Iterable headers(Object[] swaggerMethodArguments) { if (0 <= parameterIndex && parameterIndex < swaggerMethodArguments.length) { final Object methodArgument = swaggerMethodArguments[headerSubstitution.methodParameterIndex()]; if (methodArgument instanceof Map) { + @SuppressWarnings("unchecked") final Map headerCollection = (Map) methodArgument; final String headerCollectionPrefix = headerSubstitution.urlParameterName(); for (final Map.Entry headerCollectionEntry : headerCollection.entrySet()) { diff --git a/core/azure-core/src/main/java/com/azure/core/implementation/serializer/HttpResponseBodyDecoder.java b/core/azure-core/src/main/java/com/azure/core/implementation/serializer/HttpResponseBodyDecoder.java index 97df3f20bf0c5..0d3fc89953658 100644 --- a/core/azure-core/src/main/java/com/azure/core/implementation/serializer/HttpResponseBodyDecoder.java +++ b/core/azure-core/src/main/java/com/azure/core/implementation/serializer/HttpResponseBodyDecoder.java @@ -274,6 +274,7 @@ private static Object convertToResultType(Object wireResponse, Type resultType, if (TypeUtil.isTypeOrSubTypeOf(resultType, List.class)) { final Type resultElementType = TypeUtil.getTypeArgument(resultType); + @SuppressWarnings("unchecked") final List wireResponseList = (List) wireResponse; final int wireResponseListSize = wireResponseList.size(); @@ -289,6 +290,7 @@ private static Object convertToResultType(Object wireResponse, Type resultType, } else if (TypeUtil.isTypeOrSubTypeOf(resultType, Map.class)) { final Type resultValueType = TypeUtil.getTypeArguments(resultType)[1]; + @SuppressWarnings("unchecked") final Map wireResponseMap = (Map) wireResponse; final Set> wireResponseEntries = wireResponseMap.entrySet(); diff --git a/core/azure-core/src/main/java/com/azure/core/implementation/util/FluxUtil.java b/core/azure-core/src/main/java/com/azure/core/implementation/util/FluxUtil.java index bb2b62bad5a9f..1ec6329fdf95d 100644 --- a/core/azure-core/src/main/java/com/azure/core/implementation/util/FluxUtil.java +++ b/core/azure-core/src/main/java/com/azure/core/implementation/util/FluxUtil.java @@ -212,19 +212,25 @@ public void completed(Integer bytesWritten, Object attachment) { } //noinspection NonAtomicOperationOnVolatileField pos += bytesWritten; - subscription.request(1); + if (subscription != null) { + subscription.request(1); + } } @Override public void failed(Throwable exc, Object attachment) { - subscription.cancel(); + if (subscription != null) { + subscription.cancel(); + } emitter.error(exc); } }; @Override public void onError(Throwable throwable) { - subscription.cancel(); + if (subscription != null) { + subscription.cancel(); + } emitter.error(throwable); } @@ -371,7 +377,7 @@ public void completed(Integer bytesRead, ByteBuf buffer) { // use local variable to perform fewer volatile reads long pos = position; // - int bytesWanted = (int) Math.min(bytesRead, maxRequired(pos)); + int bytesWanted = Math.min(bytesRead, maxRequired(pos)); buffer.writerIndex(bytesWanted); long position2 = pos + bytesWanted; //noinspection NonAtomicOperationOnVolatileField diff --git a/core/azure-core/src/main/java/com/azure/core/implementation/util/ImplUtils.java b/core/azure-core/src/main/java/com/azure/core/implementation/util/ImplUtils.java index 272b93e2d0dbf..57e8f593632f1 100644 --- a/core/azure-core/src/main/java/com/azure/core/implementation/util/ImplUtils.java +++ b/core/azure-core/src/main/java/com/azure/core/implementation/util/ImplUtils.java @@ -81,7 +81,7 @@ public static boolean isNullOrEmpty(Object[] array) { * @param collection Collection being checked for nullness or emptiness. * @return True if the collection is null or empty, false otherwise. */ - public static boolean isNullOrEmpty(Collection collection) { + public static boolean isNullOrEmpty(Collection collection) { return collection == null || collection.isEmpty(); } @@ -90,7 +90,7 @@ public static boolean isNullOrEmpty(Collection collection) { * @param map Map being checked for nullness or emptiness. * @return True if the map is null or empty, false otherwise. */ - public static boolean isNullOrEmpty(Map map) { + public static boolean isNullOrEmpty(Map map) { return map == null || map.isEmpty(); } diff --git a/core/azure-core/src/main/java/com/azure/core/util/configuration/Configuration.java b/core/azure-core/src/main/java/com/azure/core/util/configuration/Configuration.java index 990ae06c99cb1..ab68188df2435 100644 --- a/core/azure-core/src/main/java/com/azure/core/util/configuration/Configuration.java +++ b/core/azure-core/src/main/java/com/azure/core/util/configuration/Configuration.java @@ -222,7 +222,7 @@ private boolean loadFrom(String name, Function loader, String lo String value = loader.apply(name); if (!ImplUtils.isNullOrEmpty(value) && !value.equals(configurations.get(name))) { configurations.put(name, value); - logger.asInfo().log(logMessage, name, value); + logger.info(logMessage, name, value); return true; } diff --git a/core/azure-core/src/main/java/com/azure/core/util/configuration/NoopConfiguration.java b/core/azure-core/src/main/java/com/azure/core/util/configuration/NoopConfiguration.java index 982b57b5398db..8dee4f48d17b8 100644 --- a/core/azure-core/src/main/java/com/azure/core/util/configuration/NoopConfiguration.java +++ b/core/azure-core/src/main/java/com/azure/core/util/configuration/NoopConfiguration.java @@ -15,7 +15,7 @@ public String get(String name) { @Override public T get(String name, T defaultValue) { - return null; + return defaultValue; } @Override diff --git a/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java b/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java index bf02a1cedeb49..c05516502f638 100644 --- a/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java +++ b/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java @@ -14,8 +14,8 @@ /** * This is a fluent logger helper class that wraps a plug-able {@link Logger}. * - *

This logger logs format-able messages that use {@code {}} as the placeholder. When a throwable is the last - * argument of the format varargs and the logger is enabled for {@link ClientLogger#asVerbose() verbose} logging the + *

This logger logs formattable messages that use {@code {}} as the placeholder. When a throwable is the last + * argument of the format varargs and the logger is enabled for {@link ClientLogger#verbose(String, Object...) verbose} logging the * stack trace for the throwable will be included in the log message.

* *

A minimum logging level threshold is determined by the {@link BaseConfigurations#AZURE_LOG_LEVEL AZURE_LOG_LEVEL} @@ -23,10 +23,10 @@ * *

Log level hierarchy

*
    - *
  1. {@link ClientLogger#asError() Error}
  2. - *
  3. {@link ClientLogger#asWarning() Warning}
  4. - *
  5. {@link ClientLogger#asInfo() Info}
  6. - *
  7. {@link ClientLogger#asVerbose() Verbose}
  8. + *
  9. {@link ClientLogger#error(String, Object...) Error}
  10. + *
  11. {@link ClientLogger#warning(String, Object...) Warning}
  12. + *
  13. {@link ClientLogger#info(String, Object...) Info}
  14. + *
  15. {@link ClientLogger#verbose(String, Object...) Verbose}
  16. *
* * @see Configuration @@ -34,11 +34,6 @@ public class ClientLogger { private final Logger logger; - /* - * Indicate that log level is at trace level. - */ - private static final int TRACE_LEVEL = 0; - /* * Indicate that log level is at verbose level. */ @@ -64,17 +59,12 @@ public class ClientLogger { */ private static final int DISABLED_LEVEL = 5; - private static final int DEFAULT_LOG_LEVEL = DISABLED_LEVEL; - private int level = DEFAULT_LOG_LEVEL; - - private int configurationLevel; - /** * Retrieves a logger for the passed class using the {@link LoggerFactory}. * * @param clazz Class creating the logger. */ - public ClientLogger(Class clazz) { + public ClientLogger(Class clazz) { this(clazz.getName()); } @@ -88,89 +78,108 @@ public ClientLogger(String className) { } /** - * Sets the logger to the verbose logging level. + * Logs a formattable message that uses {@code {}} as the placeholder at {@code verbose} log level * - * @return Updated ClientLogger if verbose is enabled. - */ - public ClientLogger asVerbose() { - return asLevel(VERBOSE_LEVEL); - } - - /** - * Sets the logger to the info logging level. + *

Code Samples

+ *

+ * Logging a message at verbose log level + * {@codesnippet com.azure.core.implementation.util.clientlogger.verbose} * - * @return Updated ClientLogger if info is enabled. + * @param format The formattable message to log + * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - public ClientLogger asInfo() { - return asLevel(INFORMATIONAL_LEVEL); + public void verbose(String format, Object... args) { + log(VERBOSE_LEVEL, format, args); } /** - * Sets the logger to the warning logging level. + * Logs a formattable message that uses {@code {}} as the placeholder at {@code informational} log level * - * @return Updated ClientLogger if warn is enabled. + *

Code Samples

+ *

+ * Logging a message at informational log level + * {@codesnippet com.azure.core.implementation.util.clientlogger.info} + * + * @param format The formattable message to log + * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - public ClientLogger asWarning() { - return asLevel(WARNING_LEVEL); + public void info(String format, Object... args) { + log(INFORMATIONAL_LEVEL, format, args); } /** - * Sets the logger to the error logging level. + * Logs a formattable message that uses {@code {}} as the placeholder at {@code warning} log level + * + *

Code Samples

+ *

+ * Logging a message at warning log level + * {@codesnippet com.azure.core.implementation.util.clientlogger.warning} * - * @return Updated ClientLogger if error is enabled.. + * @param format The formattable message to log + * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - public ClientLogger asError() { - return asLevel(ERROR_LEVEL); + public void warning(String format, Object... args) { + log(WARNING_LEVEL, format, args); } /** - * Logs a format-able message that uses {@code {}} as the placeholder. + * Logs a formattable message that uses {@code {}} as the placeholder at {@code error} log level * *

Code Samples

*

- * Logging a message with the default log level - *

-     * ClientLogger logger = new ClientLogger(Example.class);
-     * logger.log("A message");
-     * 
- *

- * Logging a format-able warning - *

-     * ClientLogger logger = new ClientLogger(Example.class);
-     * logger.asWarning().log("A format-able message. Hello, {}", name);
-     * 
- *

* Logging an error with stack trace - *

-     * ClientLogger logger = new ClientLogger(Example.class);
-     * try {
-     *    upload(resource);
-     * } catch (Throwable ex) {
-     *    logger.asError().log("Failed to upload {}", resource.name(), ex);
-     * }
-     * 
+ * {@codesnippet com.azure.core.implementation.util.clientlogger.error} * - * @param format Format-able message. - * @param args Arguments for the message, if an exception is being logged last argument is the throwable. + * @param format The formattable message to log + * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - public void log(String format, Object... args) { - if (canLogAtLevel(level)) { - performLogging(format, args); + public void error(String format, Object... args) { + log(ERROR_LEVEL, format, args); + } + + /* + * This method logs the formattable message if the {@code logLevel} is enabled + * + * @param logLevel The log level at which this message should be logged + * @param format The formattable message to log + * @param args Arguments for the message, if an exception is being logged last argument is the throwable. + */ + private void log(int logLevel, String format, Object... args) { + if (canLogAtLevel(logLevel)) { + performLogging(logLevel, format, args); + } + } + + /** + * This will log {@link RuntimeException}, if logging is enabled , and throw the runtime exception. + * @param runtimeException to be thrown. It will do nothing if {@code null} is provided. + * @throws RuntimeException which is requested by this call. + */ + public void logAndThrow(RuntimeException runtimeException) { + if (runtimeException == null) { + return; + } + + // it will only log if error level is enabled in configuration + if (canLogAtLevel(ERROR_LEVEL)) { + logger.error(runtimeException.getMessage(), runtimeException); } + throw runtimeException; } /* * Performs the logging. - * @param format Format-able message. + * + * @param format formattable message. * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - private void performLogging(String format, Object... args) { + private void performLogging(int logLevel, String format, Object... args) { // If the logging level is less granular than verbose remove the potential throwable from the args. - if (configurationLevel > VERBOSE_LEVEL) { + if (logLevel > VERBOSE_LEVEL) { args = attemptToRemoveThrowable(args); } - switch (level) { + switch (logLevel) { case VERBOSE_LEVEL: logger.debug(format, args); break; @@ -189,19 +198,6 @@ private void performLogging(String format, Object... args) { } } - /* - * Helper method to set the logging level. - * @param level Logging level - * @return Updated ClientLogger if the level is enabled. - */ - private ClientLogger asLevel(int level) { - if (canLogAtLevel(level)) { - this.level = level; - } - - return this; - } - /* * Helper method that determines if logging is enabled at a given level. * @param level Logging level @@ -209,7 +205,7 @@ private ClientLogger asLevel(int level) { */ private boolean canLogAtLevel(int level) { // Check the configuration level every time the logger is called in case it has changed. - configurationLevel = ConfigurationManager.getConfiguration().get(BaseConfigurations.AZURE_LOG_LEVEL, DISABLED_LEVEL); + int configurationLevel = ConfigurationManager.getConfiguration().get(BaseConfigurations.AZURE_LOG_LEVEL, DISABLED_LEVEL); if (level < configurationLevel) { return false; } @@ -230,6 +226,7 @@ private boolean canLogAtLevel(int level) { /* * Removes the last element from the arguments if it is a throwable. + * * @param args Arguments * @return The arguments with the last element removed if it was a throwable, otherwise the unmodified arguments. */ @@ -242,7 +239,6 @@ private Object[] attemptToRemoveThrowable(Object... args) { if (potentialThrowable instanceof Throwable) { return Arrays.copyOf(args, args.length - 1); } - return args; } } diff --git a/core/azure-core/src/main/java/com/azure/core/util/polling/Poller.java b/core/azure-core/src/main/java/com/azure/core/util/polling/Poller.java index 3c9da3c408202..4093c2e307b27 100644 --- a/core/azure-core/src/main/java/com/azure/core/util/polling/Poller.java +++ b/core/azure-core/src/main/java/com/azure/core/util/polling/Poller.java @@ -3,6 +3,7 @@ package com.azure.core.util.polling; +import com.azure.core.util.logging.ClientLogger; import reactor.core.Disposable; import reactor.core.publisher.Flux; @@ -58,6 +59,7 @@ */ public class Poller { + private final ClientLogger logger = new ClientLogger(Poller.class); /* * poll operation is a function that takes the previous PollResponse, and * returns a new Mono of PollResponse to represent the current state @@ -77,7 +79,7 @@ public class Poller { /* * This will be called when cancel operation is triggered. */ - private Consumer cancelOperation; + private Consumer> cancelOperation; /* * Indicate to poll automatically or not when poller is created. @@ -117,10 +119,10 @@ public class Poller { */ public Poller(Duration pollInterval, Function, Mono>> pollOperation) { if (pollInterval == null || pollInterval.toNanos() <= 0) { - throw new IllegalArgumentException("Null, negative or zero value for poll interval is not allowed."); + logger.logAndThrow(new IllegalArgumentException("Null, negative or zero value for poll interval is not allowed.")); } if (pollOperation == null) { - throw new IllegalArgumentException("Null value for poll operation is not allowed."); + logger.logAndThrow(new IllegalArgumentException("Null value for poll operation is not allowed.")); } this.pollInterval = pollInterval; @@ -153,7 +155,7 @@ public Poller(Duration pollInterval, Function, Mono, Mono>> pollOperation, Consumer cancelOperation) { + public Poller(Duration pollInterval, Function, Mono>> pollOperation, Consumer> cancelOperation) { this(pollInterval, pollOperation); this.cancelOperation = cancelOperation; } @@ -245,10 +247,10 @@ public PollResponse blockUntil(OperationStatus statusToBlockFor) { */ public PollResponse blockUntil(OperationStatus statusToBlockFor, Duration timeout) { if (statusToBlockFor == null) { - throw new IllegalArgumentException("Null value for status is not allowed."); + logger.logAndThrow(new IllegalArgumentException("Null value for status is not allowed.")); } if (timeout != null && timeout.toNanos() <= 0) { - throw new IllegalArgumentException("Negative or zero value for timeout is not allowed."); + logger.logAndThrow(new IllegalArgumentException("Negative or zero value for timeout is not allowed.")); } if (!isAutoPollingEnabled()) { setAutoPollingEnabled(true); diff --git a/core/azure-core/src/samples/java/com/azure/core/implementation/util/ClientLoggerJavaDocCodeSnippets.java b/core/azure-core/src/samples/java/com/azure/core/implementation/util/ClientLoggerJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..c042947396688 --- /dev/null +++ b/core/azure-core/src/samples/java/com/azure/core/implementation/util/ClientLoggerJavaDocCodeSnippets.java @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.implementation.util; + +import com.azure.core.util.logging.ClientLogger; +import java.io.File; +import java.io.IOException; + +/** + * Code snippets for {@link ClientLogger} javadocs + */ +public class ClientLoggerJavaDocCodeSnippets { + + /** + * Code snippets to show usage of {@link ClientLogger} at all log levels + */ + public void loggingSnippets() { + + ClientLogger logger = new ClientLogger(ClientLoggerJavaDocCodeSnippets.class); + String name = getName(); + + // BEGIN: com.azure.core.implementation.util.clientlogger.verbose + logger.verbose("A formattable message. Hello, {}", name); + // END: com.azure.core.implementation.util.clientlogger.verbose + + // BEGIN: com.azure.core.implementation.util.clientlogger.info + logger.info("A formattable message. Hello, {}", name); + // END: com.azure.core.implementation.util.clientlogger.info + + // BEGIN: com.azure.core.implementation.util.clientlogger.warning + logger.warning("A formattable message. Hello, {}", name); + // END: com.azure.core.implementation.util.clientlogger.warning + + File resource = getFile(); + // BEGIN: com.azure.core.implementation.util.clientlogger.error + try { + upload(resource); + } catch (IOException ex) { + logger.error("A formattable message. Hello, {}", name, ex); + } + // END: com.azure.core.implementation.util.clientlogger.error + } + + /** + * Implementation not provided + * @return {@code null} + */ + private File getFile() { + return null; + } + + /** + * Implementation not provided + * @return {@code null} + */ + private String getName() { + return null; + } + + /** + * Implementation not provided + * @param resource A file resource + * @throws IOException if upload fails + */ + private void upload(File resource) throws IOException { + throw new IOException(); + } +} diff --git a/core/azure-core/src/test/java/com/azure/core/implementation/RestProxyTests.java b/core/azure-core/src/test/java/com/azure/core/implementation/RestProxyTests.java index b4ab70e4984b3..2afd1cdd5768a 100644 --- a/core/azure-core/src/test/java/com/azure/core/implementation/RestProxyTests.java +++ b/core/azure-core/src/test/java/com/azure/core/implementation/RestProxyTests.java @@ -510,6 +510,7 @@ public void syncPutRequestWithUnexpectedResponse() { assertNotNull(e.value()); assertTrue(e.value() instanceof LinkedHashMap); + @SuppressWarnings("unchecked") final LinkedHashMap expectedBody = (LinkedHashMap) e.value(); assertEquals("I'm the body!", expectedBody.get("data")); } @@ -526,6 +527,7 @@ public void asyncPutRequestWithUnexpectedResponse() { assertNotNull(e.value()); assertTrue(e.value() instanceof LinkedHashMap); + @SuppressWarnings("unchecked") final LinkedHashMap expectedBody = (LinkedHashMap) e.value(); assertEquals("I'm the body!", expectedBody.get("data")); } @@ -628,6 +630,7 @@ public void syncPutRequestWithUnexpectedResponseAndNoFallthroughExceptionType() assertNotNull(e.value()); assertTrue(e.value() instanceof LinkedHashMap); + @SuppressWarnings("unchecked") final LinkedHashMap expectedBody = (LinkedHashMap) e.value(); assertEquals("I'm the body!", expectedBody.get("data")); } catch (Throwable e) { @@ -646,6 +649,7 @@ public void asyncPutRequestWithUnexpectedResponseAndNoFallthroughExceptionType() assertNotNull(e.value()); assertTrue(e.value() instanceof LinkedHashMap); + @SuppressWarnings("unchecked") final LinkedHashMap expectedBody = (LinkedHashMap) e.value(); assertEquals("I'm the body!", expectedBody.get("data")); } catch (Throwable e) { diff --git a/core/azure-core/src/test/java/com/azure/core/util/polling/PollerTests.java b/core/azure-core/src/test/java/com/azure/core/util/polling/PollerTests.java index 8d2b4f65b49c4..c03e1b19ef51d 100644 --- a/core/azure-core/src/test/java/com/azure/core/util/polling/PollerTests.java +++ b/core/azure-core/src/test/java/com/azure/core/util/polling/PollerTests.java @@ -234,7 +234,7 @@ public void disableAutoPollAndEnableAfterCompletionSuccessfullyDone() throws Exc Poller createCertPoller = new Poller<>(pollInterval, pollOperation); - new Thread().sleep(6 * pollInterval.toMillis()); + Thread.sleep(6 * pollInterval.toMillis()); debug("Try to disable autopolling.."); createCertPoller.setAutoPollingEnabled(false); @@ -271,7 +271,7 @@ public void autoStartPollingAndSuccessfullyComplete() throws Exception { Poller createCertPoller = new Poller<>(pollInterval, pollOperation); while (createCertPoller.getStatus() != OperationStatus.SUCCESSFULLY_COMPLETED) { - new Thread().sleep(pollInterval.toMillis()); + Thread.sleep(pollInterval.toMillis()); } Assert.assertTrue(createCertPoller.getStatus() == OperationStatus.SUCCESSFULLY_COMPLETED); diff --git a/core/pom.xml b/core/pom.xml index 4f6a7ce87ce25..8a99642ce90cc 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -2,19 +2,20 @@ ~ Copyright (c) Microsoft Corporation. All rights reserved. ~ Licensed under the MIT License. --> - + 4.0.0 com.azure azure-client-sdk-parent - 1.0.0 + 1.1.0 ../pom.client.xml com.azure azure-core-parent - 1.0.0-preview.1 + 1.0.0-preview.3 pom Microsoft Azure Core Libraries for Java @@ -33,12 +34,12 @@ scm:git:https://github.com/Azure/azure-sdk-for-java scm:git:https://github.com/Azure/azure-sdk-for-java.git scm:git:https://github.com/Azure/azure-sdk-for-java.git - v1.0.0-preview.1 UTF-8 - + + diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml index ba75290e7d9fb..d1b091127da59 100644 --- a/eng/.docsettings.yml +++ b/eng/.docsettings.yml @@ -3,6 +3,7 @@ omitted_paths: - profiles/* - loganalytics/data-plane/samples/* - sdk/applicationinsights/microsoft-azure-applicationinsights-query/samples/* + - sdk/loganalytics/microsoft-azure-loganalytics/samples/* - "*/resource-manager/*" - eng/* language: java @@ -34,18 +35,19 @@ known_presence_issues: - ['cognitiveservices/data-plane/vision/customvision/prediction', '#2847'] - ['cognitiveservices/data-plane/vision/customvision/training', '#2847'] - ['cognitiveservices/data-plane/vision/faceapi', '#2847'] - - ['keyvault/data-plane/azure-keyvault', '#2847'] - - ['keyvault/data-plane/azure-keyvault-core', '#2847'] - - ['keyvault/data-plane/azure-keyvault-cryptography', '#2847'] - - ['keyvault/data-plane/azure-keyvault-extensions', '#2847'] - - ['keyvault/data-plane/azure-keyvault-webkey', '#2847'] - - ['mediaservices/data-plane', '#2847'] + - ['sdk/keyvault/microsoft-azure-keyvault', '#2847'] + - ['sdk/keyvault/microsoft-azure-keyvault-core', '#2847'] + - ['sdk/keyvault/microsoft-azure-keyvault-cryptography', '#2847'] + - ['sdk/keyvault/microsoft-azure-keyvault-extensions', '#2847'] + - ['sdk/keyvault/microsoft-azure-keyvault-webkey', '#2847'] + - ['sdk/mediaservices/microsoft-azure-media', '#2847'] - ['core/build-tools', '#2847'] - ['core/azure-core', '#2847'] - ['core/azure-core-auth', '#2847'] - ['core/azure-core-management', '#2847'] - ['cosmosdb/data-plane/commons-test-utils', '#2847'] - ['cosmosdb/data-plane/sdk', '#2847'] + - ['sdk/cosmos/sdk', '#2847'] - ['cosmosdb/data-plane/gateway', '#2847'] - ['cosmosdb/data-plane/commons', '#2847'] - ['cosmosdb/data-plane/direct-impl', '#2847'] @@ -53,13 +55,13 @@ known_content_issues: - ['sdk/template/azure-sdk-template/README.md','has other required sections'] - ['README.md', '#3113'] - ['sdk/applicationinsights/microsoft-azure-applicationinsights-query/README.md', '#3113'] - - ['authorization/msi-auth-token-provider-jar/readme.md', '#3113'] - ['sdk/batch/microsoft-azure-batch/README.md', '#3113'] - ['eventgrid/data-plane/README.md', '#3113'] - ['eventhubs/data-plane/readme.md', '#3113'] - ['eventhubs/data-plane/azure-eventhubs-eph/Readme.md', '#3113'] - - ['keyvault/data-plane/README.md', '#3113'] - - ['loganalytics/data-plane/README.md', '#3113'] + - ['sdk/authorization/microsoft-azure-authentication-msi-token-provider/readme.md', '#3113'] + - ['sdk/keyvault/README.md', '#3113'] + - ['sdk/loganalytics/microsoft-azure-loganalytics/README.md', '#3113'] - ['sdk/servicebus/README.md', '#3113'] - ['storage/data-plane/README.md', '#3113'] - ['storage/data-plane/swagger/README.md', '#3113'] @@ -68,6 +70,10 @@ known_content_issues: - ['cosmosdb/data-plane/benchmark/README.md', '#3113'] - ['cosmosdb/data-plane/changelog/README.md', '#3113'] - ['cosmosdb/data-plane/faq/README.md', '#3113'] + - ['sdk/cosmos/faq/README.md', '#3113'] + - ['sdk/cosmos/changelog/README.md', '#3113'] + - ['sdk/cosmos/benchmark/README.md', '#3113'] + - ['sdk/cosmos/README.md', '#3113'] package_indexing_exclusion_list: - azure-loganalytics-sample - azure-applicationinsights-query-sample diff --git a/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java new file mode 100644 index 0000000000000..6c4a730d5a99c --- /dev/null +++ b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ExternalDependencyExposedCheck.java @@ -0,0 +1,220 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.checkstyle.checks; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier; +import com.puppycrawl.tools.checkstyle.utils.CheckUtil; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * No external dependency exposed in public API + */ +public class ExternalDependencyExposedCheck extends AbstractCheck { + private static final String EXTERNAL_DEPENDENCY_ERROR = + "Class ''%s'', is a class from external dependency. You should not use it as a return or method argument type."; + + private static final Set VALID_DEPENDENCY_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + "java", "com.azure", "reactor", "io.netty.buffer.ByteBuf" + ))); + + private final Map simpleClassNameToQualifiedNameMap = new HashMap<>(); + private static boolean isImplPackage; + + @Override + public void beginTree(DetailAST rootAST) { + simpleClassNameToQualifiedNameMap.clear(); + isImplPackage = false; + } + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[] { + TokenTypes.PACKAGE_DEF, + TokenTypes.IMPORT, + TokenTypes.METHOD_DEF + }; + } + + @Override + public void visitToken(DetailAST token) { + if (isImplPackage) { + return; + } + + switch (token.getType()) { + case TokenTypes.PACKAGE_DEF: + String packageName = FullIdent.createFullIdent(token.findFirstToken(TokenTypes.DOT)).getText(); + isImplPackage = packageName.contains(".implementation"); + break; + case TokenTypes.IMPORT: + // Add all imported classes into a map, key is the name of class and value is the full package path of class. + final String importClassPath = FullIdent.createFullIdentBelow(token).getText(); + final String className = importClassPath.substring(importClassPath.lastIndexOf(".") + 1); + simpleClassNameToQualifiedNameMap.put(className, importClassPath); + break; + case TokenTypes.METHOD_DEF: + checkNoExternalDependencyExposed(token); + break; + default: + // Checkstyle complains if there's no default block in switch + break; + } + } + + /** + * Checks for external dependency, log the error if it is an invalid external dependency. + * + * @param methodDefToken METHOD_DEF AST node + */ + private void checkNoExternalDependencyExposed(DetailAST methodDefToken) { + final DetailAST modifiersToken = methodDefToken.findFirstToken(TokenTypes.MODIFIERS); + + // Getting the modifier of the method to determine if it is 'public' or 'protected'. + // Ignore the check if it is neither of 'public' nor 'protected', + final AccessModifier accessModifier = CheckUtil.getAccessModifierFromModifiersToken(modifiersToken); + if (!accessModifier.equals(AccessModifier.PUBLIC) && !accessModifier.equals(AccessModifier.PROTECTED)) { + return; + } + + // Checks for the return type of method + final DetailAST typeToken = methodDefToken.findFirstToken(TokenTypes.TYPE); + if (typeToken != null) { + getInvalidReturnTypes(typeToken).forEach( + (token, returnTypeName) -> log(token, String.format(EXTERNAL_DEPENDENCY_ERROR, returnTypeName))); + } + + // Checks for the parameters of the method + final DetailAST parametersToken = methodDefToken.findFirstToken(TokenTypes.PARAMETERS); + if (parametersToken != null) { + getInvalidParameterTypes(parametersToken).forEach( + (token, returnTypeName) -> log(token, String.format(EXTERNAL_DEPENDENCY_ERROR, returnTypeName))); + } + } + + /** + * Get invalid return types from a given TYPE node. + * + * @param typeToken TYPE AST node + * @return a map that maps the invalid TYPE node and the type name. + */ + private Map getInvalidReturnTypes(DetailAST typeToken) { + final Map invalidReturnTypeMap = new HashMap<>(); + + // Add all invalid external return types to the map + final DetailAST identToken = typeToken.findFirstToken(TokenTypes.IDENT); + if (identToken == null) { + return invalidReturnTypeMap; + } + final String typeName = identToken.getText(); + if (!isValidClassDependency(typeName)) { + invalidReturnTypeMap.put(typeToken, typeName); + } + + // TYPE_ARGUMENTS, add all invalid external types to the map + final DetailAST typeArgumentsToken = typeToken.findFirstToken(TokenTypes.TYPE_ARGUMENTS); + if (typeArgumentsToken != null) { + invalidReturnTypeMap.putAll(getInvalidTypeFromTypeArguments(typeArgumentsToken)); + } + + return invalidReturnTypeMap; + } + + /** + * Get invalid parameter types from a given PARAMETERS node. + * + * @param parametersTypeToken PARAMETERS AST node + * @return a map that maps all the invalid TYPE_ARGUMENT node and the type name + */ + private Map getInvalidParameterTypes(DetailAST parametersTypeToken) { + final Map invalidParameterTypesMap = new HashMap<>(); + for (DetailAST ast = parametersTypeToken.getFirstChild(); ast != null; ast = ast.getNextSibling()) { + if (ast.getType() == TokenTypes.PARAMETER_DEF) { + invalidParameterTypesMap.putAll(getInvalidTypeFromTypeArguments(ast.findFirstToken(TokenTypes.TYPE))); + } + } + return invalidParameterTypesMap; + } + + /** + * A helper function that checks TYPE AST node. Since both return type and input parameter argument type has + * TYPE AST node under. This function applied to both. + * + * @param typeArgumentsToken TYPE_ARGUMENTS AST node + * @return a map that maps all the invalid TYPE_ARGUMENT node and the type name + */ + private Map getInvalidTypeFromTypeArguments(DetailAST typeArgumentsToken) { + final Map invalidTypesMap = new HashMap<>(); + if (typeArgumentsToken == null) { + return invalidTypesMap; + } + // Checks multiple type arguments + for (DetailAST ast = typeArgumentsToken.getFirstChild(); ast != null; ast = ast.getNextSibling()) { + if (ast.getType() != TokenTypes.TYPE_ARGUMENT) { + continue; + } + + final String invalidTypeName = getInvalidTypeNameFromTypeArgument(ast); + if (invalidTypeName != null) { + invalidTypesMap.put(ast, invalidTypeName); + } + } + return invalidTypesMap; + } + + /** + * Get invalid type name from TYPE_ARGUMENT + * + * @param typeArgumentToken TYPE_ARGUMENT AST node + * @return an invalid type name if it is an invalid library. Otherwise, returns null. + */ + private String getInvalidTypeNameFromTypeArgument(DetailAST typeArgumentToken) { + final DetailAST identToken = typeArgumentToken.findFirstToken(TokenTypes.IDENT); + // if there is no IDENT token, implies the token is default java types. + if (identToken == null) { + return null; + } + + final String typeName = identToken.getText(); + // if not exist in the classPathMap, that implies the type is java default types, such as int. + return isValidClassDependency(typeName) ? null : typeName; + } + + /** + * A helper function that checks for whether a class is from a valid internal dependency or is a suppression class + * + * @param typeName the type name of class + * @return true if the class is a suppression class, otherwise, return false. + */ + private boolean isValidClassDependency(String typeName) { + // If the qualified class name does not exist in the map, + // it implies the type is a primitive Java type (ie. int, long, etc). + if (!simpleClassNameToQualifiedNameMap.containsKey(typeName)) { + return true; + } + + final String qualifiedName = simpleClassNameToQualifiedNameMap.get(typeName); + return VALID_DEPENDENCY_SET.stream() + .anyMatch(validPackageName -> qualifiedName.startsWith(validPackageName)); + } +} diff --git a/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java index 3b4250c5aa2dc..a21ed603ab72e 100644 --- a/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java +++ b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java @@ -109,10 +109,5 @@ public void visitToken(DetailAST ast) { // Checkstyle complains if there's no default block in switch break; } - } - - } - - diff --git a/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ServiceClientInstantiationCheck.java b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ServiceClientInstantiationCheck.java new file mode 100644 index 0000000000000..38adfaabbade6 --- /dev/null +++ b/eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ServiceClientInstantiationCheck.java @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.tools.checkstyle.checks; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier; +import com.puppycrawl.tools.checkstyle.utils.CheckUtil; + +/** + * Verify the classes with annotation @ServiceClient should have following rules: + *
    + *
  1. No public or protected constructors
  2. + *
  3. No public static method named 'builder'
  4. + *
  5. Since these classes are supposed to be immutable, all fields in the service client classes should be final.
  6. + *
+ */ +public class ServiceClientInstantiationCheck extends AbstractCheck { + private static final String SERVICE_CLIENT = "ServiceClient"; + private static final String BUILDER = "builder"; + private static final String ASYNC_CLIENT ="AsyncClient"; + private static final String CLIENT = "Client"; + private static final String IS_ASYNC = "isAsync"; + + private static boolean hasServiceClientAnnotation; + private static boolean isAsync; + private static boolean isImplPackage; + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[] { + TokenTypes.PACKAGE_DEF, + TokenTypes.CLASS_DEF, + TokenTypes.CTOR_DEF, + TokenTypes.METHOD_DEF, + TokenTypes.OBJBLOCK + }; + } + + @Override + public void beginTree(DetailAST root) { + hasServiceClientAnnotation = false; + isAsync = false; + isImplPackage = false; + } + + @Override + public void visitToken(DetailAST token) { + if (isImplPackage) { + return; + } + + switch (token.getType()) { + case TokenTypes.PACKAGE_DEF: + String packageName = FullIdent.createFullIdent(token.findFirstToken(TokenTypes.DOT)).getText(); + isImplPackage = packageName.contains(".implementation"); + break; + case TokenTypes.CLASS_DEF: + hasServiceClientAnnotation = hasServiceClientAnnotation(token); + if (hasServiceClientAnnotation) { + checkServiceClientNaming(token); + } + break; + case TokenTypes.CTOR_DEF: + if (hasServiceClientAnnotation) { + checkConstructor(token); + } + break; + case TokenTypes.METHOD_DEF: + if (hasServiceClientAnnotation) { + checkMethodName(token); + } + break; + case TokenTypes.OBJBLOCK: + if (hasServiceClientAnnotation) { + checkClassField(token); + } + break; + default: + // Checkstyle complains if there's no default block in switch + break; + } + } + + /** + * Checks if the class is annotated with annotation @ServiceClient. A class could have multiple annotations. + * + * @param classDefToken the CLASS_DEF AST node + * @return true if the class is annotated with @ServiceClient, false otherwise. + */ + private boolean hasServiceClientAnnotation(DetailAST classDefToken) { + // Always has MODIFIERS node + final DetailAST modifiersToken = classDefToken.findFirstToken(TokenTypes.MODIFIERS); + + for (DetailAST ast = modifiersToken.getFirstChild(); ast != null; ast = ast.getNextSibling()) { + if (ast.getType() != TokenTypes.ANNOTATION) { + continue; + } + // One class could have multiple annotations, return true if found one. + final DetailAST annotationIdent = ast.findFirstToken(TokenTypes.IDENT); + if (annotationIdent != null && SERVICE_CLIENT.equals(annotationIdent.getText())) { + isAsync = isAsyncServiceClient(ast); + return true; + } + } + // If no @ServiceClient annotated with this class, return false + return false; + } + + /** + * Checks for public or protected constructor for the service client class. + * Log error if the service client has public or protected constructor. + * + * @param ctorToken the CTOR_DEF AST node + */ + private void checkConstructor(DetailAST ctorToken) { + final DetailAST modifiersToken = ctorToken.findFirstToken(TokenTypes.MODIFIERS); + // find constructor's modifier accessibility, no public or protected constructor + final AccessModifier accessModifier = CheckUtil.getAccessModifierFromModifiersToken(modifiersToken); + if (accessModifier.equals(AccessModifier.PUBLIC) || accessModifier.equals(AccessModifier.PROTECTED)) { + log(modifiersToken, "@ServiceClient class should not have any public or protected constructor."); + } + } + + /** + * Checks for public static method named 'builder'. Should avoid to use method name, 'builder'. + * + * @param methodDefToken the METHOD_DEF AST node + */ + private void checkMethodName(DetailAST methodDefToken) { + final DetailAST methodNameToken = methodDefToken.findFirstToken(TokenTypes.IDENT); + if (!BUILDER.equals(methodNameToken.getText())) { + return; + } + + final DetailAST modifiersToken = methodDefToken.findFirstToken(TokenTypes.MODIFIERS); + // find method's modifier accessibility, should not have a public static method called 'builder' + final AccessModifier accessModifier = CheckUtil.getAccessModifierFromModifiersToken(modifiersToken); + if (accessModifier.equals(AccessModifier.PUBLIC) && modifiersToken.branchContains(TokenTypes.LITERAL_STATIC)) { + log(modifiersToken, "@ServiceClient class should not have a public static method named ''builder''."); + } + } + + /** + * Checks that the field variables in the @ServiceClient are final. ServiceClients should be immutable. + * + * @param objBlockToken the OBJBLOCK AST node + */ + private void checkClassField(DetailAST objBlockToken) { + for (DetailAST ast = objBlockToken.getFirstChild(); ast != null; ast = ast.getNextSibling()) { + if (TokenTypes.VARIABLE_DEF != ast.getType()) { + continue; + } + final DetailAST modifiersToken = ast.findFirstToken(TokenTypes.MODIFIERS); + // VARIABLE_DEF token will always MODIFIERS token. If there is no modifier at the variable, no child under + // MODIFIERS token. Also the previous sibling of OBJBLOCK will always be class name IDENT node. + if (!modifiersToken.branchContains(TokenTypes.FINAL)) { + log(modifiersToken, String.format("The variable field ''%s'' of class ''%s'' should be final. Classes annotated with @ServiceClient are supposed to be immutable.", + ast.findFirstToken(TokenTypes.IDENT).getText(), objBlockToken.getPreviousSibling().getText())); + } + } + } + + /** + * Checks for the class name of Service Client. It should be named AsyncClient or Client. + * + * @param classDefToken the CLASS_DEF AST node + */ + private void checkServiceClientNaming(DetailAST classDefToken) { + final String className = classDefToken.findFirstToken(TokenTypes.IDENT).getText(); + // Async service client + if (isAsync && !className.endsWith(ASYNC_CLIENT)) { + log(classDefToken, String.format("Async class ''%s'' must be named AsyncClient ", className)); + } + // Sync service client + if (!isAsync && !className.endsWith(CLIENT)) { + log(classDefToken, String.format("Sync class %s must be named Client.", className)); + } + } + + /** + * A function checks if the annotation node has a member key is {@code IS_ASYNC} with value equals to 'true'. + * If the value equals 'true', which indicates the @ServiceClient is an asynchronous client. + * If the member pair is missing. By default, it is a synchronous service client. + * + * @param annotationToken the ANNOTATION AST node + * @return true if the annotation has {@code IS_ASYNC} value 'true', otherwise, false. + */ + private boolean isAsyncServiceClient(DetailAST annotationToken) { + for (DetailAST ast = annotationToken.getFirstChild(); ast != null; ast = ast.getNextSibling()) { + if (ast.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + continue; + } + + // skip this annotation member value pair if no IDENT found, since we are looking for member, 'isAsync'. + final DetailAST identToken = ast.findFirstToken(TokenTypes.IDENT); + if (identToken == null) { + continue; + } + + // skip this annotation member value pair if the member is not 'isAsync'. + if (!IS_ASYNC.equals(identToken.getText())) { + continue; + } + + // skip this annotation member value pair if the member has no EXPR value + final DetailAST exprToken = ast.findFirstToken(TokenTypes.EXPR); + if (exprToken == null) { + continue; + } + + // true if isAsync = true, false otherwise. + return exprToken.branchContains(TokenTypes.LITERAL_TRUE); + } + // By default, if the IS_ASYNC doesn't exist, the service client is a synchronous client. + return false; + } +} diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index f8a5f76638da4..1f9752c52de54 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -6,13 +6,13 @@ - + + files="keyvault[/\\]microsoft-azure-.*[/\\].*[/\\](IKey|ISignatureTransform|KeyVaultClientBase|KeyVaultClientCustom)\.java"/> - + @@ -85,4 +85,8 @@ + + + + diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml index 5594540a232fe..0e37ecfac62cf 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle.xml @@ -274,9 +274,21 @@ page at http://checkstyle.sourceforge.net/config.html --> + 1) not return classes in the implementation package + 2) no class of implementation package as method's parameters --> + + + + + + + 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 8e6c2c8844554..f7e3bcb5eb317 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 @@ -61,7 +61,10 @@ - + + + + @@ -104,7 +107,10 @@ - + + + + @@ -238,7 +244,10 @@ - + + + + @@ -357,7 +366,10 @@ - + + + + @@ -422,6 +434,15 @@ + + + + + + + + + @@ -477,4 +498,14 @@ + + + + + + + + + + diff --git a/eng/jacoco-test-coverage/pom.xml b/eng/jacoco-test-coverage/pom.xml index 82ed0618208a7..b6567bd45d9e5 100644 --- a/eng/jacoco-test-coverage/pom.xml +++ b/eng/jacoco-test-coverage/pom.xml @@ -3,14 +3,14 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.azure azure-client-sdk-parent - 1.0.0 + 1.1.0 ../../pom.client.xml @@ -23,8 +23,11 @@ https://github.com/Azure/azure-sdk-for-java - 5.0.0-preview.1 + 1.0.0-preview.3 + 1.0.0-preview.1 + 1.0.0-preview.1 4.0.0-preview.1 + 5.0.0-preview.2 @@ -44,22 +47,27 @@ com.azure azure-core - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-core-amqp - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-core-management - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-data-appconfiguration - ${version} + ${azure-data-appconfiguration.version} + + + com.azure + azure-identity + ${azure-identity.version} com.azure @@ -76,22 +84,21 @@ azure-messaging-eventhubs ${azure-messaging-eventhubs.version} - - com.azure - tracing-opentelemetry - ${version} - - - com.azure - azure-identity - 1.0.0-preview.1 - + + + + + + + + - - - - - + + + + + diff --git a/eng/pipelines/mgmt.yml b/eng/pipelines/mgmt.yml new file mode 100644 index 0000000000000..c9c850dcc8202 --- /dev/null +++ b/eng/pipelines/mgmt.yml @@ -0,0 +1,38 @@ +trigger: + - master + +variables: + MavenGoals: 'clean,compile' + +jobs: + - job: 'Build' + + strategy: + matrix: + Java 8: + ArtifactName: 'packages' + JavaVersion: '1.8' + Java 7: + ArtifactName: 'packages' + JavaVersion: '1.7' + + pool: + vmImage: 'ubuntu-16.04' + + steps: + - task: ShellScript@2 + displayName: 'call mvn for each mgmt sdk individually' + inputs: + scriptPath: "$(System.DefaultWorkingDirectory)/eng/pipelines/scripts/mgmt_sdk_compiler.sh" + workingDirectory: "$(System.DefaultWorkingDirectory)" + failOnStandardError: true + args: "$(JavaVersion) $(MavenGoals)" + + - task: PublishTestResults@2 + condition: succeededOrFailed() + inputs: + mergeTestResults: true + testRunTitle: 'On Java $(JavaVersion)' + + + \ No newline at end of file diff --git a/eng/pipelines/scripts/mgmt_sdk_compiler.sh b/eng/pipelines/scripts/mgmt_sdk_compiler.sh new file mode 100644 index 0000000000000..af6ce2f2c2dd5 --- /dev/null +++ b/eng/pipelines/scripts/mgmt_sdk_compiler.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +#args expected +# $1. Java version : 1.7 or 1,8, defaults to "1.8" +# $2. Goals, defaults to "clean compile", value expected is a comma delemited string eg : "clean,compile" + +echo "#### CWD : " +pwd + +echo "#### versions of java available:" +ls /usr/lib/jvm + +echo "#### Original java home $JAVA_HOME" + +JAVA7HOME="/usr/lib/jvm/zulu-7-azure-amd64" +JAVA8HOME="/usr/lib/jvm/zulu-8-azure-amd64" + +JAVAHOME="$JAVA8HOME" + +MAVENGOALS="clean compile" + +if [ -n "$1" ] && [ "$1" == "1.7" ]; +then + JAVAHOME="$JAVA7HOME"; + echo "runing java 7 build"; +fi + + +if [ -n "$2" ]; +then + TEMP_VAL=$(echo "$2" | sed -r 's/,/ /g') + MAVENGOALS="$TEMP_VAL"; + echo "maven goals overriden to $MAVENGOALS" +fi + +export JAVA_HOME="$JAVAHOME" + +echo "#### Using java at : $JAVA_HOME" + +echo "#### Maven properties:" +mvn --version + +#TODO: +#for some reason the workingdirectory dos not seem to work... +#fix the following cd cmd once we figure out how to get it to work +#change to the root of the sources repo +cd ../../.. + +for i in `ls -d */*/v20* | grep -v "node_modules/*/*"`; +do + echo "######## building folder $i" + cd $i; + mvn --batch-mode -Dgpg.skip -Dmaven.wagon.http.pool=false -Dorg.slf4j.simpleLogger.defaultLogLevel=error -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warns $MAVENGOALS; + if [ $? != 0 ]; + then cd -; exit -1; + else cd -; + fi; +done diff --git a/eng/pipelines/templates/jobs/archetype-sdk-client.yml b/eng/pipelines/templates/jobs/archetype-sdk-client.yml index cd3aece496be9..6846affce6888 100644 --- a/eng/pipelines/templates/jobs/archetype-sdk-client.yml +++ b/eng/pipelines/templates/jobs/archetype-sdk-client.yml @@ -19,6 +19,11 @@ jobs: JavaVersion: '1.11' steps: + - script: | + echo "##vso[build.addbuildtag]Scheduled" + displayName: 'Tag scheduled builds' + condition: and(eq(variables['Build.SourceBranchName'],'master'),eq(variables['Build.Reason'],'Schedule')) + - task: Maven@3 displayName: 'Build and Package' inputs: @@ -68,7 +73,7 @@ jobs: displayName: 'Install reporting tools' inputs: mavenPomFile: pom.client.xml - options: '$(DefaultOptions) -Dinclude-non-shipping-modules -DskipTests -Dgpg.skip' + options: '$(DefaultOptions) -Djava-lts -Dinclude-non-shipping-modules -DskipTests -Dgpg.skip' mavenOptions: '$(LoggingOptions)' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' @@ -80,7 +85,7 @@ jobs: displayName: 'Generate Maven project site, including JavaDocs, SpotBugs, and CheckStyle reports' inputs: mavenPomFile: pom.client.xml - options: '$(DefaultOptions) -DskipTests -Dgpg.skip' + options: '$(DefaultOptions) -Djava-lts -DskipTests -Dgpg.skip' mavenOptions: '$(LoggingOptions)' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' @@ -212,4 +217,4 @@ jobs: condition: succeededOrFailed() inputs: mergeTestResults: true - testRunTitle: '$(OSName) on Java $(JavaVersion)' \ No newline at end of file + testRunTitle: '$(OSName) on Java $(JavaVersion)' diff --git a/eng/repo-docs/index.html b/eng/repo-docs/index.html new file mode 100644 index 0000000000000..3070e9acb4551 --- /dev/null +++ b/eng/repo-docs/index.html @@ -0,0 +1,517 @@ + + + + + + + + + Azure SDK For Java - Github.io Landing Page + + + + + + + + +
+
+
+ +
+

Azure Java SDK

+

Refer to the links below for reference documentation generated from the Azure SDK for Java source code.

+
+ +
+
    +
  • + Client Libraries +
  • + +
    +
  • + + JavaDocs +
  • +
    +
+
+ +
+
    +
  • + Data Libraries +
  • + +
    +
  • + + JavaDocs +
  • +
    +
+
+
+ +
+
+
+
+

Powered by Azure.

+
+
+
+
+ + + + \ No newline at end of file diff --git a/eng/spotbugs-aggregate-report/pom.xml b/eng/spotbugs-aggregate-report/pom.xml index 0e9be8f52c13d..df95e28e5936a 100644 --- a/eng/spotbugs-aggregate-report/pom.xml +++ b/eng/spotbugs-aggregate-report/pom.xml @@ -6,21 +6,27 @@ azure-client-sdk-parent com.azure - 1.0.0 + 1.1.0 ../../pom.client.xml 4.0.0 spotbugs-reporting 1.0.0 + 5.0.1 2.3.1 2.5.1 1.2.0 2.0.0 10.5.0 - 1.0.0-SNAPSHOT - 5.0.0-preview.1 + + + 1.0.0-preview.3 + 1.0.0-preview.1 + 1.0.0-preview.1 + 4.0.0-preview.1 + 5.0.0-preview.2 @@ -114,27 +120,22 @@ com.azure azure-core - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-core-amqp - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-core-management - 1.0.0-preview.1 - - - com.azure - azure-core-test - 1.0.0-preview.1 + ${azure-core.version} com.azure azure-core-test - 1.0.0-preview.1 + ${azure-core.version} com.azure @@ -146,7 +147,17 @@ azure-messaging-eventhubs ${azure-messaging-eventhubs.version} + + + com.google.code.findbugs + jsr305 + 3.0.2 + provided + + generate-sources none diff --git a/eventhubs/client/CHANGELOG.md b/eventhubs/client/CHANGELOG.md deleted file mode 100644 index 677dfc353e3e7..0000000000000 --- a/eventhubs/client/CHANGELOG.md +++ /dev/null @@ -1,4 +0,0 @@ -# Release History - -## 5.0.0-preview.1 (2019-07-01) -For release notes and more information please visit https://aka.ms/azure-sdk-preview1-java \ No newline at end of file diff --git a/eventhubs/client/azure-eventhubs/pom.xml b/eventhubs/client/azure-eventhubs/pom.xml deleted file mode 100644 index ecfbbabed7907..0000000000000 --- a/eventhubs/client/azure-eventhubs/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - 4.0.0 - - com.azure - azure-messaging-eventhubs-parent - 5.0.0-preview.1 - ../pom.xml - - - com.azure - azure-messaging-eventhubs - 5.0.0-preview.1 - - Microsoft Azure client library for Event Hubs - Libraries built on Microsoft Azure Event Hubs - https://github.com/Azure/azure-sdk-for-java - - - - azure-java-build-docs - ${site.url}/site/${project.artifactId} - - - - - scm:git:https://github.com/Azure/azure-sdk-for-java - - - diff --git a/eventhubs/data-plane/pom.xml b/eventhubs/data-plane/pom.xml index 3c1235e0732c8..72c5ab14aa8b1 100644 --- a/eventhubs/data-plane/pom.xml +++ b/eventhubs/data-plane/pom.xml @@ -7,7 +7,7 @@ com.azure azure-data-sdk-parent - 1.0.0 + 1.1.0 ../../pom.data.xml diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/pom.xml b/hanaonazure/resource-manager/v2017_11_03_preview/pom.xml index 9d4bf5705ea10..d83c350d750c1 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/pom.xml +++ b/hanaonazure/resource-manager/v2017_11_03_preview/pom.xml @@ -15,7 +15,7 @@ ../../../pom.management.xml azure-mgmt-hanaonazure - 1.0.0-beta-2 + 1.0.0-beta-3 jar Microsoft Azure SDK for HanaOnAzure Management This package contains Microsoft HanaOnAzure Management SDK. @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/HanaInstances.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/HanaInstances.java index f6d0fbed04ee4..dc6a6c7cd639e 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/HanaInstances.java +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/HanaInstances.java @@ -33,6 +33,26 @@ public interface HanaInstances extends SupportsCreating, Resource, GroupableResourceCore, HasResourceGroup, Refreshable, Updatable, HasManager { + /** + * @return the hanaDbName value. + */ + String hanaDbName(); + + /** + * @return the hanaDbPassword value. + */ + String hanaDbPassword(); + + /** + * @return the hanaDbSqlPort value. + */ + Integer hanaDbSqlPort(); + + /** + * @return the hanaDbUsername value. + */ + String hanaDbUsername(); + + /** + * @return the hanaHostname value. + */ + String hanaHostname(); + + /** + * @return the hanaSubnet value. + */ + String hanaSubnet(); + + /** + * @return the provisioningState value. + */ + HanaProvisioningStatesEnum provisioningState(); + + /** + * The entirety of the SapMonitor definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithGroup, DefinitionStages.WithCreate { + } + + /** + * Grouping of SapMonitor definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a SapMonitor definition. + */ + interface Blank extends GroupableResourceCore.DefinitionWithRegion { + } + + /** + * The stage of the SapMonitor definition allowing to specify the resource group. + */ + interface WithGroup extends GroupableResourceCore.DefinitionStages.WithGroup { + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaDbName. + */ + interface WithHanaDbName { + /** + * Specifies hanaDbName. + * @param hanaDbName Database name of the HANA instance + * @return the next definition stage + */ + WithCreate withHanaDbName(String hanaDbName); + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaDbPassword. + */ + interface WithHanaDbPassword { + /** + * Specifies hanaDbPassword. + * @param hanaDbPassword Database password of the HANA instance + * @return the next definition stage + */ + WithCreate withHanaDbPassword(String hanaDbPassword); + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaDbSqlPort. + */ + interface WithHanaDbSqlPort { + /** + * Specifies hanaDbSqlPort. + * @param hanaDbSqlPort Database port of the HANA instance + * @return the next definition stage + */ + WithCreate withHanaDbSqlPort(Integer hanaDbSqlPort); + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaDbUsername. + */ + interface WithHanaDbUsername { + /** + * Specifies hanaDbUsername. + * @param hanaDbUsername Database username of the HANA instance + * @return the next definition stage + */ + WithCreate withHanaDbUsername(String hanaDbUsername); + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaHostname. + */ + interface WithHanaHostname { + /** + * Specifies hanaHostname. + * @param hanaHostname Hostname of the HANA instance + * @return the next definition stage + */ + WithCreate withHanaHostname(String hanaHostname); + } + + /** + * The stage of the sapmonitor definition allowing to specify HanaSubnet. + */ + interface WithHanaSubnet { + /** + * Specifies hanaSubnet. + * @param hanaSubnet Specifies the SAP monitor unique ID + * @return the next definition stage + */ + WithCreate withHanaSubnet(String hanaSubnet); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable, Resource.DefinitionWithTags, DefinitionStages.WithHanaDbName, DefinitionStages.WithHanaDbPassword, DefinitionStages.WithHanaDbSqlPort, DefinitionStages.WithHanaDbUsername, DefinitionStages.WithHanaHostname, DefinitionStages.WithHanaSubnet { + } + } + /** + * The template for a SapMonitor update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, Resource.UpdateWithTags, UpdateStages.WithHanaDbName, UpdateStages.WithHanaDbPassword, UpdateStages.WithHanaDbSqlPort, UpdateStages.WithHanaDbUsername, UpdateStages.WithHanaHostname, UpdateStages.WithHanaSubnet { + } + + /** + * Grouping of SapMonitor update stages. + */ + interface UpdateStages { + /** + * The stage of the sapmonitor update allowing to specify HanaDbName. + */ + interface WithHanaDbName { + /** + * Specifies hanaDbName. + * @param hanaDbName Database name of the HANA instance + * @return the next update stage + */ + Update withHanaDbName(String hanaDbName); + } + + /** + * The stage of the sapmonitor update allowing to specify HanaDbPassword. + */ + interface WithHanaDbPassword { + /** + * Specifies hanaDbPassword. + * @param hanaDbPassword Database password of the HANA instance + * @return the next update stage + */ + Update withHanaDbPassword(String hanaDbPassword); + } + + /** + * The stage of the sapmonitor update allowing to specify HanaDbSqlPort. + */ + interface WithHanaDbSqlPort { + /** + * Specifies hanaDbSqlPort. + * @param hanaDbSqlPort Database port of the HANA instance + * @return the next update stage + */ + Update withHanaDbSqlPort(Integer hanaDbSqlPort); + } + + /** + * The stage of the sapmonitor update allowing to specify HanaDbUsername. + */ + interface WithHanaDbUsername { + /** + * Specifies hanaDbUsername. + * @param hanaDbUsername Database username of the HANA instance + * @return the next update stage + */ + Update withHanaDbUsername(String hanaDbUsername); + } + + /** + * The stage of the sapmonitor update allowing to specify HanaHostname. + */ + interface WithHanaHostname { + /** + * Specifies hanaHostname. + * @param hanaHostname Hostname of the HANA instance + * @return the next update stage + */ + Update withHanaHostname(String hanaHostname); + } + + /** + * The stage of the sapmonitor update allowing to specify HanaSubnet. + */ + interface WithHanaSubnet { + /** + * Specifies hanaSubnet. + * @param hanaSubnet Specifies the SAP monitor unique ID + * @return the next update stage + */ + Update withHanaSubnet(String hanaSubnet); + } + + } +} diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/SapMonitors.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/SapMonitors.java new file mode 100644 index 0000000000000..d01ca506b8992 --- /dev/null +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/SapMonitors.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.hanaonazure.v2017_11_03_preview; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import com.microsoft.azure.arm.resources.collection.SupportsDeletingByResourceGroup; +import com.microsoft.azure.arm.resources.collection.SupportsBatchDeletion; +import com.microsoft.azure.arm.resources.collection.SupportsGettingByResourceGroup; +import rx.Observable; +import com.microsoft.azure.arm.collection.SupportsListing; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.implementation.SapMonitorsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing SapMonitors. + */ +public interface SapMonitors extends SupportsCreating, SupportsDeletingByResourceGroup, SupportsBatchDeletion, SupportsGettingByResourceGroup, SupportsListing, HasInner { +} diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesImpl.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesImpl.java index 222be84cb98fa..22f815a1c8541 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesImpl.java +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesImpl.java @@ -132,6 +132,18 @@ public Completable restartAsync(String resourceGroupName, String hanaInstanceNam return client.restartAsync(resourceGroupName, hanaInstanceName).toCompletable(); } + @Override + public Completable startAsync(String resourceGroupName, String hanaInstanceName) { + HanaInstancesInner client = this.inner(); + return client.startAsync(resourceGroupName, hanaInstanceName).toCompletable(); + } + + @Override + public Completable shutdownAsync(String resourceGroupName, String hanaInstanceName) { + HanaInstancesInner client = this.inner(); + return client.shutdownAsync(resourceGroupName, hanaInstanceName).toCompletable(); + } + @Override public Completable enableMonitoringAsync(String resourceGroupName, String hanaInstanceName, MonitoringDetails monitoringParameter) { HanaInstancesInner client = this.inner(); diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesInner.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesInner.java index 9d41257ad424f..f4af67cccdad0 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesInner.java +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaInstancesInner.java @@ -110,6 +110,22 @@ interface HanaInstancesService { @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/restart") Observable> beginRestart(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances start" }) + @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/start") + Observable> start(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances beginStart" }) + @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/start") + Observable> beginStart(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances shutdown" }) + @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/shutdown") + Observable> shutdown(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances beginShutdown" }) + @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/shutdown") + Observable> beginShutdown(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances enableMonitoring" }) @POST("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/hanaInstances/{hanaInstanceName}/monitoring") Observable> enableMonitoring(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("hanaInstanceName") String hanaInstanceName, @Query("api-version") String apiVersion, @Body MonitoringDetails monitoringParameter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); @@ -982,7 +998,7 @@ private ServiceResponse updateDelegate(Response * @param resourceGroupName Name of the resource group. * @param hanaInstanceName Name of the SAP HANA on Azure instance. * @throws IllegalArgumentException thrown if parameters fail the validation - * @throws CloudException thrown if the request is rejected by server + * @throws ErrorResponseException thrown if the request is rejected by server * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent */ public void restart(String resourceGroupName, String hanaInstanceName) { @@ -1050,7 +1066,7 @@ public Observable> restartWithServiceResponseAsync(String * @param resourceGroupName Name of the resource group. * @param hanaInstanceName Name of the SAP HANA on Azure instance. * @throws IllegalArgumentException thrown if parameters fail the validation - * @throws CloudException thrown if the request is rejected by server + * @throws ErrorResponseException thrown if the request is rejected by server * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent */ public void beginRestart(String resourceGroupName, String hanaInstanceName) { @@ -1122,11 +1138,319 @@ public Observable> call(Response response) { }); } - private ServiceResponse beginRestartDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { - return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + private ServiceResponse beginRestartDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) .register(200, new TypeToken() { }.getType()) .register(202, new TypeToken() { }.getType()) - .registerError(CloudException.class) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void start(String resourceGroupName, String hanaInstanceName) { + startWithServiceResponseAsync(resourceGroupName, hanaInstanceName).toBlocking().last().body(); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture startAsync(String resourceGroupName, String hanaInstanceName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(startWithServiceResponseAsync(resourceGroupName, hanaInstanceName), serviceCallback); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable startAsync(String resourceGroupName, String hanaInstanceName) { + return startWithServiceResponseAsync(resourceGroupName, hanaInstanceName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> startWithServiceResponseAsync(String resourceGroupName, String hanaInstanceName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (hanaInstanceName == null) { + throw new IllegalArgumentException("Parameter hanaInstanceName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.start(this.client.subscriptionId(), resourceGroupName, hanaInstanceName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginStart(String resourceGroupName, String hanaInstanceName) { + beginStartWithServiceResponseAsync(resourceGroupName, hanaInstanceName).toBlocking().single().body(); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginStartAsync(String resourceGroupName, String hanaInstanceName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginStartWithServiceResponseAsync(resourceGroupName, hanaInstanceName), serviceCallback); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginStartAsync(String resourceGroupName, String hanaInstanceName) { + return beginStartWithServiceResponseAsync(resourceGroupName, hanaInstanceName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * The operation to start a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginStartWithServiceResponseAsync(String resourceGroupName, String hanaInstanceName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (hanaInstanceName == null) { + throw new IllegalArgumentException("Parameter hanaInstanceName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginStart(this.client.subscriptionId(), resourceGroupName, hanaInstanceName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginStartDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginStartDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void shutdown(String resourceGroupName, String hanaInstanceName) { + shutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName).toBlocking().last().body(); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture shutdownAsync(String resourceGroupName, String hanaInstanceName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(shutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName), serviceCallback); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable shutdownAsync(String resourceGroupName, String hanaInstanceName) { + return shutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> shutdownWithServiceResponseAsync(String resourceGroupName, String hanaInstanceName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (hanaInstanceName == null) { + throw new IllegalArgumentException("Parameter hanaInstanceName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.shutdown(this.client.subscriptionId(), resourceGroupName, hanaInstanceName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginShutdown(String resourceGroupName, String hanaInstanceName) { + beginShutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName).toBlocking().single().body(); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginShutdownAsync(String resourceGroupName, String hanaInstanceName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginShutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName), serviceCallback); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginShutdownAsync(String resourceGroupName, String hanaInstanceName) { + return beginShutdownWithServiceResponseAsync(resourceGroupName, hanaInstanceName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * The operation to shutdown a SAP HANA instance. + * + * @param resourceGroupName Name of the resource group. + * @param hanaInstanceName Name of the SAP HANA on Azure instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginShutdownWithServiceResponseAsync(String resourceGroupName, String hanaInstanceName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (hanaInstanceName == null) { + throw new IllegalArgumentException("Parameter hanaInstanceName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginShutdown(this.client.subscriptionId(), resourceGroupName, hanaInstanceName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginShutdownDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginShutdownDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) .build(response); } diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaManagementClientImpl.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaManagementClientImpl.java index cca459ef451c3..9bd75711270f7 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaManagementClientImpl.java +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaManagementClientImpl.java @@ -158,6 +158,19 @@ public HanaInstancesInner hanaInstances() { return this.hanaInstances; } + /** + * The SapMonitorsInner object to access its operations. + */ + private SapMonitorsInner sapMonitors; + + /** + * Gets the SapMonitorsInner object to access its operations. + * @return the SapMonitorsInner object. + */ + public SapMonitorsInner sapMonitors() { + return this.sapMonitors; + } + /** * Initializes an instance of HanaManagementClient client. * @@ -195,6 +208,7 @@ protected void initialize() { this.generateClientRequestId = true; this.operations = new OperationsInner(restClient().retrofit(), this); this.hanaInstances = new HanaInstancesInner(restClient().retrofit(), this); + this.sapMonitors = new SapMonitorsInner(restClient().retrofit(), this); this.azureClient = new AzureClient(this); } diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaOnAzureManager.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaOnAzureManager.java index f5492b95bf7e2..1b76c2d2b35f4 100644 --- a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaOnAzureManager.java +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/HanaOnAzureManager.java @@ -18,6 +18,7 @@ import com.microsoft.rest.RestClient; import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.Operations; import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaInstances; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors; import com.microsoft.azure.arm.resources.implementation.AzureConfigurableCoreImpl; import com.microsoft.azure.arm.resources.implementation.ManagerCore; @@ -27,6 +28,7 @@ public final class HanaOnAzureManager extends ManagerCore { private Operations operations; private HanaInstances hanaInstances; + private SapMonitors sapMonitors; /** * Get a Configurable instance that can be used to create HanaOnAzureManager with optional configuration. * @@ -94,6 +96,16 @@ public HanaInstances hanaInstances() { return this.hanaInstances; } + /** + * @return Entry point to manage SapMonitors. + */ + public SapMonitors sapMonitors() { + if (this.sapMonitors == null) { + this.sapMonitors = new SapMonitorsImpl(this); + } + return this.sapMonitors; + } + /** * The implementation for Configurable interface. */ diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorImpl.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorImpl.java new file mode 100644 index 0000000000000..9f62f46ebc730 --- /dev/null +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorImpl.java @@ -0,0 +1,118 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.implementation; + +import com.microsoft.azure.arm.resources.models.implementation.GroupableResourceCoreImpl; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitor; +import rx.Observable; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaProvisioningStatesEnum; + +class SapMonitorImpl extends GroupableResourceCoreImpl implements SapMonitor, SapMonitor.Definition, SapMonitor.Update { + SapMonitorImpl(String name, SapMonitorInner inner, HanaOnAzureManager manager) { + super(name, inner, manager); + } + + @Override + public Observable createResourceAsync() { + SapMonitorsInner client = this.manager().inner().sapMonitors(); + return client.createAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + SapMonitorsInner client = this.manager().inner().sapMonitors(); + return client.createAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + SapMonitorsInner client = this.manager().inner().sapMonitors(); + return client.getByResourceGroupAsync(this.resourceGroupName(), this.name()); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + + @Override + public String hanaDbName() { + return this.inner().hanaDbName(); + } + + @Override + public String hanaDbPassword() { + return this.inner().hanaDbPassword(); + } + + @Override + public Integer hanaDbSqlPort() { + return this.inner().hanaDbSqlPort(); + } + + @Override + public String hanaDbUsername() { + return this.inner().hanaDbUsername(); + } + + @Override + public String hanaHostname() { + return this.inner().hanaHostname(); + } + + @Override + public String hanaSubnet() { + return this.inner().hanaSubnet(); + } + + @Override + public HanaProvisioningStatesEnum provisioningState() { + return this.inner().provisioningState(); + } + + @Override + public SapMonitorImpl withHanaDbName(String hanaDbName) { + this.inner().withHanaDbName(hanaDbName); + return this; + } + + @Override + public SapMonitorImpl withHanaDbPassword(String hanaDbPassword) { + this.inner().withHanaDbPassword(hanaDbPassword); + return this; + } + + @Override + public SapMonitorImpl withHanaDbSqlPort(Integer hanaDbSqlPort) { + this.inner().withHanaDbSqlPort(hanaDbSqlPort); + return this; + } + + @Override + public SapMonitorImpl withHanaDbUsername(String hanaDbUsername) { + this.inner().withHanaDbUsername(hanaDbUsername); + return this; + } + + @Override + public SapMonitorImpl withHanaHostname(String hanaHostname) { + this.inner().withHanaHostname(hanaHostname); + return this; + } + + @Override + public SapMonitorImpl withHanaSubnet(String hanaSubnet) { + this.inner().withHanaSubnet(hanaSubnet); + return this; + } + +} diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorInner.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorInner.java new file mode 100644 index 0000000000000..bc0d08bbd2215 --- /dev/null +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorInner.java @@ -0,0 +1,196 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.implementation; + +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.HanaProvisioningStatesEnum; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.rest.serializer.JsonFlatten; +import com.microsoft.rest.SkipParentValidation; +import com.microsoft.azure.Resource; + +/** + * SAP monitor info on Azure (ARM properties and SAP monitor properties). + */ +@JsonFlatten +@SkipParentValidation +public class SapMonitorInner extends Resource { + /** + * Specifies the SAP monitor unique ID. + */ + @JsonProperty(value = "properties.hanaSubnet") + private String hanaSubnet; + + /** + * Hostname of the HANA instance. + */ + @JsonProperty(value = "properties.hanaHostname") + private String hanaHostname; + + /** + * Database name of the HANA instance. + */ + @JsonProperty(value = "properties.hanaDbName") + private String hanaDbName; + + /** + * Database port of the HANA instance. + */ + @JsonProperty(value = "properties.hanaDbSqlPort") + private Integer hanaDbSqlPort; + + /** + * Database username of the HANA instance. + */ + @JsonProperty(value = "properties.hanaDbUsername") + private String hanaDbUsername; + + /** + * Database password of the HANA instance. + */ + @JsonProperty(value = "properties.hanaDbPassword") + private String hanaDbPassword; + + /** + * State of provisioning of the HanaInstance. Possible values include: + * 'Accepted', 'Creating', 'Updating', 'Failed', 'Succeeded', 'Deleting', + * 'Migrating'. + */ + @JsonProperty(value = "properties.provisioningState", access = JsonProperty.Access.WRITE_ONLY) + private HanaProvisioningStatesEnum provisioningState; + + /** + * Get specifies the SAP monitor unique ID. + * + * @return the hanaSubnet value + */ + public String hanaSubnet() { + return this.hanaSubnet; + } + + /** + * Set specifies the SAP monitor unique ID. + * + * @param hanaSubnet the hanaSubnet value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaSubnet(String hanaSubnet) { + this.hanaSubnet = hanaSubnet; + return this; + } + + /** + * Get hostname of the HANA instance. + * + * @return the hanaHostname value + */ + public String hanaHostname() { + return this.hanaHostname; + } + + /** + * Set hostname of the HANA instance. + * + * @param hanaHostname the hanaHostname value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaHostname(String hanaHostname) { + this.hanaHostname = hanaHostname; + return this; + } + + /** + * Get database name of the HANA instance. + * + * @return the hanaDbName value + */ + public String hanaDbName() { + return this.hanaDbName; + } + + /** + * Set database name of the HANA instance. + * + * @param hanaDbName the hanaDbName value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaDbName(String hanaDbName) { + this.hanaDbName = hanaDbName; + return this; + } + + /** + * Get database port of the HANA instance. + * + * @return the hanaDbSqlPort value + */ + public Integer hanaDbSqlPort() { + return this.hanaDbSqlPort; + } + + /** + * Set database port of the HANA instance. + * + * @param hanaDbSqlPort the hanaDbSqlPort value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaDbSqlPort(Integer hanaDbSqlPort) { + this.hanaDbSqlPort = hanaDbSqlPort; + return this; + } + + /** + * Get database username of the HANA instance. + * + * @return the hanaDbUsername value + */ + public String hanaDbUsername() { + return this.hanaDbUsername; + } + + /** + * Set database username of the HANA instance. + * + * @param hanaDbUsername the hanaDbUsername value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaDbUsername(String hanaDbUsername) { + this.hanaDbUsername = hanaDbUsername; + return this; + } + + /** + * Get database password of the HANA instance. + * + * @return the hanaDbPassword value + */ + public String hanaDbPassword() { + return this.hanaDbPassword; + } + + /** + * Set database password of the HANA instance. + * + * @param hanaDbPassword the hanaDbPassword value to set + * @return the SapMonitorInner object itself. + */ + public SapMonitorInner withHanaDbPassword(String hanaDbPassword) { + this.hanaDbPassword = hanaDbPassword; + return this; + } + + /** + * Get state of provisioning of the HanaInstance. Possible values include: 'Accepted', 'Creating', 'Updating', 'Failed', 'Succeeded', 'Deleting', 'Migrating'. + * + * @return the provisioningState value + */ + public HanaProvisioningStatesEnum provisioningState() { + return this.provisioningState; + } + +} diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsImpl.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsImpl.java new file mode 100644 index 0000000000000..5d2e60ec7e281 --- /dev/null +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsImpl.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * def + */ + +package com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.implementation; + +import com.microsoft.azure.arm.resources.collection.implementation.GroupableResourcesCoreImpl; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitor; +import rx.Observable; +import rx.Completable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import com.microsoft.azure.arm.resources.ResourceUtilsCore; +import com.microsoft.azure.arm.utils.RXMapper; +import rx.functions.Func1; +import com.microsoft.azure.PagedList; +import com.microsoft.azure.Page; + +class SapMonitorsImpl extends GroupableResourcesCoreImpl implements SapMonitors { + protected SapMonitorsImpl(HanaOnAzureManager manager) { + super(manager.inner().sapMonitors(), manager); + } + + @Override + protected Observable getInnerAsync(String resourceGroupName, String name) { + SapMonitorsInner client = this.inner(); + return client.getByResourceGroupAsync(resourceGroupName, name); + } + + @Override + protected Completable deleteInnerAsync(String resourceGroupName, String name) { + SapMonitorsInner client = this.inner(); + return client.deleteAsync(resourceGroupName, name).toCompletable(); + } + + @Override + public Observable deleteByIdsAsync(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Observable.empty(); + } + Collection> observables = new ArrayList<>(); + for (String id : ids) { + final String resourceGroupName = ResourceUtilsCore.groupFromResourceId(id); + final String name = ResourceUtilsCore.nameFromResourceId(id); + Observable o = RXMapper.map(this.inner().deleteAsync(resourceGroupName, name), id); + observables.add(o); + } + return Observable.mergeDelayError(observables); + } + + @Override + public Observable deleteByIdsAsync(String...ids) { + return this.deleteByIdsAsync(new ArrayList(Arrays.asList(ids))); + } + + @Override + public void deleteByIds(Collection ids) { + if (ids != null && !ids.isEmpty()) { + this.deleteByIdsAsync(ids).toBlocking().last(); + } + } + + @Override + public void deleteByIds(String...ids) { + this.deleteByIds(new ArrayList(Arrays.asList(ids))); + } + + @Override + public PagedList list() { + SapMonitorsInner client = this.inner(); + return this.wrapList(client.list()); + } + + @Override + public Observable listAsync() { + SapMonitorsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public SapMonitor call(SapMonitorInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public SapMonitorImpl define(String name) { + return wrapModel(name); + } + + @Override + protected SapMonitorImpl wrapModel(SapMonitorInner inner) { + return new SapMonitorImpl(inner.name(), inner, manager()); + } + + @Override + protected SapMonitorImpl wrapModel(String name) { + return new SapMonitorImpl(name, new SapMonitorInner(), this.manager()); + } + +} diff --git a/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsInner.java b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsInner.java new file mode 100644 index 0000000000000..061112bdc85c5 --- /dev/null +++ b/hanaonazure/resource-manager/v2017_11_03_preview/src/main/java/com/microsoft/azure/management/hanaonazure/v2017_11_03_preview/implementation/SapMonitorsInner.java @@ -0,0 +1,947 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsGet; +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.ErrorResponseException; +import com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.Tags; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in SapMonitors. + */ +public class SapMonitorsInner implements InnerSupportsGet, InnerSupportsDelete { + /** The Retrofit service to perform REST calls. */ + private SapMonitorsService service; + /** The service client containing this operation class. */ + private HanaManagementClientImpl client; + + /** + * Initializes an instance of SapMonitorsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public SapMonitorsInner(Retrofit retrofit, HanaManagementClientImpl client) { + this.service = retrofit.create(SapMonitorsService.class); + this.client = client; + } + + /** + * The interface defining all the services for SapMonitors to be + * used by Retrofit to perform actually REST calls. + */ + interface SapMonitorsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors list" }) + @GET("subscriptions/{subscriptionId}/providers/Microsoft.HanaOnAzure/sapMonitors") + Observable> list(@Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors getByResourceGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}") + Observable> getByResourceGroup(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors create" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}") + Observable> create(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Body SapMonitorInner sapMonitorParameter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors beginCreate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}") + Observable> beginCreate(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Body SapMonitorInner sapMonitorParameter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors delete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors beginDelete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors update" }) + @PATCH("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.HanaOnAzure/sapMonitors/{sapMonitorName}") + Observable> update(@Path("subscriptionId") String subscriptionId, @Path("resourceGroupName") String resourceGroupName, @Path("sapMonitorName") String sapMonitorName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body Tags tagsParameter, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.hanaonazure.v2017_11_03_preview.SapMonitors listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SapMonitorInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SapMonitorInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SapMonitorInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SapMonitorInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., ErrorResponseException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * Gets properties of a SAP monitor. + * Gets properties of a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SapMonitorInner object if successful. + */ + public SapMonitorInner getByResourceGroup(String resourceGroupName, String sapMonitorName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sapMonitorName).toBlocking().single().body(); + } + + /** + * Gets properties of a SAP monitor. + * Gets properties of a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getByResourceGroupAsync(String resourceGroupName, String sapMonitorName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getByResourceGroupWithServiceResponseAsync(resourceGroupName, sapMonitorName), serviceCallback); + } + + /** + * Gets properties of a SAP monitor. + * Gets properties of a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable getByResourceGroupAsync(String resourceGroupName, String sapMonitorName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sapMonitorName).map(new Func1, SapMonitorInner>() { + @Override + public SapMonitorInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets properties of a SAP monitor. + * Gets properties of a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable> getByResourceGroupWithServiceResponseAsync(String resourceGroupName, String sapMonitorName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.getByResourceGroup(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getByResourceGroupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getByResourceGroupDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SapMonitorInner object if successful. + */ + public SapMonitorInner create(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + return createWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter).toBlocking().last().body(); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter), serviceCallback); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + return createWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter).map(new Func1, SapMonitorInner>() { + @Override + public SapMonitorInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (sapMonitorParameter == null) { + throw new IllegalArgumentException("Parameter sapMonitorParameter is required and cannot be null."); + } + Validator.validate(sapMonitorParameter); + Observable> observable = service.create(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), sapMonitorParameter, this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SapMonitorInner object if successful. + */ + public SapMonitorInner beginCreate(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + return beginCreateWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter).toBlocking().single().body(); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter), serviceCallback); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable beginCreateAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + return beginCreateWithServiceResponseAsync(resourceGroupName, sapMonitorName, sapMonitorParameter).map(new Func1, SapMonitorInner>() { + @Override + public SapMonitorInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates a SAP monitor. + * Creates a SAP monitor for the specified subscription, resource group, and resource name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param sapMonitorParameter Request body representing a SAP Monitor + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String resourceGroupName, String sapMonitorName, SapMonitorInner sapMonitorParameter) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (sapMonitorParameter == null) { + throw new IllegalArgumentException("Parameter sapMonitorParameter is required and cannot be null."); + } + Validator.validate(sapMonitorParameter); + return service.beginCreate(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), sapMonitorParameter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String resourceGroupName, String sapMonitorName) { + deleteWithServiceResponseAsync(resourceGroupName, sapMonitorName).toBlocking().last().body(); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String resourceGroupName, String sapMonitorName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(resourceGroupName, sapMonitorName), serviceCallback); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String resourceGroupName, String sapMonitorName) { + return deleteWithServiceResponseAsync(resourceGroupName, sapMonitorName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String resourceGroupName, String sapMonitorName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String resourceGroupName, String sapMonitorName) { + beginDeleteWithServiceResponseAsync(resourceGroupName, sapMonitorName).toBlocking().single().body(); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String resourceGroupName, String sapMonitorName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(resourceGroupName, sapMonitorName), serviceCallback); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String resourceGroupName, String sapMonitorName) { + return beginDeleteWithServiceResponseAsync(resourceGroupName, sapMonitorName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SAP monitor. + * Deletes a SAP monitor with the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String resourceGroupName, String sapMonitorName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SapMonitorInner object if successful. + */ + public SapMonitorInner update(String resourceGroupName, String sapMonitorName) { + return updateWithServiceResponseAsync(resourceGroupName, sapMonitorName).toBlocking().single().body(); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sapMonitorName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sapMonitorName), serviceCallback); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable updateAsync(String resourceGroupName, String sapMonitorName) { + return updateWithServiceResponseAsync(resourceGroupName, sapMonitorName).map(new Func1, SapMonitorInner>() { + @Override + public SapMonitorInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sapMonitorName) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final Map tags = null; + Tags tagsParameter = new Tags(); + tagsParameter.withTags(null); + return service.update(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), this.client.acceptLanguage(), tagsParameter, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = updateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param tags Tags field of the HANA instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SapMonitorInner object if successful. + */ + public SapMonitorInner update(String resourceGroupName, String sapMonitorName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sapMonitorName, tags).toBlocking().single().body(); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param tags Tags field of the HANA instance. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sapMonitorName, Map tags, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sapMonitorName, tags), serviceCallback); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param tags Tags field of the HANA instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable updateAsync(String resourceGroupName, String sapMonitorName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sapMonitorName, tags).map(new Func1, SapMonitorInner>() { + @Override + public SapMonitorInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Patches the Tags field of a SAP monitor. + * Patches the Tags field of a SAP monitor for the specified subscription, resource group, and monitor name. + * + * @param resourceGroupName Name of the resource group. + * @param sapMonitorName Name of the SAP monitor resource. + * @param tags Tags field of the HANA instance. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SapMonitorInner object + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sapMonitorName, Map tags) { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sapMonitorName == null) { + throw new IllegalArgumentException("Parameter sapMonitorName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(tags); + Tags tagsParameter = new Tags(); + tagsParameter.withTags(tags); + return service.update(this.client.subscriptionId(), resourceGroupName, sapMonitorName, this.client.apiVersion(), this.client.acceptLanguage(), tagsParameter, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = updateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse updateDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws ErrorResponseException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SapMonitorInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SapMonitorInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SapMonitorInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets a list of SAP monitors in the specified subscription. + * Gets a list of SAP monitors in the specified subscription. The operations returns various properties of each SAP monitor. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SapMonitorInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws ErrorResponseException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., ErrorResponseException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } + +} diff --git a/keyvault/client/keys/CHANGELOG.md b/keyvault/client/keys/CHANGELOG.md deleted file mode 100644 index 63e0314b74012..0000000000000 --- a/keyvault/client/keys/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Release History - -## 4.0.0-preview.1 (2019-06-28) -For release notes and more information please visit -https://aka.ms/azure-sdk-preview1-java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java b/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java deleted file mode 100644 index 03d31d131f9b5..0000000000000 --- a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.security.keyvault.keys; - -import com.azure.core.credentials.TokenCredential; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.policy.HttpLogDetailLevel; -import com.azure.core.http.policy.HttpLoggingPolicy; -import com.azure.core.http.policy.HttpPipelinePolicy; -import com.azure.core.implementation.annotation.ServiceClientBuilder; - - -/** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link KeyClient key client}, - * calling {@link KeyClientBuilder#build() build} constructs an instance of the client. - * - *

The minimal configuration options required by {@link KeyClientBuilder keyClientBuilder} to build {@link KeyClient} - * are {@link String endpoint} and {@link TokenCredential credential}.

- *
- * KeyClient.builder()
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .credential(new DefaultAzureCredential())
- *   .build();
- * 
- * - *

The {@link HttpLogDetailLevel log detail level}, multiple custom {@link HttpLoggingPolicy policies} and custom - * {@link HttpClient http client} can be optionally configured in the {@link KeyClientBuilder}.

- *
- * KeyClient.builder()
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .credential(new DefaultAzureCredential())
- *   .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
- *   .addPolicy(customPolicyOne)
- *   .addPolicy(customPolicyTwo)
- *   .httpClient(client)
- *   .build();
- * 
- * - *

Alternatively, custom {@link HttpPipeline http pipeline} with custom {@link HttpPipelinePolicy} policies and {@link String endpoint} - * can be specified. It provides finer control over the construction of {@link KeyClient client}

- *
- * KeyClient.builder()
- *   .pipeline(new HttpPipeline(customPoliciesList))
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .build()
- * 
- * - * @see KeyClient - */ -@ServiceClientBuilder(serviceClients = KeyClient.class) -public final class KeyClientBuilder { - private KeyAsyncClientBuilder builder; - - KeyClientBuilder() { - this.builder = KeyAsyncClient.builder(); - } - - /** - * Creates a {@link KeyClient} based on options set in the builder. - * Every time {@code build()} is called, a new instance of {@link KeyClient} is created. - * - *

If {@link KeyClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link KeyClientBuilder#endpoint(String) serviceEndpoint} are used to create the - * {@link KeyClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, - * then {@link KeyClientBuilder#credential(TokenCredential) key vault credential} and - * {@link KeyClientBuilder#endpoint(String) key vault endpoint} are required to build the {@link KeyClient client}.

- * - * @return A KeyClient with the options set from the builder. - * @throws IllegalStateException If {@link KeyClientBuilder#credential(TokenCredential)} or - * {@link KeyClientBuilder#endpoint(String)} have not been set. - */ - public KeyClient build() { - return new KeyClient(builder.build()); - } - - /** - * Sets the vault endpoint url to send HTTP requests to. - * - * @param endpoint The vault endpoint url is used as destination on Azure to send requests to. - * @return the updated ServiceClientBuilder object. - * @throws IllegalArgumentException if {@code endpoint} is null or it cannot be parsed into a valid URL. - */ - public KeyClientBuilder endpoint(String endpoint) { - builder.endpoint(endpoint); - return this; - } - - /** - * Sets the credential to use when authenticating HTTP requests. - * - * @param credential The credential to use for authenticating HTTP requests. - * @return the updated {@link KeyClientBuilder} object. - * @throws NullPointerException if {@code credential} is {@code null}. - */ - public KeyClientBuilder credential(TokenCredential credential) { - builder.credential(credential); - return this; - } - - /** - * Sets the logging level for HTTP requests and responses. - * - *

logLevel is optional. If not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

- * - * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return the updated {@link KeyClientBuilder} object. - * @throws NullPointerException if {@code logLevel} is {@code null}. - */ - public KeyClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { - builder.httpLogDetailLevel(logLevel); - return this; - } - - /** - * Adds a policy to the set of existing policies that are executed after - * {@link KeyClient} required policies. - * - * @param policy The {@link HttpPipelinePolicy policy} to be added. - * @return the updated {@link KeyClientBuilder} object. - * @throws NullPointerException if {@code policy} is {@code null}. - */ - public KeyClientBuilder addPolicy(HttpPipelinePolicy policy) { - builder.addPolicy(policy); - return this; - } - - /** - * Sets the HTTP client to use for sending and receiving requests to and from the service. - * - * @param client The HTTP client to use for requests. - * @return the updated {@link KeyClientBuilder} object. - * @throws NullPointerException If {@code client} is {@code null}. - */ - public KeyClientBuilder httpClient(HttpClient client) { - builder.httpClient(client); - return this; - } - - /** - * Sets the HTTP pipeline to use for the service client. - * - * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link KeyClientBuilder#endpoint(String) endpoint} to build {@link KeyClient}. - * - * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return the updated {@link KeyClientBuilder} object. - */ - public KeyClientBuilder pipeline(HttpPipeline pipeline) { - builder.pipeline(pipeline); - return this; - } -} diff --git a/keyvault/client/keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java b/keyvault/client/keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java deleted file mode 100644 index 6208b37da9a39..0000000000000 --- a/keyvault/client/keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.security.keyvault.keys; - -import com.azure.core.credentials.TokenCredential; -import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.models.Key; -import com.azure.security.keyvault.keys.models.KeyBase; -import com.azure.security.keyvault.keys.models.webkey.KeyType; - -/** - * This class contains code samples for generating javadocs through doclets for {@link KeyClient} - */ -public final class KeyClientJavaDocCodeSnippets { - - /** - * Generates code sample for creating a {@link KeyClient} - * @return An instance of {@link KeyClient} - */ - public KeyClient createClient() { - // BEGIN: com.azure.keyvault.keys.keyclient.instantiation - KeyClient keyClient = KeyClient.builder() - .endpoint("https://myvault.azure.net/") - .credential(new DefaultAzureCredential()) - .build(); - // END: com.azure.keyvault.keys.keyclient.instantiation - return keyClient; - } - - /** - * Generates a code sample for using {@link KeyClient#createKey(String, KeyType)} - */ - public void createKey() { - KeyClient keyClient = createClient(); - // BEGIN: com.azure.keyvault.keys.keyclient.createKey#string-keyType - Key retKey = keyClient.createKey("keyName", KeyType.EC).value(); - System.out.printf("Key is created with name %s and id %s %n", retKey.name(), retKey.id()); - // END: com.azure.keyvault.keys.keyclient.createKey#string-keyType - } - - /** - * Generates code sample for using {@link KeyClient#listKeyVersions(String)} - */ - public void listKeyVersions() { - KeyClient keyClient = createClient(); - // BEGIN: com.azure.keyvault.keys.keyclient.listKeyVersions - for (KeyBase key : keyClient.listKeyVersions("keyName")) { - Key keyWithMaterial = keyClient.getKey(key).value(); - System.out.printf("Received key's version with name %s, type %s and version %s", keyWithMaterial.name(), - keyWithMaterial.keyMaterial().kty(), keyWithMaterial.version()); - } - // END: com.azure.keyvault.keys.keyclient.listKeyVersions - } - - /** - * Implementation not provided for this method - * @return {@code null} - */ - private TokenCredential getKeyVaultCredential() { - return null; - } -} diff --git a/keyvault/client/secrets/CHANGELOG.md b/keyvault/client/secrets/CHANGELOG.md deleted file mode 100644 index 63e0314b74012..0000000000000 --- a/keyvault/client/secrets/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Release History - -## 4.0.0-preview.1 (2019-06-28) -For release notes and more information please visit -https://aka.ms/azure-sdk-preview1-java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java b/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java deleted file mode 100644 index b095749fce5f2..0000000000000 --- a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.security.keyvault.secrets; - -import com.azure.core.implementation.annotation.ServiceClientBuilder; -import com.azure.core.util.configuration.ConfigurationManager; -import com.azure.core.util.configuration.Configuration; -import com.azure.core.credentials.TokenCredential; -import com.azure.core.http.HttpClient; -import com.azure.core.http.HttpPipeline; -import com.azure.core.http.policy.HttpLogDetailLevel; -import com.azure.core.http.policy.HttpLoggingPolicy; -import com.azure.core.http.policy.HttpPipelinePolicy; - -/** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link SecretClient secret client}, - * calling {@link SecretClientBuilder#build() build} constructs an instance of the client. - * - *

The minimal configuration options required by {@link SecretClientBuilder secretClientBuilder} to build {@link SecretClient} - * are {@link String endpoint} and {@link TokenCredential credential}.

- *
- * SecretClient.builder()
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .credential(new DefaultAzureCredential())
- *   .build();
- * 
- * - *

The {@link HttpLogDetailLevel log detail level}, multiple custom {@link HttpLoggingPolicy policies} and custom - * {@link HttpClient http client} can be optionally configured in the {@link SecretClientBuilder}.

- *
- * SecretClient.builder()
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .credential(new DefaultAzureCredential())
- *   .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
- *   .addPolicy(customPolicyOne)
- *   .addPolicy(customPolicyTwo)
- *   .httpClient(client)
- *   .build();
- * 
- * - *

Alternatively, custom {@link HttpPipeline http pipeline} with custom {@link HttpPipelinePolicy} policies and {@link String endpoint} - * can be specified. It provides finer control over the construction of {@link SecretClient client}

- *
- * SecretClient.builder()
- *   .pipeline(new HttpPipeline(customPoliciesList))
- *   .endpoint("https://myvault.vault.azure.net/")
- *   .build()
- * 
- * - * @see SecretClient - */ -@ServiceClientBuilder(serviceClients = SecretClient.class) -public final class SecretClientBuilder { - private final SecretAsyncClientBuilder builder; - - SecretClientBuilder() { - builder = SecretAsyncClient.builder(); - } - - /** - * Creates a {@link SecretClient} based on options set in the builder. - * Every time {@code build()} is called, a new instance of {@link SecretClient} is created. - * - *

If {@link SecretClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link SecretClientBuilder#endpoint(String) serviceEndpoint} are used to create the - * {@link SecretClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, - * then {@link SecretClientBuilder#credential(TokenCredential) key vault credential and - * {@link SecretClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link SecretClient client}.}

- * - * @return A SecretClient with the options set from the builder. - * @throws IllegalStateException If {@link SecretClientBuilder#credential(TokenCredential)} or - * {@link SecretClientBuilder#endpoint(String)} have not been set. - */ - public SecretClient build() { - return new SecretClient(builder.build()); - } - - /** - * Sets the vault endpoint url to send HTTP requests to. - * - * @param endpoint The vault endpoint url is used as destination on Azure to send requests to. - * @return the updated {@link SecretClientBuilder} object. - * @throws IllegalArgumentException if {@code endpoint} is null or it cannot be parsed into a valid URL. - */ - public SecretClientBuilder endpoint(String endpoint) { - builder.endpoint(endpoint); - return this; - } - - /** - * Sets the credential to use when authenticating HTTP requests. - * - * @param credential The credential to use for authenticating HTTP requests. - * @return the updated {@link SecretClientBuilder} object. - * @throws NullPointerException if {@code credential} is {@code null}. - */ - public SecretClientBuilder credential(TokenCredential credential) { - builder.credential(credential); - return this; - } - - /** - * Sets the logging level for HTTP requests and responses. - * - *

logLevel is optional. If not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

- * - * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return the updated {@link SecretClientBuilder} object. - * @throws NullPointerException if {@code logLevel} is {@code null}. - */ - public SecretClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { - builder.httpLogDetailLevel(logLevel); - return this; - } - - /** - * Adds a policy to the set of existing policies that are executed after - * {@link SecretClient} required policies. - * - * @param policy The {@link HttpPipelinePolicy policy} to be added. - * @return the updated {@link SecretClientBuilder} object. - * @throws NullPointerException if {@code policy} is {@code null}. - */ - public SecretClientBuilder addPolicy(HttpPipelinePolicy policy) { - builder.addPolicy(policy); - return this; - } - - /** - * Sets the HTTP client to use for sending and receiving requests to and from the service. - * - * @param client The HTTP client to use for requests. - * @return the updated {@link SecretClientBuilder} object. - * @throws NullPointerException If {@code client} is {@code null}. - */ - public SecretClientBuilder httpClient(HttpClient client) { - builder.httpClient(client); - return this; - } - - /** - * Sets the HTTP pipeline to use for the service client. - * - * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link SecretClientBuilder#endpoint(String) endpoint} to build {@link SecretClient}. - * - * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return the updated {@link SecretClientBuilder} object. - */ - public SecretClientBuilder pipeline(HttpPipeline pipeline) { - builder.pipeline(pipeline); - return this; - } - - /** - * Sets the configuration store that is used during construction of the service client. - * - * The default configuration store is a clone of the {@link ConfigurationManager#getConfiguration() global - * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. - * - * @param configuration The configuration store used to - * @return The updated SecretClientBuilder object. - */ - public SecretClientBuilder configuration(Configuration configuration) { - builder.configuration(configuration); - return this; - } -} diff --git a/keyvault/client/secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java b/keyvault/client/secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java deleted file mode 100644 index 71fba64e2252e..0000000000000 --- a/keyvault/client/secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.azure.security.keyvault.secrets; - -import com.azure.security.keyvault.secrets.models.Secret; -import com.azure.security.keyvault.secrets.models.SecretBase; - -/** - * This class contains code samples for generating javadocs through doclets for {@link SecretClient] - */ -public final class SecretClientJavaDocCodeSnippets { - - /** - * Method to insert code snippets for {@link SecretClient#getSecret(SecretBase)} - */ - public void getSecret() { - SecretClient secretClient = getSecretClient(); - // BEGIN: com.azure.keyvault.secretclient.getSecret#secretBase - for(SecretBase secret : secretClient.listSecrets()){ - Secret secretWithValue = secretClient.getSecret(secret).value(); - System.out.printf("Secret is returned with name %s and value %s %n", secretWithValue.name(), - secretWithValue.value()); - } - // END: com.azure.keyvault.secretclient.getSecret#secretBase - } - - /** - * Implementation not provided for this method - * @return {@code null} - */ - private SecretClient getSecretClient() { - return null; - } -} diff --git a/mediaservices/resource-manager/v2015_10_01/pom.xml b/mediaservices/resource-manager/v2015_10_01/pom.xml index f5b4359736385..70a748016da39 100644 --- a/mediaservices/resource-manager/v2015_10_01/pom.xml +++ b/mediaservices/resource-manager/v2015_10_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/netapp/resource-manager/v2019_06_01/pom.xml b/netapp/resource-manager/v2019_06_01/pom.xml index 64bb9aec1e57d..07688d78b3990 100644 --- a/netapp/resource-manager/v2019_06_01/pom.xml +++ b/netapp/resource-manager/v2019_06_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/PoolsImpl.java b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/PoolsImpl.java index dc145cfa70b83..2243f74b09cb6 100644 --- a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/PoolsImpl.java +++ b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/PoolsImpl.java @@ -64,10 +64,14 @@ public CapacityPool call(CapacityPoolInner inner) { public Observable getAsync(String resourceGroupName, String accountName, String poolName) { PoolsInner client = this.inner(); return client.getAsync(resourceGroupName, accountName, poolName) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public CapacityPool call(CapacityPoolInner inner) { - return wrapModel(inner); + public Observable call(CapacityPoolInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((CapacityPool)wrapModel(inner)); + } } }); } diff --git a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/SnapshotsImpl.java b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/SnapshotsImpl.java index 48c2a5c78ef5f..9ed6494294703 100644 --- a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/SnapshotsImpl.java +++ b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/SnapshotsImpl.java @@ -64,10 +64,14 @@ public Snapshot call(SnapshotInner inner) { public Observable getAsync(String resourceGroupName, String accountName, String poolName, String volumeName, String snapshotName) { SnapshotsInner client = this.inner(); return client.getAsync(resourceGroupName, accountName, poolName, volumeName, snapshotName) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public Snapshot call(SnapshotInner inner) { - return wrapModel(inner); + public Observable call(SnapshotInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((Snapshot)wrapModel(inner)); + } } }); } diff --git a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/VolumesImpl.java b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/VolumesImpl.java index 68a6022f4a777..62cd23cf29408 100644 --- a/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/VolumesImpl.java +++ b/netapp/resource-manager/v2019_06_01/src/main/java/com/microsoft/azure/management/netapp/v2019_06_01/implementation/VolumesImpl.java @@ -64,10 +64,14 @@ public Volume call(VolumeInner inner) { public Observable getAsync(String resourceGroupName, String accountName, String poolName, String volumeName) { VolumesInner client = this.inner(); return client.getAsync(resourceGroupName, accountName, poolName, volumeName) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public Volume call(VolumeInner inner) { - return wrapModel(inner); + public Observable call(VolumeInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((Volume)wrapModel(inner)); + } } }); } diff --git a/notificationhubs/resource-manager/v2016_03_01/pom.xml b/notificationhubs/resource-manager/v2016_03_01/pom.xml index 61c69279d5cda..ff98ac0d32bc0 100644 --- a/notificationhubs/resource-manager/v2016_03_01/pom.xml +++ b/notificationhubs/resource-manager/v2016_03_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/operationsmanagement/resource-manager/v2015_11_01_preview/pom.xml b/operationsmanagement/resource-manager/v2015_11_01_preview/pom.xml index ba38371ea9207..7b030a5cc6ac1 100644 --- a/operationsmanagement/resource-manager/v2015_11_01_preview/pom.xml +++ b/operationsmanagement/resource-manager/v2015_11_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/parent/pom.xml b/parent/pom.xml index 6a5873e491ecf..1c259a2117bae 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -6,7 +6,7 @@ com.azure azure-sdk-parent pom - 1.0.0 + 1.1.0 Microsoft Azure SDK for Java Parent Parent POM for Microsoft Azure SDK for Java @@ -101,7 +101,8 @@ 2.9.9 1.6.10 1.10 - 3.1.11 + 4.0.0-beta3 + 3.1.12 0.31.0 1.2.0 2.11.1 @@ -160,8 +161,8 @@ 3.7.1 3.0.0 1.8 - 3.0.0 - 8.18 + 3.1.0 + 8.19 2.28.2 0.8.4
@@ -408,7 +409,7 @@ ${spock-core.version} - + cglib cglib-nodep ${cglib-nodep.version} diff --git a/policy/resource-manager/v2018_05_01/pom.xml b/policy/resource-manager/v2018_05_01/pom.xml index 19d701cb0b806..d483a98022dfe 100644 --- a/policy/resource-manager/v2018_05_01/pom.xml +++ b/policy/resource-manager/v2018_05_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/policyinsights/resource-manager/v2018_04_04/pom.xml b/policyinsights/resource-manager/v2018_04_04/pom.xml index a653b51b57303..0e82e83b4f0dd 100644 --- a/policyinsights/resource-manager/v2018_04_04/pom.xml +++ b/policyinsights/resource-manager/v2018_04_04/pom.xml @@ -15,11 +15,11 @@ ../../../pom.management.xml azure-mgmt-policyinsights - 1.0.0-beta-1 + 1.0.0-beta jar Microsoft Azure SDK for PolicyInsights Management This package contains Microsoft PolicyInsights Management SDK. - https://github.com/Azure/azure-libraries-for-java + https://github.com/Azure/azure-sdk-for-java The MIT License (MIT) @@ -28,8 +28,8 @@ - scm:git:https://github.com/Azure/azure-libraries-for-java - scm:git:git@github.com:Azure/azure-libraries-for-java.git + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git HEAD @@ -64,15 +64,15 @@ com.microsoft.azure azure-mgmt-resources - 1.11.1 test com.microsoft.azure azure-arm-client-runtime - 1.5.2 test-jar test + + 1.6.5 diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/OperationDisplay.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/OperationDisplay.java index 20ecbc62ba348..b1c5a01b83dc4 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/OperationDisplay.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/OperationDisplay.java @@ -39,7 +39,7 @@ public class OperationDisplay { private String description; /** - * Get the provider value. + * Get resource provider name. * * @return the provider value */ @@ -48,7 +48,7 @@ public String provider() { } /** - * Set the provider value. + * Set resource provider name. * * @param provider the provider value to set * @return the OperationDisplay object itself. @@ -59,7 +59,7 @@ public OperationDisplay withProvider(String provider) { } /** - * Get the resource value. + * Get resource name on which the operation is performed. * * @return the resource value */ @@ -68,7 +68,7 @@ public String resource() { } /** - * Set the resource value. + * Set resource name on which the operation is performed. * * @param resource the resource value to set * @return the OperationDisplay object itself. @@ -79,7 +79,7 @@ public OperationDisplay withResource(String resource) { } /** - * Get the operation value. + * Get operation name. * * @return the operation value */ @@ -88,7 +88,7 @@ public String operation() { } /** - * Set the operation value. + * Set operation name. * * @param operation the operation value to set * @return the OperationDisplay object itself. @@ -99,7 +99,7 @@ public OperationDisplay withOperation(String operation) { } /** - * Get the description value. + * Get operation description. * * @return the description value */ @@ -108,7 +108,7 @@ public String description() { } /** - * Set the description value. + * Set operation description. * * @param description the description value to set * @return the OperationDisplay object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyAssignmentSummary.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyAssignmentSummary.java index 853e2cfeca655..4cf796ef8f232 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyAssignmentSummary.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyAssignmentSummary.java @@ -40,7 +40,7 @@ public class PolicyAssignmentSummary { private List policyDefinitions; /** - * Get the policyAssignmentId value. + * Get policy assignment ID. * * @return the policyAssignmentId value */ @@ -49,7 +49,7 @@ public String policyAssignmentId() { } /** - * Set the policyAssignmentId value. + * Set policy assignment ID. * * @param policyAssignmentId the policyAssignmentId value to set * @return the PolicyAssignmentSummary object itself. @@ -60,7 +60,7 @@ public PolicyAssignmentSummary withPolicyAssignmentId(String policyAssignmentId) } /** - * Get the policySetDefinitionId value. + * Get policy set definition ID, if the policy assignment is for a policy set. * * @return the policySetDefinitionId value */ @@ -69,7 +69,7 @@ public String policySetDefinitionId() { } /** - * Set the policySetDefinitionId value. + * Set policy set definition ID, if the policy assignment is for a policy set. * * @param policySetDefinitionId the policySetDefinitionId value to set * @return the PolicyAssignmentSummary object itself. @@ -80,7 +80,7 @@ public PolicyAssignmentSummary withPolicySetDefinitionId(String policySetDefinit } /** - * Get the results value. + * Get non-compliance summary for the policy assignment. * * @return the results value */ @@ -89,7 +89,7 @@ public SummaryResults results() { } /** - * Set the results value. + * Set non-compliance summary for the policy assignment. * * @param results the results value to set * @return the PolicyAssignmentSummary object itself. @@ -100,7 +100,7 @@ public PolicyAssignmentSummary withResults(SummaryResults results) { } /** - * Get the policyDefinitions value. + * Get policy definitions summary. * * @return the policyDefinitions value */ @@ -109,7 +109,7 @@ public List policyDefinitions() { } /** - * Set the policyDefinitions value. + * Set policy definitions summary. * * @param policyDefinitions the policyDefinitions value to set * @return the PolicyAssignmentSummary object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyDefinitionSummary.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyDefinitionSummary.java index 20b027ebfac22..74c45dbcef70a 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyDefinitionSummary.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyDefinitionSummary.java @@ -39,7 +39,7 @@ public class PolicyDefinitionSummary { private SummaryResults results; /** - * Get the policyDefinitionId value. + * Get policy definition ID. * * @return the policyDefinitionId value */ @@ -48,7 +48,7 @@ public String policyDefinitionId() { } /** - * Set the policyDefinitionId value. + * Set policy definition ID. * * @param policyDefinitionId the policyDefinitionId value to set * @return the PolicyDefinitionSummary object itself. @@ -59,7 +59,7 @@ public PolicyDefinitionSummary withPolicyDefinitionId(String policyDefinitionId) } /** - * Get the policyDefinitionReferenceId value. + * Get policy definition reference ID. * * @return the policyDefinitionReferenceId value */ @@ -68,7 +68,7 @@ public String policyDefinitionReferenceId() { } /** - * Set the policyDefinitionReferenceId value. + * Set policy definition reference ID. * * @param policyDefinitionReferenceId the policyDefinitionReferenceId value to set * @return the PolicyDefinitionSummary object itself. @@ -79,7 +79,7 @@ public PolicyDefinitionSummary withPolicyDefinitionReferenceId(String policyDefi } /** - * Get the effect value. + * Get policy effect, i.e. policy definition action. * * @return the effect value */ @@ -88,7 +88,7 @@ public String effect() { } /** - * Set the effect value. + * Set policy effect, i.e. policy definition action. * * @param effect the effect value to set * @return the PolicyDefinitionSummary object itself. @@ -99,7 +99,7 @@ public PolicyDefinitionSummary withEffect(String effect) { } /** - * Get the results value. + * Get non-compliance summary for the policy definition. * * @return the results value */ @@ -108,7 +108,7 @@ public SummaryResults results() { } /** - * Set the results value. + * Set non-compliance summary for the policy definition. * * @param results the results value to set * @return the PolicyDefinitionSummary object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyEvents.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyEvents.java index 7c29e655e9f58..d4f628fd5e34c 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyEvents.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyEvents.java @@ -8,7 +8,6 @@ package com.microsoft.azure.management.policyinsights.v2018_04_04; -import rx.Completable; import rx.Observable; /** @@ -100,6 +99,6 @@ public interface PolicyEvents { * @throws IllegalArgumentException thrown if parameters fail the validation * @return the observable for the request */ - Completable getMetadataAsync(String scope); + Observable getMetadataAsync(String scope); } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyStates.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyStates.java index 5b3533408bf0e..a5a7131799df7 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyStates.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/PolicyStates.java @@ -8,7 +8,6 @@ package com.microsoft.azure.management.policyinsights.v2018_04_04; -import rx.Completable; import rx.Observable; /** @@ -186,6 +185,6 @@ public interface PolicyStates { * @throws IllegalArgumentException thrown if parameters fail the validation * @return the observable for the request */ - Completable getMetadataAsync(String scope); + Observable getMetadataAsync(String scope); } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailure.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailure.java index beda033d97e09..4caf9c095cddc 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailure.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailure.java @@ -21,7 +21,7 @@ public class QueryFailure { private QueryFailureError error; /** - * Get the error value. + * Get error definition. * * @return the error value */ @@ -30,7 +30,7 @@ public QueryFailureError error() { } /** - * Set the error value. + * Set error definition. * * @param error the error value to set * @return the QueryFailure object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailureError.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailureError.java index 5ab11fe919574..df48a012368bd 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailureError.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryFailureError.java @@ -18,17 +18,17 @@ public class QueryFailureError { * Service specific error code which serves as the substatus for the HTTP * error code. */ - @JsonProperty(value = "code") + @JsonProperty(value = "code", access = JsonProperty.Access.WRITE_ONLY) private String code; /** * Description of the error. */ - @JsonProperty(value = "message") + @JsonProperty(value = "message", access = JsonProperty.Access.WRITE_ONLY) private String message; /** - * Get the code value. + * Get service specific error code which serves as the substatus for the HTTP error code. * * @return the code value */ @@ -37,18 +37,7 @@ public String code() { } /** - * Set the code value. - * - * @param code the code value to set - * @return the QueryFailureError object itself. - */ - public QueryFailureError withCode(String code) { - this.code = code; - return this; - } - - /** - * Get the message value. + * Get description of the error. * * @return the message value */ @@ -56,15 +45,4 @@ public String message() { return this.message; } - /** - * Set the message value. - * - * @param message the message value to set - * @return the QueryFailureError object itself. - */ - public QueryFailureError withMessage(String message) { - this.message = message; - return this; - } - } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryOptions.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryOptions.java index 39b59cad3f2aa..86ca2dd0dbb66 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryOptions.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/QueryOptions.java @@ -64,7 +64,7 @@ public class QueryOptions { private String apply; /** - * Get the top value. + * Get maximum number of records to return. * * @return the top value */ @@ -73,7 +73,7 @@ public Integer top() { } /** - * Set the top value. + * Set maximum number of records to return. * * @param top the top value to set * @return the QueryOptions object itself. @@ -84,7 +84,7 @@ public QueryOptions withTop(Integer top) { } /** - * Get the orderBy value. + * Get ordering expression using OData notation. One or more comma-separated column names with an optional "desc" (the default) or "asc", e.g. "$orderby=PolicyAssignmentId, ResourceId asc". * * @return the orderBy value */ @@ -93,7 +93,7 @@ public String orderBy() { } /** - * Set the orderBy value. + * Set ordering expression using OData notation. One or more comma-separated column names with an optional "desc" (the default) or "asc", e.g. "$orderby=PolicyAssignmentId, ResourceId asc". * * @param orderBy the orderBy value to set * @return the QueryOptions object itself. @@ -104,7 +104,7 @@ public QueryOptions withOrderBy(String orderBy) { } /** - * Get the select value. + * Get select expression using OData notation. Limits the columns on each record to just those requested, e.g. "$select=PolicyAssignmentId, ResourceId". * * @return the select value */ @@ -113,7 +113,7 @@ public String select() { } /** - * Set the select value. + * Set select expression using OData notation. Limits the columns on each record to just those requested, e.g. "$select=PolicyAssignmentId, ResourceId". * * @param select the select value to set * @return the QueryOptions object itself. @@ -124,7 +124,7 @@ public QueryOptions withSelect(String select) { } /** - * Get the from value. + * Get iSO 8601 formatted timestamp specifying the start time of the interval to query. When not specified, the service uses ($to - 1-day). * * @return the from value */ @@ -133,7 +133,7 @@ public DateTime from() { } /** - * Set the from value. + * Set iSO 8601 formatted timestamp specifying the start time of the interval to query. When not specified, the service uses ($to - 1-day). * * @param from the from value to set * @return the QueryOptions object itself. @@ -144,7 +144,7 @@ public QueryOptions withFrom(DateTime from) { } /** - * Get the to value. + * Get iSO 8601 formatted timestamp specifying the end time of the interval to query. When not specified, the service uses request time. * * @return the to value */ @@ -153,7 +153,7 @@ public DateTime to() { } /** - * Set the to value. + * Set iSO 8601 formatted timestamp specifying the end time of the interval to query. When not specified, the service uses request time. * * @param to the to value to set * @return the QueryOptions object itself. @@ -164,7 +164,7 @@ public QueryOptions withTo(DateTime to) { } /** - * Get the filter value. + * Get oData filter expression. * * @return the filter value */ @@ -173,7 +173,7 @@ public String filter() { } /** - * Set the filter value. + * Set oData filter expression. * * @param filter the filter value to set * @return the QueryOptions object itself. @@ -184,7 +184,7 @@ public QueryOptions withFilter(String filter) { } /** - * Get the apply value. + * Get oData apply expression for aggregations. * * @return the apply value */ @@ -193,7 +193,7 @@ public String apply() { } /** - * Set the apply value. + * Set oData apply expression for aggregations. * * @param apply the apply value to set * @return the QueryOptions object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/Summary.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/Summary.java index ff24b34766489..ade9fdf756322 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/Summary.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/Summary.java @@ -42,7 +42,7 @@ public class Summary { private List policyAssignments; /** - * Get the odataid value. + * Get oData entity ID; always set to null since summaries do not have an entity ID. * * @return the odataid value */ @@ -51,7 +51,7 @@ public String odataid() { } /** - * Set the odataid value. + * Set oData entity ID; always set to null since summaries do not have an entity ID. * * @param odataid the odataid value to set * @return the Summary object itself. @@ -62,7 +62,7 @@ public Summary withOdataid(String odataid) { } /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -71,7 +71,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the Summary object itself. @@ -82,7 +82,7 @@ public Summary withOdatacontext(String odatacontext) { } /** - * Get the results value. + * Get non-compliance summary for all policy assignments. * * @return the results value */ @@ -91,7 +91,7 @@ public SummaryResults results() { } /** - * Set the results value. + * Set non-compliance summary for all policy assignments. * * @param results the results value to set * @return the Summary object itself. @@ -102,7 +102,7 @@ public Summary withResults(SummaryResults results) { } /** - * Get the policyAssignments value. + * Get policy assignments summary. * * @return the policyAssignments value */ @@ -111,7 +111,7 @@ public List policyAssignments() { } /** - * Set the policyAssignments value. + * Set policy assignments summary. * * @param policyAssignments the policyAssignments value to set * @return the Summary object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/SummaryResults.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/SummaryResults.java index 6a2214e95bfd5..0b4549f3cdfd3 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/SummaryResults.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/SummaryResults.java @@ -34,7 +34,7 @@ public class SummaryResults { private Integer nonCompliantPolicies; /** - * Get the queryResultsUri value. + * Get hTTP POST URI for queryResults action on Microsoft.PolicyInsights to retrieve raw results for the non-compliance summary. * * @return the queryResultsUri value */ @@ -43,7 +43,7 @@ public String queryResultsUri() { } /** - * Set the queryResultsUri value. + * Set hTTP POST URI for queryResults action on Microsoft.PolicyInsights to retrieve raw results for the non-compliance summary. * * @param queryResultsUri the queryResultsUri value to set * @return the SummaryResults object itself. @@ -54,7 +54,7 @@ public SummaryResults withQueryResultsUri(String queryResultsUri) { } /** - * Get the nonCompliantResources value. + * Get number of non-compliant resources. * * @return the nonCompliantResources value */ @@ -63,7 +63,7 @@ public Integer nonCompliantResources() { } /** - * Set the nonCompliantResources value. + * Set number of non-compliant resources. * * @param nonCompliantResources the nonCompliantResources value to set * @return the SummaryResults object itself. @@ -74,7 +74,7 @@ public SummaryResults withNonCompliantResources(Integer nonCompliantResources) { } /** - * Get the nonCompliantPolicies value. + * Get number of non-compliant policies. * * @return the nonCompliantPolicies value */ @@ -83,7 +83,7 @@ public Integer nonCompliantPolicies() { } /** - * Set the nonCompliantPolicies value. + * Set number of non-compliant policies. * * @param nonCompliantPolicies the nonCompliantPolicies value to set * @return the SummaryResults object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationInner.java index d74364feade44..8d22efd4fa1cb 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationInner.java @@ -28,7 +28,7 @@ public class OperationInner { private OperationDisplay display; /** - * Get the name value. + * Get operation name. * * @return the name value */ @@ -37,7 +37,7 @@ public String name() { } /** - * Set the name value. + * Set operation name. * * @param name the name value to set * @return the OperationInner object itself. @@ -48,7 +48,7 @@ public OperationInner withName(String name) { } /** - * Get the display value. + * Get display metadata associated with the operation. * * @return the display value */ @@ -57,7 +57,7 @@ public OperationDisplay display() { } /** - * Set the display value. + * Set display metadata associated with the operation. * * @param display the display value to set * @return the OperationInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationsListResultsInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationsListResultsInner.java index ce6e0866bc240..13be27de87c62 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationsListResultsInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/OperationsListResultsInner.java @@ -28,7 +28,7 @@ public class OperationsListResultsInner { private List value; /** - * Get the odatacount value. + * Get oData entity count; represents the number of operations returned. * * @return the odatacount value */ @@ -37,7 +37,7 @@ public Integer odatacount() { } /** - * Set the odatacount value. + * Set oData entity count; represents the number of operations returned. * * @param odatacount the odatacount value to set * @return the OperationsListResultsInner object itself. @@ -48,7 +48,7 @@ public OperationsListResultsInner withOdatacount(Integer odatacount) { } /** - * Get the value value. + * Get list of available operations. * * @return the value value */ @@ -57,7 +57,7 @@ public List value() { } /** - * Set the value value. + * Set list of available operations. * * @param value the value value to set * @return the OperationsListResultsInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventInner.java index d7fed6037b931..de72cd2028401 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventInner.java @@ -180,7 +180,7 @@ public class PolicyEventInner { private String policySetDefinitionParameters; /** - * Comma seperated list of management group IDs, which represent the + * Comma separated list of management group IDs, which represent the * hierarchy of the management groups the resource is under. */ @JsonProperty(value = "managementGroupIds") @@ -207,7 +207,7 @@ public class PolicyEventInner { private String principalOid; /** - * Get the additionalProperties value. + * Get unmatched properties from the message are deserialized this collection. * * @return the additionalProperties value */ @@ -216,7 +216,7 @@ public Map additionalProperties() { } /** - * Set the additionalProperties value. + * Set unmatched properties from the message are deserialized this collection. * * @param additionalProperties the additionalProperties value to set * @return the PolicyEventInner object itself. @@ -227,7 +227,7 @@ public PolicyEventInner withAdditionalProperties(Map additionalP } /** - * Get the odataid value. + * Get oData entity ID; always set to null since policy event records do not have an entity ID. * * @return the odataid value */ @@ -236,7 +236,7 @@ public String odataid() { } /** - * Set the odataid value. + * Set oData entity ID; always set to null since policy event records do not have an entity ID. * * @param odataid the odataid value to set * @return the PolicyEventInner object itself. @@ -247,7 +247,7 @@ public PolicyEventInner withOdataid(String odataid) { } /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -256,7 +256,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the PolicyEventInner object itself. @@ -267,7 +267,7 @@ public PolicyEventInner withOdatacontext(String odatacontext) { } /** - * Get the timestamp value. + * Get timestamp for the policy event record. * * @return the timestamp value */ @@ -276,7 +276,7 @@ public DateTime timestamp() { } /** - * Set the timestamp value. + * Set timestamp for the policy event record. * * @param timestamp the timestamp value to set * @return the PolicyEventInner object itself. @@ -287,7 +287,7 @@ public PolicyEventInner withTimestamp(DateTime timestamp) { } /** - * Get the resourceId value. + * Get resource ID. * * @return the resourceId value */ @@ -296,7 +296,7 @@ public String resourceId() { } /** - * Set the resourceId value. + * Set resource ID. * * @param resourceId the resourceId value to set * @return the PolicyEventInner object itself. @@ -307,7 +307,7 @@ public PolicyEventInner withResourceId(String resourceId) { } /** - * Get the policyAssignmentId value. + * Get policy assignment ID. * * @return the policyAssignmentId value */ @@ -316,7 +316,7 @@ public String policyAssignmentId() { } /** - * Set the policyAssignmentId value. + * Set policy assignment ID. * * @param policyAssignmentId the policyAssignmentId value to set * @return the PolicyEventInner object itself. @@ -327,7 +327,7 @@ public PolicyEventInner withPolicyAssignmentId(String policyAssignmentId) { } /** - * Get the policyDefinitionId value. + * Get policy definition ID. * * @return the policyDefinitionId value */ @@ -336,7 +336,7 @@ public String policyDefinitionId() { } /** - * Set the policyDefinitionId value. + * Set policy definition ID. * * @param policyDefinitionId the policyDefinitionId value to set * @return the PolicyEventInner object itself. @@ -347,7 +347,7 @@ public PolicyEventInner withPolicyDefinitionId(String policyDefinitionId) { } /** - * Get the effectiveParameters value. + * Get effective parameters for the policy assignment. * * @return the effectiveParameters value */ @@ -356,7 +356,7 @@ public String effectiveParameters() { } /** - * Set the effectiveParameters value. + * Set effective parameters for the policy assignment. * * @param effectiveParameters the effectiveParameters value to set * @return the PolicyEventInner object itself. @@ -367,7 +367,7 @@ public PolicyEventInner withEffectiveParameters(String effectiveParameters) { } /** - * Get the isCompliant value. + * Get flag which states whether the resource is compliant against the policy assignment it was evaluated against. * * @return the isCompliant value */ @@ -376,7 +376,7 @@ public Boolean isCompliant() { } /** - * Set the isCompliant value. + * Set flag which states whether the resource is compliant against the policy assignment it was evaluated against. * * @param isCompliant the isCompliant value to set * @return the PolicyEventInner object itself. @@ -387,7 +387,7 @@ public PolicyEventInner withIsCompliant(Boolean isCompliant) { } /** - * Get the subscriptionId value. + * Get subscription ID. * * @return the subscriptionId value */ @@ -396,7 +396,7 @@ public String subscriptionId() { } /** - * Set the subscriptionId value. + * Set subscription ID. * * @param subscriptionId the subscriptionId value to set * @return the PolicyEventInner object itself. @@ -407,7 +407,7 @@ public PolicyEventInner withSubscriptionId(String subscriptionId) { } /** - * Get the resourceType value. + * Get resource type. * * @return the resourceType value */ @@ -416,7 +416,7 @@ public String resourceType() { } /** - * Set the resourceType value. + * Set resource type. * * @param resourceType the resourceType value to set * @return the PolicyEventInner object itself. @@ -427,7 +427,7 @@ public PolicyEventInner withResourceType(String resourceType) { } /** - * Get the resourceLocation value. + * Get resource location. * * @return the resourceLocation value */ @@ -436,7 +436,7 @@ public String resourceLocation() { } /** - * Set the resourceLocation value. + * Set resource location. * * @param resourceLocation the resourceLocation value to set * @return the PolicyEventInner object itself. @@ -447,7 +447,7 @@ public PolicyEventInner withResourceLocation(String resourceLocation) { } /** - * Get the resourceGroup value. + * Get resource group name. * * @return the resourceGroup value */ @@ -456,7 +456,7 @@ public String resourceGroup() { } /** - * Set the resourceGroup value. + * Set resource group name. * * @param resourceGroup the resourceGroup value to set * @return the PolicyEventInner object itself. @@ -467,7 +467,7 @@ public PolicyEventInner withResourceGroup(String resourceGroup) { } /** - * Get the resourceTags value. + * Get list of resource tags. * * @return the resourceTags value */ @@ -476,7 +476,7 @@ public String resourceTags() { } /** - * Set the resourceTags value. + * Set list of resource tags. * * @param resourceTags the resourceTags value to set * @return the PolicyEventInner object itself. @@ -487,7 +487,7 @@ public PolicyEventInner withResourceTags(String resourceTags) { } /** - * Get the policyAssignmentName value. + * Get policy assignment name. * * @return the policyAssignmentName value */ @@ -496,7 +496,7 @@ public String policyAssignmentName() { } /** - * Set the policyAssignmentName value. + * Set policy assignment name. * * @param policyAssignmentName the policyAssignmentName value to set * @return the PolicyEventInner object itself. @@ -507,7 +507,7 @@ public PolicyEventInner withPolicyAssignmentName(String policyAssignmentName) { } /** - * Get the policyAssignmentOwner value. + * Get policy assignment owner. * * @return the policyAssignmentOwner value */ @@ -516,7 +516,7 @@ public String policyAssignmentOwner() { } /** - * Set the policyAssignmentOwner value. + * Set policy assignment owner. * * @param policyAssignmentOwner the policyAssignmentOwner value to set * @return the PolicyEventInner object itself. @@ -527,7 +527,7 @@ public PolicyEventInner withPolicyAssignmentOwner(String policyAssignmentOwner) } /** - * Get the policyAssignmentParameters value. + * Get policy assignment parameters. * * @return the policyAssignmentParameters value */ @@ -536,7 +536,7 @@ public String policyAssignmentParameters() { } /** - * Set the policyAssignmentParameters value. + * Set policy assignment parameters. * * @param policyAssignmentParameters the policyAssignmentParameters value to set * @return the PolicyEventInner object itself. @@ -547,7 +547,7 @@ public PolicyEventInner withPolicyAssignmentParameters(String policyAssignmentPa } /** - * Get the policyAssignmentScope value. + * Get policy assignment scope. * * @return the policyAssignmentScope value */ @@ -556,7 +556,7 @@ public String policyAssignmentScope() { } /** - * Set the policyAssignmentScope value. + * Set policy assignment scope. * * @param policyAssignmentScope the policyAssignmentScope value to set * @return the PolicyEventInner object itself. @@ -567,7 +567,7 @@ public PolicyEventInner withPolicyAssignmentScope(String policyAssignmentScope) } /** - * Get the policyDefinitionName value. + * Get policy definition name. * * @return the policyDefinitionName value */ @@ -576,7 +576,7 @@ public String policyDefinitionName() { } /** - * Set the policyDefinitionName value. + * Set policy definition name. * * @param policyDefinitionName the policyDefinitionName value to set * @return the PolicyEventInner object itself. @@ -587,7 +587,7 @@ public PolicyEventInner withPolicyDefinitionName(String policyDefinitionName) { } /** - * Get the policyDefinitionAction value. + * Get policy definition action, i.e. effect. * * @return the policyDefinitionAction value */ @@ -596,7 +596,7 @@ public String policyDefinitionAction() { } /** - * Set the policyDefinitionAction value. + * Set policy definition action, i.e. effect. * * @param policyDefinitionAction the policyDefinitionAction value to set * @return the PolicyEventInner object itself. @@ -607,7 +607,7 @@ public PolicyEventInner withPolicyDefinitionAction(String policyDefinitionAction } /** - * Get the policyDefinitionCategory value. + * Get policy definition category. * * @return the policyDefinitionCategory value */ @@ -616,7 +616,7 @@ public String policyDefinitionCategory() { } /** - * Set the policyDefinitionCategory value. + * Set policy definition category. * * @param policyDefinitionCategory the policyDefinitionCategory value to set * @return the PolicyEventInner object itself. @@ -627,7 +627,7 @@ public PolicyEventInner withPolicyDefinitionCategory(String policyDefinitionCate } /** - * Get the policySetDefinitionId value. + * Get policy set definition ID, if the policy assignment is for a policy set. * * @return the policySetDefinitionId value */ @@ -636,7 +636,7 @@ public String policySetDefinitionId() { } /** - * Set the policySetDefinitionId value. + * Set policy set definition ID, if the policy assignment is for a policy set. * * @param policySetDefinitionId the policySetDefinitionId value to set * @return the PolicyEventInner object itself. @@ -647,7 +647,7 @@ public PolicyEventInner withPolicySetDefinitionId(String policySetDefinitionId) } /** - * Get the policySetDefinitionName value. + * Get policy set definition name, if the policy assignment is for a policy set. * * @return the policySetDefinitionName value */ @@ -656,7 +656,7 @@ public String policySetDefinitionName() { } /** - * Set the policySetDefinitionName value. + * Set policy set definition name, if the policy assignment is for a policy set. * * @param policySetDefinitionName the policySetDefinitionName value to set * @return the PolicyEventInner object itself. @@ -667,7 +667,7 @@ public PolicyEventInner withPolicySetDefinitionName(String policySetDefinitionNa } /** - * Get the policySetDefinitionOwner value. + * Get policy set definition owner, if the policy assignment is for a policy set. * * @return the policySetDefinitionOwner value */ @@ -676,7 +676,7 @@ public String policySetDefinitionOwner() { } /** - * Set the policySetDefinitionOwner value. + * Set policy set definition owner, if the policy assignment is for a policy set. * * @param policySetDefinitionOwner the policySetDefinitionOwner value to set * @return the PolicyEventInner object itself. @@ -687,7 +687,7 @@ public PolicyEventInner withPolicySetDefinitionOwner(String policySetDefinitionO } /** - * Get the policySetDefinitionCategory value. + * Get policy set definition category, if the policy assignment is for a policy set. * * @return the policySetDefinitionCategory value */ @@ -696,7 +696,7 @@ public String policySetDefinitionCategory() { } /** - * Set the policySetDefinitionCategory value. + * Set policy set definition category, if the policy assignment is for a policy set. * * @param policySetDefinitionCategory the policySetDefinitionCategory value to set * @return the PolicyEventInner object itself. @@ -707,7 +707,7 @@ public PolicyEventInner withPolicySetDefinitionCategory(String policySetDefiniti } /** - * Get the policySetDefinitionParameters value. + * Get policy set definition parameters, if the policy assignment is for a policy set. * * @return the policySetDefinitionParameters value */ @@ -716,7 +716,7 @@ public String policySetDefinitionParameters() { } /** - * Set the policySetDefinitionParameters value. + * Set policy set definition parameters, if the policy assignment is for a policy set. * * @param policySetDefinitionParameters the policySetDefinitionParameters value to set * @return the PolicyEventInner object itself. @@ -727,7 +727,7 @@ public PolicyEventInner withPolicySetDefinitionParameters(String policySetDefini } /** - * Get the managementGroupIds value. + * Get comma separated list of management group IDs, which represent the hierarchy of the management groups the resource is under. * * @return the managementGroupIds value */ @@ -736,7 +736,7 @@ public String managementGroupIds() { } /** - * Set the managementGroupIds value. + * Set comma separated list of management group IDs, which represent the hierarchy of the management groups the resource is under. * * @param managementGroupIds the managementGroupIds value to set * @return the PolicyEventInner object itself. @@ -747,7 +747,7 @@ public PolicyEventInner withManagementGroupIds(String managementGroupIds) { } /** - * Get the policyDefinitionReferenceId value. + * Get reference ID for the policy definition inside the policy set, if the policy assignment is for a policy set. * * @return the policyDefinitionReferenceId value */ @@ -756,7 +756,7 @@ public String policyDefinitionReferenceId() { } /** - * Set the policyDefinitionReferenceId value. + * Set reference ID for the policy definition inside the policy set, if the policy assignment is for a policy set. * * @param policyDefinitionReferenceId the policyDefinitionReferenceId value to set * @return the PolicyEventInner object itself. @@ -767,7 +767,7 @@ public PolicyEventInner withPolicyDefinitionReferenceId(String policyDefinitionR } /** - * Get the tenantId value. + * Get tenant ID for the policy event record. * * @return the tenantId value */ @@ -776,7 +776,7 @@ public String tenantId() { } /** - * Set the tenantId value. + * Set tenant ID for the policy event record. * * @param tenantId the tenantId value to set * @return the PolicyEventInner object itself. @@ -787,7 +787,7 @@ public PolicyEventInner withTenantId(String tenantId) { } /** - * Get the principalOid value. + * Get principal object ID for the user who initiated the resource operation that triggered the policy event. * * @return the principalOid value */ @@ -796,7 +796,7 @@ public String principalOid() { } /** - * Set the principalOid value. + * Set principal object ID for the user who initiated the resource operation that triggered the policy event. * * @param principalOid the principalOid value to set * @return the PolicyEventInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsImpl.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsImpl.java index 1463070709326..e8b41e3b5402d 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsImpl.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsImpl.java @@ -11,7 +11,6 @@ import com.microsoft.azure.arm.model.implementation.WrapperImpl; import com.microsoft.azure.management.policyinsights.v2018_04_04.PolicyEvents; -import rx.Completable; import rx.functions.Func1; import rx.Observable; import com.microsoft.azure.management.policyinsights.v2018_04_04.PolicyEventsQueryResults; @@ -125,9 +124,9 @@ public PolicyEventsQueryResults call(PolicyEventsQueryResultsInner inner) { } @Override - public Completable getMetadataAsync(String scope) { + public Observable getMetadataAsync(String scope) { PolicyEventsInner client = this.inner(); - return client.getMetadataAsync(scope).toCompletable(); - } + return client.getMetadataAsync(scope) + ;} } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsQueryResultsInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsQueryResultsInner.java index 230ef2d8a228b..de80da671770a 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsQueryResultsInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyEventsQueryResultsInner.java @@ -36,7 +36,7 @@ public class PolicyEventsQueryResultsInner { private List value; /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -45,7 +45,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the PolicyEventsQueryResultsInner object itself. @@ -56,7 +56,7 @@ public PolicyEventsQueryResultsInner withOdatacontext(String odatacontext) { } /** - * Get the odatacount value. + * Get oData entity count; represents the number of policy event records returned. * * @return the odatacount value */ @@ -65,7 +65,7 @@ public Integer odatacount() { } /** - * Set the odatacount value. + * Set oData entity count; represents the number of policy event records returned. * * @param odatacount the odatacount value to set * @return the PolicyEventsQueryResultsInner object itself. @@ -76,7 +76,7 @@ public PolicyEventsQueryResultsInner withOdatacount(Integer odatacount) { } /** - * Get the value value. + * Get query results. * * @return the value value */ @@ -85,7 +85,7 @@ public List value() { } /** - * Set the value value. + * Set query results. * * @param value the value value to set * @return the PolicyEventsQueryResultsInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsClientImpl.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsClientImpl.java index 522e93bb31971..d93d98979f9e1 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsClientImpl.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsClientImpl.java @@ -40,11 +40,11 @@ public String apiVersion() { return this.apiVersion; } - /** Gets or sets the preferred language for the response. */ + /** The preferred language for the response. */ private String acceptLanguage; /** - * Gets Gets or sets the preferred language for the response. + * Gets The preferred language for the response. * * @return the acceptLanguage value. */ @@ -53,7 +53,7 @@ public String acceptLanguage() { } /** - * Sets Gets or sets the preferred language for the response. + * Sets The preferred language for the response. * * @param acceptLanguage the acceptLanguage value. * @return the service client itself @@ -63,11 +63,11 @@ public PolicyInsightsClientImpl withAcceptLanguage(String acceptLanguage) { return this; } - /** Gets or sets the retry timeout in seconds for Long Running Operations. Default value is 30. */ + /** The retry timeout in seconds for Long Running Operations. Default value is 30. */ private int longRunningOperationRetryTimeout; /** - * Gets Gets or sets the retry timeout in seconds for Long Running Operations. Default value is 30. + * Gets The retry timeout in seconds for Long Running Operations. Default value is 30. * * @return the longRunningOperationRetryTimeout value. */ @@ -76,7 +76,7 @@ public int longRunningOperationRetryTimeout() { } /** - * Sets Gets or sets the retry timeout in seconds for Long Running Operations. Default value is 30. + * Sets The retry timeout in seconds for Long Running Operations. Default value is 30. * * @param longRunningOperationRetryTimeout the longRunningOperationRetryTimeout value. * @return the service client itself @@ -86,11 +86,11 @@ public PolicyInsightsClientImpl withLongRunningOperationRetryTimeout(int longRun return this; } - /** When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. */ + /** Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. */ private boolean generateClientRequestId; /** - * Gets When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * Gets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. * * @return the generateClientRequestId value. */ @@ -99,7 +99,7 @@ public boolean generateClientRequestId() { } /** - * Sets When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * Sets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. * * @param generateClientRequestId the generateClientRequestId value. * @return the service client itself @@ -196,6 +196,6 @@ protected void initialize() { */ @Override public String userAgent() { - return String.format("%s (%s, %s)", super.userAgent(), "PolicyInsightsClient", "2018-04-04"); + return String.format("%s (%s, %s, auto-generated)", super.userAgent(), "PolicyInsightsClient", "2018-04-04"); } } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsManager.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsManager.java index 92a91f68bb7b1..38d9c20f48ba4 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsManager.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyInsightsManager.java @@ -11,6 +11,8 @@ import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.AzureResponseBuilder; import com.microsoft.azure.credentials.AzureTokenCredentials; +import com.microsoft.azure.management.apigeneration.Beta; +import com.microsoft.azure.management.apigeneration.Beta.SinceVersion; import com.microsoft.azure.arm.resources.AzureConfigurable; import com.microsoft.azure.serializer.AzureJacksonAdapter; import com.microsoft.rest.RestClient; diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStateInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStateInner.java index 95dab2022a185..8c0be8d3d4e18 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStateInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStateInner.java @@ -180,7 +180,7 @@ public class PolicyStateInner { private String policySetDefinitionParameters; /** - * Comma seperated list of management group IDs, which represent the + * Comma separated list of management group IDs, which represent the * hierarchy of the management groups the resource is under. */ @JsonProperty(value = "managementGroupIds") @@ -194,7 +194,7 @@ public class PolicyStateInner { private String policyDefinitionReferenceId; /** - * Get the additionalProperties value. + * Get unmatched properties from the message are deserialized this collection. * * @return the additionalProperties value */ @@ -203,7 +203,7 @@ public Map additionalProperties() { } /** - * Set the additionalProperties value. + * Set unmatched properties from the message are deserialized this collection. * * @param additionalProperties the additionalProperties value to set * @return the PolicyStateInner object itself. @@ -214,7 +214,7 @@ public PolicyStateInner withAdditionalProperties(Map additionalP } /** - * Get the odataid value. + * Get oData entity ID; always set to null since policy state records do not have an entity ID. * * @return the odataid value */ @@ -223,7 +223,7 @@ public String odataid() { } /** - * Set the odataid value. + * Set oData entity ID; always set to null since policy state records do not have an entity ID. * * @param odataid the odataid value to set * @return the PolicyStateInner object itself. @@ -234,7 +234,7 @@ public PolicyStateInner withOdataid(String odataid) { } /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -243,7 +243,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the PolicyStateInner object itself. @@ -254,7 +254,7 @@ public PolicyStateInner withOdatacontext(String odatacontext) { } /** - * Get the timestamp value. + * Get timestamp for the policy state record. * * @return the timestamp value */ @@ -263,7 +263,7 @@ public DateTime timestamp() { } /** - * Set the timestamp value. + * Set timestamp for the policy state record. * * @param timestamp the timestamp value to set * @return the PolicyStateInner object itself. @@ -274,7 +274,7 @@ public PolicyStateInner withTimestamp(DateTime timestamp) { } /** - * Get the resourceId value. + * Get resource ID. * * @return the resourceId value */ @@ -283,7 +283,7 @@ public String resourceId() { } /** - * Set the resourceId value. + * Set resource ID. * * @param resourceId the resourceId value to set * @return the PolicyStateInner object itself. @@ -294,7 +294,7 @@ public PolicyStateInner withResourceId(String resourceId) { } /** - * Get the policyAssignmentId value. + * Get policy assignment ID. * * @return the policyAssignmentId value */ @@ -303,7 +303,7 @@ public String policyAssignmentId() { } /** - * Set the policyAssignmentId value. + * Set policy assignment ID. * * @param policyAssignmentId the policyAssignmentId value to set * @return the PolicyStateInner object itself. @@ -314,7 +314,7 @@ public PolicyStateInner withPolicyAssignmentId(String policyAssignmentId) { } /** - * Get the policyDefinitionId value. + * Get policy definition ID. * * @return the policyDefinitionId value */ @@ -323,7 +323,7 @@ public String policyDefinitionId() { } /** - * Set the policyDefinitionId value. + * Set policy definition ID. * * @param policyDefinitionId the policyDefinitionId value to set * @return the PolicyStateInner object itself. @@ -334,7 +334,7 @@ public PolicyStateInner withPolicyDefinitionId(String policyDefinitionId) { } /** - * Get the effectiveParameters value. + * Get effective parameters for the policy assignment. * * @return the effectiveParameters value */ @@ -343,7 +343,7 @@ public String effectiveParameters() { } /** - * Set the effectiveParameters value. + * Set effective parameters for the policy assignment. * * @param effectiveParameters the effectiveParameters value to set * @return the PolicyStateInner object itself. @@ -354,7 +354,7 @@ public PolicyStateInner withEffectiveParameters(String effectiveParameters) { } /** - * Get the isCompliant value. + * Get flag which states whether the resource is compliant against the policy assignment it was evaluated against. * * @return the isCompliant value */ @@ -363,7 +363,7 @@ public Boolean isCompliant() { } /** - * Set the isCompliant value. + * Set flag which states whether the resource is compliant against the policy assignment it was evaluated against. * * @param isCompliant the isCompliant value to set * @return the PolicyStateInner object itself. @@ -374,7 +374,7 @@ public PolicyStateInner withIsCompliant(Boolean isCompliant) { } /** - * Get the subscriptionId value. + * Get subscription ID. * * @return the subscriptionId value */ @@ -383,7 +383,7 @@ public String subscriptionId() { } /** - * Set the subscriptionId value. + * Set subscription ID. * * @param subscriptionId the subscriptionId value to set * @return the PolicyStateInner object itself. @@ -394,7 +394,7 @@ public PolicyStateInner withSubscriptionId(String subscriptionId) { } /** - * Get the resourceType value. + * Get resource type. * * @return the resourceType value */ @@ -403,7 +403,7 @@ public String resourceType() { } /** - * Set the resourceType value. + * Set resource type. * * @param resourceType the resourceType value to set * @return the PolicyStateInner object itself. @@ -414,7 +414,7 @@ public PolicyStateInner withResourceType(String resourceType) { } /** - * Get the resourceLocation value. + * Get resource location. * * @return the resourceLocation value */ @@ -423,7 +423,7 @@ public String resourceLocation() { } /** - * Set the resourceLocation value. + * Set resource location. * * @param resourceLocation the resourceLocation value to set * @return the PolicyStateInner object itself. @@ -434,7 +434,7 @@ public PolicyStateInner withResourceLocation(String resourceLocation) { } /** - * Get the resourceGroup value. + * Get resource group name. * * @return the resourceGroup value */ @@ -443,7 +443,7 @@ public String resourceGroup() { } /** - * Set the resourceGroup value. + * Set resource group name. * * @param resourceGroup the resourceGroup value to set * @return the PolicyStateInner object itself. @@ -454,7 +454,7 @@ public PolicyStateInner withResourceGroup(String resourceGroup) { } /** - * Get the resourceTags value. + * Get list of resource tags. * * @return the resourceTags value */ @@ -463,7 +463,7 @@ public String resourceTags() { } /** - * Set the resourceTags value. + * Set list of resource tags. * * @param resourceTags the resourceTags value to set * @return the PolicyStateInner object itself. @@ -474,7 +474,7 @@ public PolicyStateInner withResourceTags(String resourceTags) { } /** - * Get the policyAssignmentName value. + * Get policy assignment name. * * @return the policyAssignmentName value */ @@ -483,7 +483,7 @@ public String policyAssignmentName() { } /** - * Set the policyAssignmentName value. + * Set policy assignment name. * * @param policyAssignmentName the policyAssignmentName value to set * @return the PolicyStateInner object itself. @@ -494,7 +494,7 @@ public PolicyStateInner withPolicyAssignmentName(String policyAssignmentName) { } /** - * Get the policyAssignmentOwner value. + * Get policy assignment owner. * * @return the policyAssignmentOwner value */ @@ -503,7 +503,7 @@ public String policyAssignmentOwner() { } /** - * Set the policyAssignmentOwner value. + * Set policy assignment owner. * * @param policyAssignmentOwner the policyAssignmentOwner value to set * @return the PolicyStateInner object itself. @@ -514,7 +514,7 @@ public PolicyStateInner withPolicyAssignmentOwner(String policyAssignmentOwner) } /** - * Get the policyAssignmentParameters value. + * Get policy assignment parameters. * * @return the policyAssignmentParameters value */ @@ -523,7 +523,7 @@ public String policyAssignmentParameters() { } /** - * Set the policyAssignmentParameters value. + * Set policy assignment parameters. * * @param policyAssignmentParameters the policyAssignmentParameters value to set * @return the PolicyStateInner object itself. @@ -534,7 +534,7 @@ public PolicyStateInner withPolicyAssignmentParameters(String policyAssignmentPa } /** - * Get the policyAssignmentScope value. + * Get policy assignment scope. * * @return the policyAssignmentScope value */ @@ -543,7 +543,7 @@ public String policyAssignmentScope() { } /** - * Set the policyAssignmentScope value. + * Set policy assignment scope. * * @param policyAssignmentScope the policyAssignmentScope value to set * @return the PolicyStateInner object itself. @@ -554,7 +554,7 @@ public PolicyStateInner withPolicyAssignmentScope(String policyAssignmentScope) } /** - * Get the policyDefinitionName value. + * Get policy definition name. * * @return the policyDefinitionName value */ @@ -563,7 +563,7 @@ public String policyDefinitionName() { } /** - * Set the policyDefinitionName value. + * Set policy definition name. * * @param policyDefinitionName the policyDefinitionName value to set * @return the PolicyStateInner object itself. @@ -574,7 +574,7 @@ public PolicyStateInner withPolicyDefinitionName(String policyDefinitionName) { } /** - * Get the policyDefinitionAction value. + * Get policy definition action, i.e. effect. * * @return the policyDefinitionAction value */ @@ -583,7 +583,7 @@ public String policyDefinitionAction() { } /** - * Set the policyDefinitionAction value. + * Set policy definition action, i.e. effect. * * @param policyDefinitionAction the policyDefinitionAction value to set * @return the PolicyStateInner object itself. @@ -594,7 +594,7 @@ public PolicyStateInner withPolicyDefinitionAction(String policyDefinitionAction } /** - * Get the policyDefinitionCategory value. + * Get policy definition category. * * @return the policyDefinitionCategory value */ @@ -603,7 +603,7 @@ public String policyDefinitionCategory() { } /** - * Set the policyDefinitionCategory value. + * Set policy definition category. * * @param policyDefinitionCategory the policyDefinitionCategory value to set * @return the PolicyStateInner object itself. @@ -614,7 +614,7 @@ public PolicyStateInner withPolicyDefinitionCategory(String policyDefinitionCate } /** - * Get the policySetDefinitionId value. + * Get policy set definition ID, if the policy assignment is for a policy set. * * @return the policySetDefinitionId value */ @@ -623,7 +623,7 @@ public String policySetDefinitionId() { } /** - * Set the policySetDefinitionId value. + * Set policy set definition ID, if the policy assignment is for a policy set. * * @param policySetDefinitionId the policySetDefinitionId value to set * @return the PolicyStateInner object itself. @@ -634,7 +634,7 @@ public PolicyStateInner withPolicySetDefinitionId(String policySetDefinitionId) } /** - * Get the policySetDefinitionName value. + * Get policy set definition name, if the policy assignment is for a policy set. * * @return the policySetDefinitionName value */ @@ -643,7 +643,7 @@ public String policySetDefinitionName() { } /** - * Set the policySetDefinitionName value. + * Set policy set definition name, if the policy assignment is for a policy set. * * @param policySetDefinitionName the policySetDefinitionName value to set * @return the PolicyStateInner object itself. @@ -654,7 +654,7 @@ public PolicyStateInner withPolicySetDefinitionName(String policySetDefinitionNa } /** - * Get the policySetDefinitionOwner value. + * Get policy set definition owner, if the policy assignment is for a policy set. * * @return the policySetDefinitionOwner value */ @@ -663,7 +663,7 @@ public String policySetDefinitionOwner() { } /** - * Set the policySetDefinitionOwner value. + * Set policy set definition owner, if the policy assignment is for a policy set. * * @param policySetDefinitionOwner the policySetDefinitionOwner value to set * @return the PolicyStateInner object itself. @@ -674,7 +674,7 @@ public PolicyStateInner withPolicySetDefinitionOwner(String policySetDefinitionO } /** - * Get the policySetDefinitionCategory value. + * Get policy set definition category, if the policy assignment is for a policy set. * * @return the policySetDefinitionCategory value */ @@ -683,7 +683,7 @@ public String policySetDefinitionCategory() { } /** - * Set the policySetDefinitionCategory value. + * Set policy set definition category, if the policy assignment is for a policy set. * * @param policySetDefinitionCategory the policySetDefinitionCategory value to set * @return the PolicyStateInner object itself. @@ -694,7 +694,7 @@ public PolicyStateInner withPolicySetDefinitionCategory(String policySetDefiniti } /** - * Get the policySetDefinitionParameters value. + * Get policy set definition parameters, if the policy assignment is for a policy set. * * @return the policySetDefinitionParameters value */ @@ -703,7 +703,7 @@ public String policySetDefinitionParameters() { } /** - * Set the policySetDefinitionParameters value. + * Set policy set definition parameters, if the policy assignment is for a policy set. * * @param policySetDefinitionParameters the policySetDefinitionParameters value to set * @return the PolicyStateInner object itself. @@ -714,7 +714,7 @@ public PolicyStateInner withPolicySetDefinitionParameters(String policySetDefini } /** - * Get the managementGroupIds value. + * Get comma separated list of management group IDs, which represent the hierarchy of the management groups the resource is under. * * @return the managementGroupIds value */ @@ -723,7 +723,7 @@ public String managementGroupIds() { } /** - * Set the managementGroupIds value. + * Set comma separated list of management group IDs, which represent the hierarchy of the management groups the resource is under. * * @param managementGroupIds the managementGroupIds value to set * @return the PolicyStateInner object itself. @@ -734,7 +734,7 @@ public PolicyStateInner withManagementGroupIds(String managementGroupIds) { } /** - * Get the policyDefinitionReferenceId value. + * Get reference ID for the policy definition inside the policy set, if the policy assignment is for a policy set. * * @return the policyDefinitionReferenceId value */ @@ -743,7 +743,7 @@ public String policyDefinitionReferenceId() { } /** - * Set the policyDefinitionReferenceId value. + * Set reference ID for the policy definition inside the policy set, if the policy assignment is for a policy set. * * @param policyDefinitionReferenceId the policyDefinitionReferenceId value to set * @return the PolicyStateInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesImpl.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesImpl.java index f0a85106b6bff..afeb77c41c742 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesImpl.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesImpl.java @@ -11,7 +11,6 @@ import com.microsoft.azure.arm.model.implementation.WrapperImpl; import com.microsoft.azure.management.policyinsights.v2018_04_04.PolicyStates; -import rx.Completable; import rx.functions.Func1; import rx.Observable; import com.microsoft.azure.management.policyinsights.v2018_04_04.PolicyStatesQueryResults; @@ -223,9 +222,9 @@ public SummarizeResults call(SummarizeResultsInner inner) { } @Override - public Completable getMetadataAsync(String scope) { + public Observable getMetadataAsync(String scope) { PolicyStatesInner client = this.inner(); - return client.getMetadataAsync(scope).toCompletable(); - } + return client.getMetadataAsync(scope) + ;} } diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesQueryResultsInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesQueryResultsInner.java index ec2abe0f9bd59..730e6bc06a2be 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesQueryResultsInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/PolicyStatesQueryResultsInner.java @@ -36,7 +36,7 @@ public class PolicyStatesQueryResultsInner { private List value; /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -45,7 +45,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the PolicyStatesQueryResultsInner object itself. @@ -56,7 +56,7 @@ public PolicyStatesQueryResultsInner withOdatacontext(String odatacontext) { } /** - * Get the odatacount value. + * Get oData entity count; represents the number of policy state records returned. * * @return the odatacount value */ @@ -65,7 +65,7 @@ public Integer odatacount() { } /** - * Set the odatacount value. + * Set oData entity count; represents the number of policy state records returned. * * @param odatacount the odatacount value to set * @return the PolicyStatesQueryResultsInner object itself. @@ -76,7 +76,7 @@ public PolicyStatesQueryResultsInner withOdatacount(Integer odatacount) { } /** - * Get the value value. + * Get query results. * * @return the value value */ @@ -85,7 +85,7 @@ public List value() { } /** - * Set the value value. + * Set query results. * * @param value the value value to set * @return the PolicyStatesQueryResultsInner object itself. diff --git a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/SummarizeResultsInner.java b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/SummarizeResultsInner.java index be6ac29ed6624..03df7898859fb 100644 --- a/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/SummarizeResultsInner.java +++ b/policyinsights/resource-manager/v2018_04_04/src/main/java/com/microsoft/azure/management/policyinsights/v2018_04_04/implementation/SummarizeResultsInner.java @@ -37,7 +37,7 @@ public class SummarizeResultsInner { private List value; /** - * Get the odatacontext value. + * Get oData context string; used by OData clients to resolve type information based on metadata. * * @return the odatacontext value */ @@ -46,7 +46,7 @@ public String odatacontext() { } /** - * Set the odatacontext value. + * Set oData context string; used by OData clients to resolve type information based on metadata. * * @param odatacontext the odatacontext value to set * @return the SummarizeResultsInner object itself. @@ -57,7 +57,7 @@ public SummarizeResultsInner withOdatacontext(String odatacontext) { } /** - * Get the odatacount value. + * Get oData entity count; represents the number of summaries returned; always set to 1. * * @return the odatacount value */ @@ -66,7 +66,7 @@ public Integer odatacount() { } /** - * Set the odatacount value. + * Set oData entity count; represents the number of summaries returned; always set to 1. * * @param odatacount the odatacount value to set * @return the SummarizeResultsInner object itself. @@ -77,7 +77,7 @@ public SummarizeResultsInner withOdatacount(Integer odatacount) { } /** - * Get the value value. + * Get summarize action results. * * @return the value value */ @@ -86,7 +86,7 @@ public List value() { } /** - * Set the value value. + * Set summarize action results. * * @param value the value value to set * @return the SummarizeResultsInner object itself. diff --git a/pom.client.xml b/pom.client.xml index 5979de4e41b1f..b09118509b848 100644 --- a/pom.client.xml +++ b/pom.client.xml @@ -6,7 +6,7 @@ com.azure azure-client-sdk-parent pom - 1.0.0 + 1.1.0 Microsoft Azure SDK for Java - Client Libraries Parent POM for Microsoft Azure SDK for Java @@ -19,7 +19,7 @@ com.azure azure-sdk-parent - 1.0.0 + 1.1.0 ./parent/pom.xml @@ -132,10 +132,8 @@ true true true - - - false - false + true + true @@ -151,13 +149,18 @@ com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} com.azure sdk-build-tools ${sdk-build-tools.version} + + com.github.spotbugs + spotbugs + ${spotbugs.version} + Max @@ -165,9 +168,7 @@ true ${project.build.directory}/spotbugs spotbugs/spotbugs-exclude.xml - - - false + true @@ -196,7 +197,9 @@ ${project.build.directory}/spotbugs - spotbugsXml.xml + + spotbugsXml.xml + ${project.build.directory}/spotbugs fancy-hist.xsl @@ -237,7 +240,8 @@ ${packageOutputDirectory} - + true + true @@ -331,7 +335,9 @@ Azure SDK for Java Reference Documentation Azure SDK for Java Reference Documentation false -
Visit the <a href="https://docs.microsoft.com/java/azure/">Azure for Java Developers</a>site for more Java documentation, including quick starts, tutorials, and code samples.
+
Visit the <a href="https://docs.microsoft.com/java/azure/">Azure for Java Developers</a>site + for more Java documentation, including quick starts, tutorials, and code samples. +
false com.microsoft.azure.template: @@ -343,7 +349,9 @@ Azure Core - com.azure.core:com.azure.core.annotations:com.azure.core.credentials:com.azure.core.exception:com.azure.core.http*:com.azure.core.configuration:com.azure.core.util* + + com.azure.core:com.azure.core.annotations:com.azure.core.credentials:com.azure.core.exception:com.azure.core.http*:com.azure.core.configuration:com.azure.core.util* + Azure Core - AMQP @@ -377,6 +385,10 @@ Azure Key Vault com.azure.security.keyvault* + + Azure Storage - Blobs + com.azure.storage.blob* + https://docs.oracle.com/javase/8/docs/api/ @@ -392,21 +404,26 @@ ${codesnippet4javadoc.version} -maxLineLength 120 -snippetpath ${project.basedir}/src/samples/java - true - true + false + false
com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} com.azure sdk-build-tools ${sdk-build-tools.version} + + com.github.spotbugs + spotbugs + ${spotbugs.version} + Max @@ -460,6 +477,8 @@ true true true + true + true @@ -480,7 +499,7 @@ com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} non-aggregate @@ -586,8 +605,12 @@ 1.8 1.8 true - true - -Xlint:all + true + + -Xlint:all + -Xlint:-serial + -Xlint:-deprecation + @@ -611,8 +634,12 @@ 11 11 true - true - -Xlint:all + true + + -Xlint:all + -Xlint:-serial + -Xlint:-deprecation + @@ -641,6 +668,9 @@ + javadoc-doclet-compatibility @@ -652,10 +682,6 @@ org.apache.maven.plugins maven-javadoc-plugin - - false + + ./sdk/identity/azure-identity + ./storage/client/blob diff --git a/pom.data.xml b/pom.data.xml index 754a9e3286be0..90cec2fac80be 100644 --- a/pom.data.xml +++ b/pom.data.xml @@ -6,7 +6,7 @@ com.azure azure-data-sdk-parent pom - 1.0.0 + 1.1.0 Microsoft Azure SDK for Java - Data Plane Libraries Parent POM for Microsoft Azure SDK for Java @@ -19,7 +19,7 @@ com.azure azure-sdk-parent - 1.0.0 + 1.1.0 ./parent/pom.xml @@ -110,7 +110,7 @@ com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} com.azure @@ -293,7 +293,7 @@ com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} com.azure @@ -369,7 +369,7 @@ com.github.spotbugs spotbugs-maven-plugin - ${spotbugs.version} + ${spotbugs.maven.version} non-aggregate @@ -543,7 +543,7 @@ ./sdk/batch/microsoft-azure-batch ./eventhubs/data-plane - ./keyvault/data-plane + ./sdk/keyvault/pom.data.xml ./sdk/servicebus ./storage/data-plane diff --git a/pom.management.xml b/pom.management.xml index b3e54a8c50355..42f888594ed23 100644 --- a/pom.management.xml +++ b/pom.management.xml @@ -21,7 +21,7 @@ com.azure azure-sdk-parent - 1.0.0 + 1.1.0 ./parent/pom.xml diff --git a/pom.xml b/pom.xml index 04446fa2474fa..125c326f84890 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ com.azure azure-sdk-parent - 1.0.0 + 1.1.0 ./parent/pom.xml diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/pom.xml b/recoveryservices.backup/resource-manager/v2016_08_10/pom.xml new file mode 100644 index 0000000000000..27c7ec3c99c98 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + com.microsoft.azure.recoveryservices.backup.v2016_08_10 + + com.microsoft.azure + azure-arm-parent + 1.1.0 + ../../../pom.management.xml + + azure-mgmt-recoveryservices + 1.0.0-beta + jar + Microsoft Azure SDK for RecoveryServices Management + This package contains Microsoft RecoveryServices Management SDK. + https://github.com/Azure/azure-sdk-for-java + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + UTF-8 + + + + + microsoft + Microsoft + + + + + com.microsoft.azure + azure-client-runtime + + + com.microsoft.azure + azure-arm-client-runtime + + + junit + junit + test + + + com.microsoft.azure + azure-client-authentication + test + + + com.microsoft.azure + azure-mgmt-resources + test + + + com.microsoft.azure + azure-arm-client-runtime + test-jar + test + + 1.6.5 + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + com.microsoft.azure.management.apigeneration.LangDefinitionProcessor + + + true + true + + true + true + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization;*.blob.core.search + + + /** +
* Copyright (c) Microsoft Corporation. All rights reserved. +
* Licensed under the MIT License. See License.txt in the project root for +
* license information. +
*/ + ]]> +
+
+
+
+
+
diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryDisplay.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryDisplay.java new file mode 100644 index 0000000000000..04ce825d5954a --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryDisplay.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Localized display information of an operation. + */ +public class ClientDiscoveryDisplay { + /** + * Name of the provider for display purposes. + */ + @JsonProperty(value = "provider") + private String provider; + + /** + * ResourceType for which this Operation can be performed. + */ + @JsonProperty(value = "resource") + private String resource; + + /** + * Operations Name itself. + */ + @JsonProperty(value = "operation") + private String operation; + + /** + * Description of the operation having details of what operation is about. + */ + @JsonProperty(value = "description") + private String description; + + /** + * Get name of the provider for display purposes. + * + * @return the provider value + */ + public String provider() { + return this.provider; + } + + /** + * Set name of the provider for display purposes. + * + * @param provider the provider value to set + * @return the ClientDiscoveryDisplay object itself. + */ + public ClientDiscoveryDisplay withProvider(String provider) { + this.provider = provider; + return this; + } + + /** + * Get resourceType for which this Operation can be performed. + * + * @return the resource value + */ + public String resource() { + return this.resource; + } + + /** + * Set resourceType for which this Operation can be performed. + * + * @param resource the resource value to set + * @return the ClientDiscoveryDisplay object itself. + */ + public ClientDiscoveryDisplay withResource(String resource) { + this.resource = resource; + return this; + } + + /** + * Get operations Name itself. + * + * @return the operation value + */ + public String operation() { + return this.operation; + } + + /** + * Set operations Name itself. + * + * @param operation the operation value to set + * @return the ClientDiscoveryDisplay object itself. + */ + public ClientDiscoveryDisplay withOperation(String operation) { + this.operation = operation; + return this; + } + + /** + * Get description of the operation having details of what operation is about. + * + * @return the description value + */ + public String description() { + return this.description; + } + + /** + * Set description of the operation having details of what operation is about. + * + * @param description the description value to set + * @return the ClientDiscoveryDisplay object itself. + */ + public ClientDiscoveryDisplay withDescription(String description) { + this.description = description; + return this; + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForLogSpecification.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForLogSpecification.java new file mode 100644 index 0000000000000..b10032623cd84 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForLogSpecification.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Class to represent shoebox log specification in json client discovery. + */ +public class ClientDiscoveryForLogSpecification { + /** + * Name for shoebox log specification. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Localized display name. + */ + @JsonProperty(value = "displayName") + private String displayName; + + /** + * blob duration of shoebox log specification. + */ + @JsonProperty(value = "blobDuration") + private String blobDuration; + + /** + * Get name for shoebox log specification. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set name for shoebox log specification. + * + * @param name the name value to set + * @return the ClientDiscoveryForLogSpecification object itself. + */ + public ClientDiscoveryForLogSpecification withName(String name) { + this.name = name; + return this; + } + + /** + * Get localized display name. + * + * @return the displayName value + */ + public String displayName() { + return this.displayName; + } + + /** + * Set localized display name. + * + * @param displayName the displayName value to set + * @return the ClientDiscoveryForLogSpecification object itself. + */ + public ClientDiscoveryForLogSpecification withDisplayName(String displayName) { + this.displayName = displayName; + return this; + } + + /** + * Get blob duration of shoebox log specification. + * + * @return the blobDuration value + */ + public String blobDuration() { + return this.blobDuration; + } + + /** + * Set blob duration of shoebox log specification. + * + * @param blobDuration the blobDuration value to set + * @return the ClientDiscoveryForLogSpecification object itself. + */ + public ClientDiscoveryForLogSpecification withBlobDuration(String blobDuration) { + this.blobDuration = blobDuration; + return this; + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForProperties.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForProperties.java new file mode 100644 index 0000000000000..a60fd82f02db4 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Class to represent shoebox properties in json client discovery. + */ +public class ClientDiscoveryForProperties { + /** + * Operation properties. + */ + @JsonProperty(value = "serviceSpecification") + private ClientDiscoveryForServiceSpecification serviceSpecification; + + /** + * Get operation properties. + * + * @return the serviceSpecification value + */ + public ClientDiscoveryForServiceSpecification serviceSpecification() { + return this.serviceSpecification; + } + + /** + * Set operation properties. + * + * @param serviceSpecification the serviceSpecification value to set + * @return the ClientDiscoveryForProperties object itself. + */ + public ClientDiscoveryForProperties withServiceSpecification(ClientDiscoveryForServiceSpecification serviceSpecification) { + this.serviceSpecification = serviceSpecification; + return this; + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForServiceSpecification.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForServiceSpecification.java new file mode 100644 index 0000000000000..10751babda68c --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryForServiceSpecification.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Class to represent shoebox service specification in json client discovery. + */ +public class ClientDiscoveryForServiceSpecification { + /** + * List of log specifications of this operation. + */ + @JsonProperty(value = "logSpecifications") + private List logSpecifications; + + /** + * Get list of log specifications of this operation. + * + * @return the logSpecifications value + */ + public List logSpecifications() { + return this.logSpecifications; + } + + /** + * Set list of log specifications of this operation. + * + * @param logSpecifications the logSpecifications value to set + * @return the ClientDiscoveryForServiceSpecification object itself. + */ + public ClientDiscoveryForServiceSpecification withLogSpecifications(List logSpecifications) { + this.logSpecifications = logSpecifications; + return this; + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryValueForSingleApi.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryValueForSingleApi.java new file mode 100644 index 0000000000000..c26975aa6ee8b --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/ClientDiscoveryValueForSingleApi.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation.RecoveryServicesManager; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation.ClientDiscoveryValueForSingleApiInner; + +/** + * Type representing ClientDiscoveryValueForSingleApi. + */ +public interface ClientDiscoveryValueForSingleApi extends HasInner, HasManager { + /** + * @return the display value. + */ + ClientDiscoveryDisplay display(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the origin value. + */ + String origin(); + + /** + * @return the properties value. + */ + ClientDiscoveryForProperties properties(); + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/Operations.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/Operations.java new file mode 100644 index 0000000000000..5f99e0af292f6 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/Operations.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation.OperationsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing Operations. + */ +public interface Operations extends HasInner { + /** + * Returns the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiImpl.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiImpl.java new file mode 100644 index 0000000000000..eb81b1001b768 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiImpl.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryValueForSingleApi; +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryDisplay; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryForProperties; + +class ClientDiscoveryValueForSingleApiImpl extends WrapperImpl implements ClientDiscoveryValueForSingleApi { + private final RecoveryServicesManager manager; + ClientDiscoveryValueForSingleApiImpl(ClientDiscoveryValueForSingleApiInner inner, RecoveryServicesManager manager) { + super(inner); + this.manager = manager; + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public ClientDiscoveryDisplay display() { + return this.inner().display(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public String origin() { + return this.inner().origin(); + } + + @Override + public ClientDiscoveryForProperties properties() { + return this.inner().properties(); + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiInner.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiInner.java new file mode 100644 index 0000000000000..befce18db34e3 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/ClientDiscoveryValueForSingleApiInner.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryDisplay; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryForProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Available operation details. + */ +public class ClientDiscoveryValueForSingleApiInner { + /** + * Name of the Operation. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Contains the localized display information for this particular + * operation. + */ + @JsonProperty(value = "display") + private ClientDiscoveryDisplay display; + + /** + * The intended executor of the operation;governs the display of the + * operation in the RBAC UX and the audit logs UX. + */ + @JsonProperty(value = "origin") + private String origin; + + /** + * ShoeBox properties for the given operation. + */ + @JsonProperty(value = "properties") + private ClientDiscoveryForProperties properties; + + /** + * Get name of the Operation. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set name of the Operation. + * + * @param name the name value to set + * @return the ClientDiscoveryValueForSingleApiInner object itself. + */ + public ClientDiscoveryValueForSingleApiInner withName(String name) { + this.name = name; + return this; + } + + /** + * Get contains the localized display information for this particular operation. + * + * @return the display value + */ + public ClientDiscoveryDisplay display() { + return this.display; + } + + /** + * Set contains the localized display information for this particular operation. + * + * @param display the display value to set + * @return the ClientDiscoveryValueForSingleApiInner object itself. + */ + public ClientDiscoveryValueForSingleApiInner withDisplay(ClientDiscoveryDisplay display) { + this.display = display; + return this; + } + + /** + * Get the intended executor of the operation;governs the display of the operation in the RBAC UX and the audit logs UX. + * + * @return the origin value + */ + public String origin() { + return this.origin; + } + + /** + * Set the intended executor of the operation;governs the display of the operation in the RBAC UX and the audit logs UX. + * + * @param origin the origin value to set + * @return the ClientDiscoveryValueForSingleApiInner object itself. + */ + public ClientDiscoveryValueForSingleApiInner withOrigin(String origin) { + this.origin = origin; + return this; + } + + /** + * Get shoeBox properties for the given operation. + * + * @return the properties value + */ + public ClientDiscoveryForProperties properties() { + return this.properties; + } + + /** + * Set shoeBox properties for the given operation. + * + * @param properties the properties value to set + * @return the ClientDiscoveryValueForSingleApiInner object itself. + */ + public ClientDiscoveryValueForSingleApiInner withProperties(ClientDiscoveryForProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/IdParsingUtils.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/IdParsingUtils.java new file mode 100644 index 0000000000000..c66f66e65f716 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/IdParsingUtils.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; +import java.util.Arrays; +import java.util.Iterator; + +class IdParsingUtils { + public static String getValueFromIdByName(String id, String name) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (part.equalsIgnoreCase(name)) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + } + return null; + } + + public static String getValueFromIdByPosition(String id, int pos) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + int index = 0; + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (index == pos) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + index++; + } + return null; + } +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsImpl.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsImpl.java new file mode 100644 index 0000000000000..a6f7f3cc78af9 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsImpl.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * abc + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.Operations; +import rx.functions.Func1; +import rx.Observable; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.ClientDiscoveryValueForSingleApi; + +class OperationsImpl extends WrapperImpl implements Operations { + private final RecoveryServicesManager manager; + + OperationsImpl(RecoveryServicesManager manager) { + super(manager.inner().operations()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable listAsync() { + OperationsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ClientDiscoveryValueForSingleApi call(ClientDiscoveryValueForSingleApiInner inner) { + return new ClientDiscoveryValueForSingleApiImpl(inner, manager()); + } + }); + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsInner.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsInner.java new file mode 100644 index 0000000000000..e27d87748ec3a --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/OperationsInner.java @@ -0,0 +1,283 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in Operations. + */ +public class OperationsInner { + /** The Retrofit service to perform REST calls. */ + private OperationsService service; + /** The service client containing this operation class. */ + private RecoveryServicesBackupClientImpl client; + + /** + * Initializes an instance of OperationsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public OperationsInner(Retrofit retrofit, RecoveryServicesBackupClientImpl client) { + this.service = retrofit.create(OperationsService.class); + this.client = client; + } + + /** + * The interface defining all the services for Operations to be + * used by Retrofit to perform actually REST calls. + */ + interface OperationsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.Operations list" }) + @GET("providers/Microsoft.RecoveryServices/operations") + Observable> list(@Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.Operations listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Returns the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ClientDiscoveryValueForSingleApiInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Returns the list of available operations. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Returns the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ClientDiscoveryValueForSingleApiInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Returns the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ClientDiscoveryValueForSingleApiInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Returns the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ClientDiscoveryValueForSingleApiInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Returns the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ClientDiscoveryValueForSingleApiInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Returns the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Returns the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ClientDiscoveryValueForSingleApiInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Returns the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ClientDiscoveryValueForSingleApiInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Returns the list of available operations. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ClientDiscoveryValueForSingleApiInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/PageImpl.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/PageImpl.java new file mode 100644 index 0000000000000..963a8fcb43780 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/PageImpl.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.Page; +import java.util.List; + +/** + * An instance of this class defines a page of Azure resources and a link to + * get the next page of resources, if any. + * + * @param type of Azure resource + */ +public class PageImpl implements Page { + /** + * The link to the next page. + */ + @JsonProperty("nextLink") + private String nextPageLink; + + /** + * The list of items. + */ + @JsonProperty("value") + private List items; + + /** + * Gets the link to the next page. + * + * @return the link to the next page. + */ + @Override + public String nextPageLink() { + return this.nextPageLink; + } + + /** + * Gets the list of items. + * + * @return the list of items in {@link List}. + */ + @Override + public List items() { + return items; + } + + /** + * Sets the link to the next page. + * + * @param nextPageLink the link to the next page. + * @return this Page object itself. + */ + public PageImpl setNextPageLink(String nextPageLink) { + this.nextPageLink = nextPageLink; + return this; + } + + /** + * Sets the list of items. + * + * @param items the list of items in {@link List}. + * @return this Page object itself. + */ + public PageImpl setItems(List items) { + this.items = items; + return this; + } +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesBackupClientImpl.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesBackupClientImpl.java new file mode 100644 index 0000000000000..5bc6ebefbe494 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesBackupClientImpl.java @@ -0,0 +1,173 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.microsoft.azure.AzureClient; +import com.microsoft.azure.AzureServiceClient; +import com.microsoft.rest.credentials.ServiceClientCredentials; +import com.microsoft.rest.RestClient; + +/** + * Initializes a new instance of the RecoveryServicesBackupClientImpl class. + */ +public class RecoveryServicesBackupClientImpl extends AzureServiceClient { + /** the {@link AzureClient} used for long running operations. */ + private AzureClient azureClient; + + /** + * Gets the {@link AzureClient} used for long running operations. + * @return the azure client; + */ + public AzureClient getAzureClient() { + return this.azureClient; + } + + /** Client Api Version. */ + private String apiVersion; + + /** + * Gets Client Api Version. + * + * @return the apiVersion value. + */ + public String apiVersion() { + return this.apiVersion; + } + + /** The preferred language for the response. */ + private String acceptLanguage; + + /** + * Gets The preferred language for the response. + * + * @return the acceptLanguage value. + */ + public String acceptLanguage() { + return this.acceptLanguage; + } + + /** + * Sets The preferred language for the response. + * + * @param acceptLanguage the acceptLanguage value. + * @return the service client itself + */ + public RecoveryServicesBackupClientImpl withAcceptLanguage(String acceptLanguage) { + this.acceptLanguage = acceptLanguage; + return this; + } + + /** The retry timeout in seconds for Long Running Operations. Default value is 30. */ + private int longRunningOperationRetryTimeout; + + /** + * Gets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @return the longRunningOperationRetryTimeout value. + */ + public int longRunningOperationRetryTimeout() { + return this.longRunningOperationRetryTimeout; + } + + /** + * Sets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @param longRunningOperationRetryTimeout the longRunningOperationRetryTimeout value. + * @return the service client itself + */ + public RecoveryServicesBackupClientImpl withLongRunningOperationRetryTimeout(int longRunningOperationRetryTimeout) { + this.longRunningOperationRetryTimeout = longRunningOperationRetryTimeout; + return this; + } + + /** Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. */ + private boolean generateClientRequestId; + + /** + * Gets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @return the generateClientRequestId value. + */ + public boolean generateClientRequestId() { + return this.generateClientRequestId; + } + + /** + * Sets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @param generateClientRequestId the generateClientRequestId value. + * @return the service client itself + */ + public RecoveryServicesBackupClientImpl withGenerateClientRequestId(boolean generateClientRequestId) { + this.generateClientRequestId = generateClientRequestId; + return this; + } + + /** + * The OperationsInner object to access its operations. + */ + private OperationsInner operations; + + /** + * Gets the OperationsInner object to access its operations. + * @return the OperationsInner object. + */ + public OperationsInner operations() { + return this.operations; + } + + /** + * Initializes an instance of RecoveryServicesBackupClient client. + * + * @param credentials the management credentials for Azure + */ + public RecoveryServicesBackupClientImpl(ServiceClientCredentials credentials) { + this("https://management.azure.com", credentials); + } + + /** + * Initializes an instance of RecoveryServicesBackupClient client. + * + * @param baseUrl the base URL of the host + * @param credentials the management credentials for Azure + */ + public RecoveryServicesBackupClientImpl(String baseUrl, ServiceClientCredentials credentials) { + super(baseUrl, credentials); + initialize(); + } + + /** + * Initializes an instance of RecoveryServicesBackupClient client. + * + * @param restClient the REST client to connect to Azure. + */ + public RecoveryServicesBackupClientImpl(RestClient restClient) { + super(restClient); + initialize(); + } + + protected void initialize() { + this.apiVersion = "2016-08-10"; + this.acceptLanguage = "en-US"; + this.longRunningOperationRetryTimeout = 30; + this.generateClientRequestId = true; + this.operations = new OperationsInner(restClient().retrofit(), this); + this.azureClient = new AzureClient(this); + } + + /** + * Gets the User-Agent header for the client. + * + * @return the user agent string. + */ + @Override + public String userAgent() { + return String.format("%s (%s, %s, auto-generated)", super.userAgent(), "RecoveryServicesBackupClient", "2016-08-10"); + } +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesManager.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesManager.java new file mode 100644 index 0000000000000..83e5f5259ef6c --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/RecoveryServicesManager.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; + +import com.microsoft.azure.AzureEnvironment; +import com.microsoft.azure.AzureResponseBuilder; +import com.microsoft.azure.credentials.AzureTokenCredentials; +import com.microsoft.azure.management.apigeneration.Beta; +import com.microsoft.azure.management.apigeneration.Beta.SinceVersion; +import com.microsoft.azure.arm.resources.AzureConfigurable; +import com.microsoft.azure.serializer.AzureJacksonAdapter; +import com.microsoft.rest.RestClient; +import com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.Operations; +import com.microsoft.azure.arm.resources.implementation.AzureConfigurableCoreImpl; +import com.microsoft.azure.arm.resources.implementation.ManagerCore; + +/** + * Entry point to Azure RecoveryServices resource management. + */ +public final class RecoveryServicesManager extends ManagerCore { + private Operations operations; + /** + * Get a Configurable instance that can be used to create RecoveryServicesManager with optional configuration. + * + * @return the instance allowing configurations + */ + public static Configurable configure() { + return new RecoveryServicesManager.ConfigurableImpl(); + } + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices resource management API entry points. + * + * @param credentials the credentials to use + * @return the RecoveryServicesManager + */ + public static RecoveryServicesManager authenticate(AzureTokenCredentials credentials) { + return new RecoveryServicesManager(new RestClient.Builder() + .withBaseUrl(credentials.environment(), AzureEnvironment.Endpoint.RESOURCE_MANAGER) + .withCredentials(credentials) + .withSerializerAdapter(new AzureJacksonAdapter()) + .withResponseBuilderFactory(new AzureResponseBuilder.Factory()) + .build()); + } + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices resource management API entry points. + * + * @param restClient the RestClient to be used for API calls. + * @return the RecoveryServicesManager + */ + public static RecoveryServicesManager authenticate(RestClient restClient) { + return new RecoveryServicesManager(restClient); + } + /** + * The interface allowing configurations to be set. + */ + public interface Configurable extends AzureConfigurable { + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices management API entry points. + * + * @param credentials the credentials to use + * @return the interface exposing RecoveryServices management API entry points that work across subscriptions + */ + RecoveryServicesManager authenticate(AzureTokenCredentials credentials); + } + + /** + * @return Entry point to manage Operations. + */ + public Operations operations() { + if (this.operations == null) { + this.operations = new OperationsImpl(this); + } + return this.operations; + } + + /** + * The implementation for Configurable interface. + */ + private static final class ConfigurableImpl extends AzureConfigurableCoreImpl implements Configurable { + public RecoveryServicesManager authenticate(AzureTokenCredentials credentials) { + return RecoveryServicesManager.authenticate(buildRestClient(credentials)); + } + } + private RecoveryServicesManager(RestClient restClient) { + super( + restClient, + null, + new RecoveryServicesBackupClientImpl(restClient)); + } +} diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/package-info.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/package-info.java new file mode 100644 index 0000000000000..cb2c8c0a99b97 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/implementation/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementation classes for RecoveryServicesBackupClient. + * Open API 2.0 Specs for Azure RecoveryServices Backup service. + */ +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10.implementation; diff --git a/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/package-info.java b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/package-info.java new file mode 100644 index 0000000000000..77fe3324d6330 --- /dev/null +++ b/recoveryservices.backup/resource-manager/v2016_08_10/src/main/java/com/microsoft/azure/management/recoveryservices/backup/v2016_08_10/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the classes for RecoveryServicesBackupClient. + * Open API 2.0 Specs for Azure RecoveryServices Backup service. + */ +package com.microsoft.azure.management.recoveryservices.backup.v2016_08_10; diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/pom.xml b/recoveryservices.siterecovery/resource-manager/v2018_01_10/pom.xml new file mode 100644 index 0000000000000..561d37a745749 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + com.microsoft.azure.recoveryservices.siterecovery.v2018_01_10 + + com.microsoft.azure + azure-arm-parent + 1.1.0 + ../../../pom.management.xml + + azure-mgmt-recoveryservices + 1.0.0-beta + jar + Microsoft Azure SDK for RecoveryServices Management + This package contains Microsoft RecoveryServices Management SDK. + https://github.com/Azure/azure-sdk-for-java + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + UTF-8 + + + + + microsoft + Microsoft + + + + + com.microsoft.azure + azure-client-runtime + + + com.microsoft.azure + azure-arm-client-runtime + + + junit + junit + test + + + com.microsoft.azure + azure-client-authentication + test + + + com.microsoft.azure + azure-mgmt-resources + test + + + com.microsoft.azure + azure-arm-client-runtime + test-jar + test + + 1.6.5 + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + com.microsoft.azure.management.apigeneration.LangDefinitionProcessor + + + true + true + + true + true + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization;*.blob.core.search + + + /** +
* Copyright (c) Microsoft Corporation. All rights reserved. +
* Licensed under the MIT License. See License.txt in the project root for +
* license information. +
*/ + ]]> +
+
+
+
+
+
diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AApplyRecoveryPointInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AApplyRecoveryPointInput.java new file mode 100644 index 0000000000000..c09d2b7233625 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AApplyRecoveryPointInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ApplyRecoveryPoint input specific to A2A provider. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AApplyRecoveryPointInput extends ApplyRecoveryPointProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerCreationInput.java new file mode 100644 index 0000000000000..e131df958b69b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerCreationInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A cloud creation input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AContainerCreationInput extends ReplicationProviderSpecificContainerCreationInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerMappingInput.java new file mode 100644 index 0000000000000..5713ab5ae50d0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AContainerMappingInput.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A container mapping input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AContainerMappingInput extends ReplicationProviderSpecificContainerMappingInput { + /** + * A value indicating whether the auto update is enabled. Possible values + * include: 'Disabled', 'Enabled'. + */ + @JsonProperty(value = "agentAutoUpdateStatus") + private AgentAutoUpdateStatus agentAutoUpdateStatus; + + /** + * The automation account arm id. + */ + @JsonProperty(value = "automationAccountArmId") + private String automationAccountArmId; + + /** + * Get a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @return the agentAutoUpdateStatus value + */ + public AgentAutoUpdateStatus agentAutoUpdateStatus() { + return this.agentAutoUpdateStatus; + } + + /** + * Set a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @param agentAutoUpdateStatus the agentAutoUpdateStatus value to set + * @return the A2AContainerMappingInput object itself. + */ + public A2AContainerMappingInput withAgentAutoUpdateStatus(AgentAutoUpdateStatus agentAutoUpdateStatus) { + this.agentAutoUpdateStatus = agentAutoUpdateStatus; + return this; + } + + /** + * Get the automation account arm id. + * + * @return the automationAccountArmId value + */ + public String automationAccountArmId() { + return this.automationAccountArmId; + } + + /** + * Set the automation account arm id. + * + * @param automationAccountArmId the automationAccountArmId value to set + * @return the A2AContainerMappingInput object itself. + */ + public A2AContainerMappingInput withAutomationAccountArmId(String automationAccountArmId) { + this.automationAccountArmId = automationAccountArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEnableProtectionInput.java new file mode 100644 index 0000000000000..07b9f8533af99 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEnableProtectionInput.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A enable protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AEnableProtectionInput extends EnableProtectionProviderSpecificInput { + /** + * The fabric specific object Id of the virtual machine. + */ + @JsonProperty(value = "fabricObjectId") + private String fabricObjectId; + + /** + * The recovery container Id. + */ + @JsonProperty(value = "recoveryContainerId") + private String recoveryContainerId; + + /** + * The recovery resource group Id. Valid for V2 scenarios. + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * The recovery cloud service Id. Valid for V1 scenarios. + */ + @JsonProperty(value = "recoveryCloudServiceId") + private String recoveryCloudServiceId; + + /** + * The recovery availability set Id. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * The list of vm disk details. + */ + @JsonProperty(value = "vmDisks") + private List vmDisks; + + /** + * The list of vm managed disk details. + */ + @JsonProperty(value = "vmManagedDisks") + private List vmManagedDisks; + + /** + * The multi vm group name. + */ + @JsonProperty(value = "multiVmGroupName") + private String multiVmGroupName; + + /** + * The boot diagnostic storage account. + */ + @JsonProperty(value = "recoveryBootDiagStorageAccountId") + private String recoveryBootDiagStorageAccountId; + + /** + * The recovery disk encryption information. + */ + @JsonProperty(value = "diskEncryptionInfo") + private DiskEncryptionInfo diskEncryptionInfo; + + /** + * Get the fabric specific object Id of the virtual machine. + * + * @return the fabricObjectId value + */ + public String fabricObjectId() { + return this.fabricObjectId; + } + + /** + * Set the fabric specific object Id of the virtual machine. + * + * @param fabricObjectId the fabricObjectId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withFabricObjectId(String fabricObjectId) { + this.fabricObjectId = fabricObjectId; + return this; + } + + /** + * Get the recovery container Id. + * + * @return the recoveryContainerId value + */ + public String recoveryContainerId() { + return this.recoveryContainerId; + } + + /** + * Set the recovery container Id. + * + * @param recoveryContainerId the recoveryContainerId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withRecoveryContainerId(String recoveryContainerId) { + this.recoveryContainerId = recoveryContainerId; + return this; + } + + /** + * Get the recovery resource group Id. Valid for V2 scenarios. + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the recovery resource group Id. Valid for V2 scenarios. + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get the recovery cloud service Id. Valid for V1 scenarios. + * + * @return the recoveryCloudServiceId value + */ + public String recoveryCloudServiceId() { + return this.recoveryCloudServiceId; + } + + /** + * Set the recovery cloud service Id. Valid for V1 scenarios. + * + * @param recoveryCloudServiceId the recoveryCloudServiceId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withRecoveryCloudServiceId(String recoveryCloudServiceId) { + this.recoveryCloudServiceId = recoveryCloudServiceId; + return this; + } + + /** + * Get the recovery availability set Id. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the recovery availability set Id. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get the list of vm disk details. + * + * @return the vmDisks value + */ + public List vmDisks() { + return this.vmDisks; + } + + /** + * Set the list of vm disk details. + * + * @param vmDisks the vmDisks value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withVmDisks(List vmDisks) { + this.vmDisks = vmDisks; + return this; + } + + /** + * Get the list of vm managed disk details. + * + * @return the vmManagedDisks value + */ + public List vmManagedDisks() { + return this.vmManagedDisks; + } + + /** + * Set the list of vm managed disk details. + * + * @param vmManagedDisks the vmManagedDisks value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withVmManagedDisks(List vmManagedDisks) { + this.vmManagedDisks = vmManagedDisks; + return this; + } + + /** + * Get the multi vm group name. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get the boot diagnostic storage account. + * + * @return the recoveryBootDiagStorageAccountId value + */ + public String recoveryBootDiagStorageAccountId() { + return this.recoveryBootDiagStorageAccountId; + } + + /** + * Set the boot diagnostic storage account. + * + * @param recoveryBootDiagStorageAccountId the recoveryBootDiagStorageAccountId value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withRecoveryBootDiagStorageAccountId(String recoveryBootDiagStorageAccountId) { + this.recoveryBootDiagStorageAccountId = recoveryBootDiagStorageAccountId; + return this; + } + + /** + * Get the recovery disk encryption information. + * + * @return the diskEncryptionInfo value + */ + public DiskEncryptionInfo diskEncryptionInfo() { + return this.diskEncryptionInfo; + } + + /** + * Set the recovery disk encryption information. + * + * @param diskEncryptionInfo the diskEncryptionInfo value to set + * @return the A2AEnableProtectionInput object itself. + */ + public A2AEnableProtectionInput withDiskEncryptionInfo(DiskEncryptionInfo diskEncryptionInfo) { + this.diskEncryptionInfo = diskEncryptionInfo; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEventDetails.java new file mode 100644 index 0000000000000..7a026a7d2112b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AEventDetails.java @@ -0,0 +1,177 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a A2A event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AEventDetails extends EventProviderSpecificDetails { + /** + * The protected item arm name. + */ + @JsonProperty(value = "protectedItemName") + private String protectedItemName; + + /** + * The azure vm arm id. + */ + @JsonProperty(value = "fabricObjectId") + private String fabricObjectId; + + /** + * Fabric arm name. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The fabric location. + */ + @JsonProperty(value = "fabricLocation") + private String fabricLocation; + + /** + * Remote fabric arm name. + */ + @JsonProperty(value = "remoteFabricName") + private String remoteFabricName; + + /** + * Remote fabric location. + */ + @JsonProperty(value = "remoteFabricLocation") + private String remoteFabricLocation; + + /** + * Get the protected item arm name. + * + * @return the protectedItemName value + */ + public String protectedItemName() { + return this.protectedItemName; + } + + /** + * Set the protected item arm name. + * + * @param protectedItemName the protectedItemName value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withProtectedItemName(String protectedItemName) { + this.protectedItemName = protectedItemName; + return this; + } + + /** + * Get the azure vm arm id. + * + * @return the fabricObjectId value + */ + public String fabricObjectId() { + return this.fabricObjectId; + } + + /** + * Set the azure vm arm id. + * + * @param fabricObjectId the fabricObjectId value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withFabricObjectId(String fabricObjectId) { + this.fabricObjectId = fabricObjectId; + return this; + } + + /** + * Get fabric arm name. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set fabric arm name. + * + * @param fabricName the fabricName value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the fabric location. + * + * @return the fabricLocation value + */ + public String fabricLocation() { + return this.fabricLocation; + } + + /** + * Set the fabric location. + * + * @param fabricLocation the fabricLocation value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withFabricLocation(String fabricLocation) { + this.fabricLocation = fabricLocation; + return this; + } + + /** + * Get remote fabric arm name. + * + * @return the remoteFabricName value + */ + public String remoteFabricName() { + return this.remoteFabricName; + } + + /** + * Set remote fabric arm name. + * + * @param remoteFabricName the remoteFabricName value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withRemoteFabricName(String remoteFabricName) { + this.remoteFabricName = remoteFabricName; + return this; + } + + /** + * Get remote fabric location. + * + * @return the remoteFabricLocation value + */ + public String remoteFabricLocation() { + return this.remoteFabricLocation; + } + + /** + * Set remote fabric location. + * + * @param remoteFabricLocation the remoteFabricLocation value to set + * @return the A2AEventDetails object itself. + */ + public A2AEventDetails withRemoteFabricLocation(String remoteFabricLocation) { + this.remoteFabricLocation = remoteFabricLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AFailoverProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AFailoverProviderInput.java new file mode 100644 index 0000000000000..67f5f8b8be98f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AFailoverProviderInput.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A provider specific input for failover. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AFailoverProviderInput extends ProviderSpecificFailoverInput { + /** + * The recovery point id to be passed to failover to a particular recovery + * point. In case of latest recovery point, null should be passed. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * A value indicating whether to use recovery cloud service for TFO or not. + */ + @JsonProperty(value = "cloudServiceCreationOption") + private String cloudServiceCreationOption; + + /** + * Get the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the A2AFailoverProviderInput object itself. + */ + public A2AFailoverProviderInput withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + + /** + * Get a value indicating whether to use recovery cloud service for TFO or not. + * + * @return the cloudServiceCreationOption value + */ + public String cloudServiceCreationOption() { + return this.cloudServiceCreationOption; + } + + /** + * Set a value indicating whether to use recovery cloud service for TFO or not. + * + * @param cloudServiceCreationOption the cloudServiceCreationOption value to set + * @return the A2AFailoverProviderInput object itself. + */ + public A2AFailoverProviderInput withCloudServiceCreationOption(String cloudServiceCreationOption) { + this.cloudServiceCreationOption = cloudServiceCreationOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyCreationInput.java new file mode 100644 index 0000000000000..5417ca549b8c6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyCreationInput.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A Policy creation input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2APolicyCreationInput extends PolicyProviderSpecificInput { + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The crash consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * The app consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. Value should + * be 'Enabled' or 'Disabled'. Possible values include: 'Enable', + * 'Disable'. + */ + @JsonProperty(value = "multiVmSyncStatus", required = true) + private SetMultiVmSyncStatus multiVmSyncStatus; + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the A2APolicyCreationInput object itself. + */ + public A2APolicyCreationInput withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the crash consistent snapshot frequency (in minutes). + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency (in minutes). + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the A2APolicyCreationInput object itself. + */ + public A2APolicyCreationInput withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + + /** + * Get the app consistent snapshot frequency (in minutes). + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency (in minutes). + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the A2APolicyCreationInput object itself. + */ + public A2APolicyCreationInput withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @return the multiVmSyncStatus value + */ + public SetMultiVmSyncStatus multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the A2APolicyCreationInput object itself. + */ + public A2APolicyCreationInput withMultiVmSyncStatus(SetMultiVmSyncStatus multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyDetails.java new file mode 100644 index 0000000000000..6ea4fc9b6f374 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2APolicyDetails.java @@ -0,0 +1,152 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A specific policy details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2APolicyDetails extends PolicyProviderSpecificDetails { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * The crash consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the A2APolicyDetails object itself. + */ + public A2APolicyDetails withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the A2APolicyDetails object itself. + */ + public A2APolicyDetails withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the A2APolicyDetails object itself. + */ + public A2APolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the A2APolicyDetails object itself. + */ + public A2APolicyDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + + /** + * Get the crash consistent snapshot frequency in minutes. + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency in minutes. + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the A2APolicyDetails object itself. + */ + public A2APolicyDetails withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedDiskDetails.java new file mode 100644 index 0000000000000..fd167fe0b1e37 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedDiskDetails.java @@ -0,0 +1,513 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A2A protected disk details. + */ +public class A2AProtectedDiskDetails { + /** + * The disk uri. + */ + @JsonProperty(value = "diskUri") + private String diskUri; + + /** + * The recovery disk storage account. + */ + @JsonProperty(value = "recoveryAzureStorageAccountId") + private String recoveryAzureStorageAccountId; + + /** + * The primary disk storage account. + */ + @JsonProperty(value = "primaryDiskAzureStorageAccountId") + private String primaryDiskAzureStorageAccountId; + + /** + * Recovery disk uri. + */ + @JsonProperty(value = "recoveryDiskUri") + private String recoveryDiskUri; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName") + private String diskName; + + /** + * The disk capacity in bytes. + */ + @JsonProperty(value = "diskCapacityInBytes") + private Long diskCapacityInBytes; + + /** + * The primary staging storage account. + */ + @JsonProperty(value = "primaryStagingAzureStorageAccountId") + private String primaryStagingAzureStorageAccountId; + + /** + * The type of disk. + */ + @JsonProperty(value = "diskType") + private String diskType; + + /** + * A value indicating whether resync is required for this disk. + */ + @JsonProperty(value = "resyncRequired") + private Boolean resyncRequired; + + /** + * The percentage of the monitoring job. The type of the monitoring job is + * defined by MonitoringJobType property. + */ + @JsonProperty(value = "monitoringPercentageCompletion") + private Integer monitoringPercentageCompletion; + + /** + * The type of the monitoring job. The progress is contained in + * MonitoringPercentageCompletion property. + */ + @JsonProperty(value = "monitoringJobType") + private String monitoringJobType; + + /** + * The data pending for replication in MB at staging account. + */ + @JsonProperty(value = "dataPendingInStagingStorageAccountInMB") + private Double dataPendingInStagingStorageAccountInMB; + + /** + * The data pending at source virtual machine in MB. + */ + @JsonProperty(value = "dataPendingAtSourceAgentInMB") + private Double dataPendingAtSourceAgentInMB; + + /** + * A value indicating whether vm has encrypted os disk or not. + */ + @JsonProperty(value = "isDiskEncrypted") + private Boolean isDiskEncrypted; + + /** + * The secret URL / identifier (BEK). + */ + @JsonProperty(value = "secretIdentifier") + private String secretIdentifier; + + /** + * The KeyVault resource id for secret (BEK). + */ + @JsonProperty(value = "dekKeyVaultArmId") + private String dekKeyVaultArmId; + + /** + * A value indicating whether disk key got encrypted or not. + */ + @JsonProperty(value = "isDiskKeyEncrypted") + private Boolean isDiskKeyEncrypted; + + /** + * The key URL / identifier (KEK). + */ + @JsonProperty(value = "keyIdentifier") + private String keyIdentifier; + + /** + * The KeyVault resource id for key (KEK). + */ + @JsonProperty(value = "kekKeyVaultArmId") + private String kekKeyVaultArmId; + + /** + * Get the disk uri. + * + * @return the diskUri value + */ + public String diskUri() { + return this.diskUri; + } + + /** + * Set the disk uri. + * + * @param diskUri the diskUri value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDiskUri(String diskUri) { + this.diskUri = diskUri; + return this; + } + + /** + * Get the recovery disk storage account. + * + * @return the recoveryAzureStorageAccountId value + */ + public String recoveryAzureStorageAccountId() { + return this.recoveryAzureStorageAccountId; + } + + /** + * Set the recovery disk storage account. + * + * @param recoveryAzureStorageAccountId the recoveryAzureStorageAccountId value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withRecoveryAzureStorageAccountId(String recoveryAzureStorageAccountId) { + this.recoveryAzureStorageAccountId = recoveryAzureStorageAccountId; + return this; + } + + /** + * Get the primary disk storage account. + * + * @return the primaryDiskAzureStorageAccountId value + */ + public String primaryDiskAzureStorageAccountId() { + return this.primaryDiskAzureStorageAccountId; + } + + /** + * Set the primary disk storage account. + * + * @param primaryDiskAzureStorageAccountId the primaryDiskAzureStorageAccountId value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withPrimaryDiskAzureStorageAccountId(String primaryDiskAzureStorageAccountId) { + this.primaryDiskAzureStorageAccountId = primaryDiskAzureStorageAccountId; + return this; + } + + /** + * Get recovery disk uri. + * + * @return the recoveryDiskUri value + */ + public String recoveryDiskUri() { + return this.recoveryDiskUri; + } + + /** + * Set recovery disk uri. + * + * @param recoveryDiskUri the recoveryDiskUri value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withRecoveryDiskUri(String recoveryDiskUri) { + this.recoveryDiskUri = recoveryDiskUri; + return this; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Set the disk name. + * + * @param diskName the diskName value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDiskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Get the disk capacity in bytes. + * + * @return the diskCapacityInBytes value + */ + public Long diskCapacityInBytes() { + return this.diskCapacityInBytes; + } + + /** + * Set the disk capacity in bytes. + * + * @param diskCapacityInBytes the diskCapacityInBytes value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDiskCapacityInBytes(Long diskCapacityInBytes) { + this.diskCapacityInBytes = diskCapacityInBytes; + return this; + } + + /** + * Get the primary staging storage account. + * + * @return the primaryStagingAzureStorageAccountId value + */ + public String primaryStagingAzureStorageAccountId() { + return this.primaryStagingAzureStorageAccountId; + } + + /** + * Set the primary staging storage account. + * + * @param primaryStagingAzureStorageAccountId the primaryStagingAzureStorageAccountId value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withPrimaryStagingAzureStorageAccountId(String primaryStagingAzureStorageAccountId) { + this.primaryStagingAzureStorageAccountId = primaryStagingAzureStorageAccountId; + return this; + } + + /** + * Get the type of disk. + * + * @return the diskType value + */ + public String diskType() { + return this.diskType; + } + + /** + * Set the type of disk. + * + * @param diskType the diskType value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDiskType(String diskType) { + this.diskType = diskType; + return this; + } + + /** + * Get a value indicating whether resync is required for this disk. + * + * @return the resyncRequired value + */ + public Boolean resyncRequired() { + return this.resyncRequired; + } + + /** + * Set a value indicating whether resync is required for this disk. + * + * @param resyncRequired the resyncRequired value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withResyncRequired(Boolean resyncRequired) { + this.resyncRequired = resyncRequired; + return this; + } + + /** + * Get the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @return the monitoringPercentageCompletion value + */ + public Integer monitoringPercentageCompletion() { + return this.monitoringPercentageCompletion; + } + + /** + * Set the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @param monitoringPercentageCompletion the monitoringPercentageCompletion value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withMonitoringPercentageCompletion(Integer monitoringPercentageCompletion) { + this.monitoringPercentageCompletion = monitoringPercentageCompletion; + return this; + } + + /** + * Get the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @return the monitoringJobType value + */ + public String monitoringJobType() { + return this.monitoringJobType; + } + + /** + * Set the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @param monitoringJobType the monitoringJobType value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withMonitoringJobType(String monitoringJobType) { + this.monitoringJobType = monitoringJobType; + return this; + } + + /** + * Get the data pending for replication in MB at staging account. + * + * @return the dataPendingInStagingStorageAccountInMB value + */ + public Double dataPendingInStagingStorageAccountInMB() { + return this.dataPendingInStagingStorageAccountInMB; + } + + /** + * Set the data pending for replication in MB at staging account. + * + * @param dataPendingInStagingStorageAccountInMB the dataPendingInStagingStorageAccountInMB value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDataPendingInStagingStorageAccountInMB(Double dataPendingInStagingStorageAccountInMB) { + this.dataPendingInStagingStorageAccountInMB = dataPendingInStagingStorageAccountInMB; + return this; + } + + /** + * Get the data pending at source virtual machine in MB. + * + * @return the dataPendingAtSourceAgentInMB value + */ + public Double dataPendingAtSourceAgentInMB() { + return this.dataPendingAtSourceAgentInMB; + } + + /** + * Set the data pending at source virtual machine in MB. + * + * @param dataPendingAtSourceAgentInMB the dataPendingAtSourceAgentInMB value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDataPendingAtSourceAgentInMB(Double dataPendingAtSourceAgentInMB) { + this.dataPendingAtSourceAgentInMB = dataPendingAtSourceAgentInMB; + return this; + } + + /** + * Get a value indicating whether vm has encrypted os disk or not. + * + * @return the isDiskEncrypted value + */ + public Boolean isDiskEncrypted() { + return this.isDiskEncrypted; + } + + /** + * Set a value indicating whether vm has encrypted os disk or not. + * + * @param isDiskEncrypted the isDiskEncrypted value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withIsDiskEncrypted(Boolean isDiskEncrypted) { + this.isDiskEncrypted = isDiskEncrypted; + return this; + } + + /** + * Get the secret URL / identifier (BEK). + * + * @return the secretIdentifier value + */ + public String secretIdentifier() { + return this.secretIdentifier; + } + + /** + * Set the secret URL / identifier (BEK). + * + * @param secretIdentifier the secretIdentifier value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withSecretIdentifier(String secretIdentifier) { + this.secretIdentifier = secretIdentifier; + return this; + } + + /** + * Get the KeyVault resource id for secret (BEK). + * + * @return the dekKeyVaultArmId value + */ + public String dekKeyVaultArmId() { + return this.dekKeyVaultArmId; + } + + /** + * Set the KeyVault resource id for secret (BEK). + * + * @param dekKeyVaultArmId the dekKeyVaultArmId value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withDekKeyVaultArmId(String dekKeyVaultArmId) { + this.dekKeyVaultArmId = dekKeyVaultArmId; + return this; + } + + /** + * Get a value indicating whether disk key got encrypted or not. + * + * @return the isDiskKeyEncrypted value + */ + public Boolean isDiskKeyEncrypted() { + return this.isDiskKeyEncrypted; + } + + /** + * Set a value indicating whether disk key got encrypted or not. + * + * @param isDiskKeyEncrypted the isDiskKeyEncrypted value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withIsDiskKeyEncrypted(Boolean isDiskKeyEncrypted) { + this.isDiskKeyEncrypted = isDiskKeyEncrypted; + return this; + } + + /** + * Get the key URL / identifier (KEK). + * + * @return the keyIdentifier value + */ + public String keyIdentifier() { + return this.keyIdentifier; + } + + /** + * Set the key URL / identifier (KEK). + * + * @param keyIdentifier the keyIdentifier value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withKeyIdentifier(String keyIdentifier) { + this.keyIdentifier = keyIdentifier; + return this; + } + + /** + * Get the KeyVault resource id for key (KEK). + * + * @return the kekKeyVaultArmId value + */ + public String kekKeyVaultArmId() { + return this.kekKeyVaultArmId; + } + + /** + * Set the KeyVault resource id for key (KEK). + * + * @param kekKeyVaultArmId the kekKeyVaultArmId value to set + * @return the A2AProtectedDiskDetails object itself. + */ + public A2AProtectedDiskDetails withKekKeyVaultArmId(String kekKeyVaultArmId) { + this.kekKeyVaultArmId = kekKeyVaultArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedManagedDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedManagedDiskDetails.java new file mode 100644 index 0000000000000..eecca9df185cb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectedManagedDiskDetails.java @@ -0,0 +1,567 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A2A protected managed disk details. + */ +public class A2AProtectedManagedDiskDetails { + /** + * The managed disk Arm id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The recovery disk resource group Arm Id. + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * Recovery target disk Arm Id. + */ + @JsonProperty(value = "recoveryTargetDiskId") + private String recoveryTargetDiskId; + + /** + * Recovery replica disk Arm Id. + */ + @JsonProperty(value = "recoveryReplicaDiskId") + private String recoveryReplicaDiskId; + + /** + * The replica disk type. Its an optional value and will be same as source + * disk type if not user provided. + */ + @JsonProperty(value = "recoveryReplicaDiskAccountType") + private String recoveryReplicaDiskAccountType; + + /** + * The target disk type after failover. Its an optional value and will be + * same as source disk type if not user provided. + */ + @JsonProperty(value = "recoveryTargetDiskAccountType") + private String recoveryTargetDiskAccountType; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName") + private String diskName; + + /** + * The disk capacity in bytes. + */ + @JsonProperty(value = "diskCapacityInBytes") + private Long diskCapacityInBytes; + + /** + * The primary staging storage account. + */ + @JsonProperty(value = "primaryStagingAzureStorageAccountId") + private String primaryStagingAzureStorageAccountId; + + /** + * The type of disk. + */ + @JsonProperty(value = "diskType") + private String diskType; + + /** + * A value indicating whether resync is required for this disk. + */ + @JsonProperty(value = "resyncRequired") + private Boolean resyncRequired; + + /** + * The percentage of the monitoring job. The type of the monitoring job is + * defined by MonitoringJobType property. + */ + @JsonProperty(value = "monitoringPercentageCompletion") + private Integer monitoringPercentageCompletion; + + /** + * The type of the monitoring job. The progress is contained in + * MonitoringPercentageCompletion property. + */ + @JsonProperty(value = "monitoringJobType") + private String monitoringJobType; + + /** + * The data pending for replication in MB at staging account. + */ + @JsonProperty(value = "dataPendingInStagingStorageAccountInMB") + private Double dataPendingInStagingStorageAccountInMB; + + /** + * The data pending at source virtual machine in MB. + */ + @JsonProperty(value = "dataPendingAtSourceAgentInMB") + private Double dataPendingAtSourceAgentInMB; + + /** + * A value indicating whether vm has encrypted os disk or not. + */ + @JsonProperty(value = "isDiskEncrypted") + private Boolean isDiskEncrypted; + + /** + * The secret URL / identifier (BEK). + */ + @JsonProperty(value = "secretIdentifier") + private String secretIdentifier; + + /** + * The KeyVault resource id for secret (BEK). + */ + @JsonProperty(value = "dekKeyVaultArmId") + private String dekKeyVaultArmId; + + /** + * A value indicating whether disk key got encrypted or not. + */ + @JsonProperty(value = "isDiskKeyEncrypted") + private Boolean isDiskKeyEncrypted; + + /** + * The key URL / identifier (KEK). + */ + @JsonProperty(value = "keyIdentifier") + private String keyIdentifier; + + /** + * The KeyVault resource id for key (KEK). + */ + @JsonProperty(value = "kekKeyVaultArmId") + private String kekKeyVaultArmId; + + /** + * Get the managed disk Arm id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the managed disk Arm id. + * + * @param diskId the diskId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the recovery disk resource group Arm Id. + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the recovery disk resource group Arm Id. + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get recovery target disk Arm Id. + * + * @return the recoveryTargetDiskId value + */ + public String recoveryTargetDiskId() { + return this.recoveryTargetDiskId; + } + + /** + * Set recovery target disk Arm Id. + * + * @param recoveryTargetDiskId the recoveryTargetDiskId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withRecoveryTargetDiskId(String recoveryTargetDiskId) { + this.recoveryTargetDiskId = recoveryTargetDiskId; + return this; + } + + /** + * Get recovery replica disk Arm Id. + * + * @return the recoveryReplicaDiskId value + */ + public String recoveryReplicaDiskId() { + return this.recoveryReplicaDiskId; + } + + /** + * Set recovery replica disk Arm Id. + * + * @param recoveryReplicaDiskId the recoveryReplicaDiskId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withRecoveryReplicaDiskId(String recoveryReplicaDiskId) { + this.recoveryReplicaDiskId = recoveryReplicaDiskId; + return this; + } + + /** + * Get the replica disk type. Its an optional value and will be same as source disk type if not user provided. + * + * @return the recoveryReplicaDiskAccountType value + */ + public String recoveryReplicaDiskAccountType() { + return this.recoveryReplicaDiskAccountType; + } + + /** + * Set the replica disk type. Its an optional value and will be same as source disk type if not user provided. + * + * @param recoveryReplicaDiskAccountType the recoveryReplicaDiskAccountType value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withRecoveryReplicaDiskAccountType(String recoveryReplicaDiskAccountType) { + this.recoveryReplicaDiskAccountType = recoveryReplicaDiskAccountType; + return this; + } + + /** + * Get the target disk type after failover. Its an optional value and will be same as source disk type if not user provided. + * + * @return the recoveryTargetDiskAccountType value + */ + public String recoveryTargetDiskAccountType() { + return this.recoveryTargetDiskAccountType; + } + + /** + * Set the target disk type after failover. Its an optional value and will be same as source disk type if not user provided. + * + * @param recoveryTargetDiskAccountType the recoveryTargetDiskAccountType value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withRecoveryTargetDiskAccountType(String recoveryTargetDiskAccountType) { + this.recoveryTargetDiskAccountType = recoveryTargetDiskAccountType; + return this; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Set the disk name. + * + * @param diskName the diskName value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDiskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Get the disk capacity in bytes. + * + * @return the diskCapacityInBytes value + */ + public Long diskCapacityInBytes() { + return this.diskCapacityInBytes; + } + + /** + * Set the disk capacity in bytes. + * + * @param diskCapacityInBytes the diskCapacityInBytes value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDiskCapacityInBytes(Long diskCapacityInBytes) { + this.diskCapacityInBytes = diskCapacityInBytes; + return this; + } + + /** + * Get the primary staging storage account. + * + * @return the primaryStagingAzureStorageAccountId value + */ + public String primaryStagingAzureStorageAccountId() { + return this.primaryStagingAzureStorageAccountId; + } + + /** + * Set the primary staging storage account. + * + * @param primaryStagingAzureStorageAccountId the primaryStagingAzureStorageAccountId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withPrimaryStagingAzureStorageAccountId(String primaryStagingAzureStorageAccountId) { + this.primaryStagingAzureStorageAccountId = primaryStagingAzureStorageAccountId; + return this; + } + + /** + * Get the type of disk. + * + * @return the diskType value + */ + public String diskType() { + return this.diskType; + } + + /** + * Set the type of disk. + * + * @param diskType the diskType value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDiskType(String diskType) { + this.diskType = diskType; + return this; + } + + /** + * Get a value indicating whether resync is required for this disk. + * + * @return the resyncRequired value + */ + public Boolean resyncRequired() { + return this.resyncRequired; + } + + /** + * Set a value indicating whether resync is required for this disk. + * + * @param resyncRequired the resyncRequired value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withResyncRequired(Boolean resyncRequired) { + this.resyncRequired = resyncRequired; + return this; + } + + /** + * Get the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @return the monitoringPercentageCompletion value + */ + public Integer monitoringPercentageCompletion() { + return this.monitoringPercentageCompletion; + } + + /** + * Set the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @param monitoringPercentageCompletion the monitoringPercentageCompletion value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withMonitoringPercentageCompletion(Integer monitoringPercentageCompletion) { + this.monitoringPercentageCompletion = monitoringPercentageCompletion; + return this; + } + + /** + * Get the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @return the monitoringJobType value + */ + public String monitoringJobType() { + return this.monitoringJobType; + } + + /** + * Set the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @param monitoringJobType the monitoringJobType value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withMonitoringJobType(String monitoringJobType) { + this.monitoringJobType = monitoringJobType; + return this; + } + + /** + * Get the data pending for replication in MB at staging account. + * + * @return the dataPendingInStagingStorageAccountInMB value + */ + public Double dataPendingInStagingStorageAccountInMB() { + return this.dataPendingInStagingStorageAccountInMB; + } + + /** + * Set the data pending for replication in MB at staging account. + * + * @param dataPendingInStagingStorageAccountInMB the dataPendingInStagingStorageAccountInMB value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDataPendingInStagingStorageAccountInMB(Double dataPendingInStagingStorageAccountInMB) { + this.dataPendingInStagingStorageAccountInMB = dataPendingInStagingStorageAccountInMB; + return this; + } + + /** + * Get the data pending at source virtual machine in MB. + * + * @return the dataPendingAtSourceAgentInMB value + */ + public Double dataPendingAtSourceAgentInMB() { + return this.dataPendingAtSourceAgentInMB; + } + + /** + * Set the data pending at source virtual machine in MB. + * + * @param dataPendingAtSourceAgentInMB the dataPendingAtSourceAgentInMB value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDataPendingAtSourceAgentInMB(Double dataPendingAtSourceAgentInMB) { + this.dataPendingAtSourceAgentInMB = dataPendingAtSourceAgentInMB; + return this; + } + + /** + * Get a value indicating whether vm has encrypted os disk or not. + * + * @return the isDiskEncrypted value + */ + public Boolean isDiskEncrypted() { + return this.isDiskEncrypted; + } + + /** + * Set a value indicating whether vm has encrypted os disk or not. + * + * @param isDiskEncrypted the isDiskEncrypted value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withIsDiskEncrypted(Boolean isDiskEncrypted) { + this.isDiskEncrypted = isDiskEncrypted; + return this; + } + + /** + * Get the secret URL / identifier (BEK). + * + * @return the secretIdentifier value + */ + public String secretIdentifier() { + return this.secretIdentifier; + } + + /** + * Set the secret URL / identifier (BEK). + * + * @param secretIdentifier the secretIdentifier value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withSecretIdentifier(String secretIdentifier) { + this.secretIdentifier = secretIdentifier; + return this; + } + + /** + * Get the KeyVault resource id for secret (BEK). + * + * @return the dekKeyVaultArmId value + */ + public String dekKeyVaultArmId() { + return this.dekKeyVaultArmId; + } + + /** + * Set the KeyVault resource id for secret (BEK). + * + * @param dekKeyVaultArmId the dekKeyVaultArmId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withDekKeyVaultArmId(String dekKeyVaultArmId) { + this.dekKeyVaultArmId = dekKeyVaultArmId; + return this; + } + + /** + * Get a value indicating whether disk key got encrypted or not. + * + * @return the isDiskKeyEncrypted value + */ + public Boolean isDiskKeyEncrypted() { + return this.isDiskKeyEncrypted; + } + + /** + * Set a value indicating whether disk key got encrypted or not. + * + * @param isDiskKeyEncrypted the isDiskKeyEncrypted value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withIsDiskKeyEncrypted(Boolean isDiskKeyEncrypted) { + this.isDiskKeyEncrypted = isDiskKeyEncrypted; + return this; + } + + /** + * Get the key URL / identifier (KEK). + * + * @return the keyIdentifier value + */ + public String keyIdentifier() { + return this.keyIdentifier; + } + + /** + * Set the key URL / identifier (KEK). + * + * @param keyIdentifier the keyIdentifier value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withKeyIdentifier(String keyIdentifier) { + this.keyIdentifier = keyIdentifier; + return this; + } + + /** + * Get the KeyVault resource id for key (KEK). + * + * @return the kekKeyVaultArmId value + */ + public String kekKeyVaultArmId() { + return this.kekKeyVaultArmId; + } + + /** + * Set the KeyVault resource id for key (KEK). + * + * @param kekKeyVaultArmId the kekKeyVaultArmId value to set + * @return the A2AProtectedManagedDiskDetails object itself. + */ + public A2AProtectedManagedDiskDetails withKekKeyVaultArmId(String kekKeyVaultArmId) { + this.kekKeyVaultArmId = kekKeyVaultArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectionContainerMappingDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectionContainerMappingDetails.java new file mode 100644 index 0000000000000..257d194e2bb2e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AProtectionContainerMappingDetails.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AProtectionContainerMappingDetails extends ProtectionContainerMappingProviderSpecificDetails { + /** + * A value indicating whether the auto update is enabled. Possible values + * include: 'Disabled', 'Enabled'. + */ + @JsonProperty(value = "agentAutoUpdateStatus") + private AgentAutoUpdateStatus agentAutoUpdateStatus; + + /** + * The automation account arm id. + */ + @JsonProperty(value = "automationAccountArmId") + private String automationAccountArmId; + + /** + * The schedule arm name. + */ + @JsonProperty(value = "scheduleName") + private String scheduleName; + + /** + * The job schedule arm name. + */ + @JsonProperty(value = "jobScheduleName") + private String jobScheduleName; + + /** + * Get a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @return the agentAutoUpdateStatus value + */ + public AgentAutoUpdateStatus agentAutoUpdateStatus() { + return this.agentAutoUpdateStatus; + } + + /** + * Set a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @param agentAutoUpdateStatus the agentAutoUpdateStatus value to set + * @return the A2AProtectionContainerMappingDetails object itself. + */ + public A2AProtectionContainerMappingDetails withAgentAutoUpdateStatus(AgentAutoUpdateStatus agentAutoUpdateStatus) { + this.agentAutoUpdateStatus = agentAutoUpdateStatus; + return this; + } + + /** + * Get the automation account arm id. + * + * @return the automationAccountArmId value + */ + public String automationAccountArmId() { + return this.automationAccountArmId; + } + + /** + * Set the automation account arm id. + * + * @param automationAccountArmId the automationAccountArmId value to set + * @return the A2AProtectionContainerMappingDetails object itself. + */ + public A2AProtectionContainerMappingDetails withAutomationAccountArmId(String automationAccountArmId) { + this.automationAccountArmId = automationAccountArmId; + return this; + } + + /** + * Get the schedule arm name. + * + * @return the scheduleName value + */ + public String scheduleName() { + return this.scheduleName; + } + + /** + * Set the schedule arm name. + * + * @param scheduleName the scheduleName value to set + * @return the A2AProtectionContainerMappingDetails object itself. + */ + public A2AProtectionContainerMappingDetails withScheduleName(String scheduleName) { + this.scheduleName = scheduleName; + return this; + } + + /** + * Get the job schedule arm name. + * + * @return the jobScheduleName value + */ + public String jobScheduleName() { + return this.jobScheduleName; + } + + /** + * Set the job schedule arm name. + * + * @param jobScheduleName the jobScheduleName value to set + * @return the A2AProtectionContainerMappingDetails object itself. + */ + public A2AProtectionContainerMappingDetails withJobScheduleName(String jobScheduleName) { + this.jobScheduleName = jobScheduleName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARecoveryPointDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARecoveryPointDetails.java new file mode 100644 index 0000000000000..aa0d24f8e7f9b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARecoveryPointDetails.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A provider specific recovery point details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2ARecoveryPointDetails extends ProviderSpecificRecoveryPointDetails { + /** + * A value indicating whether the recovery point is multi VM consistent. + * Possible values include: 'MultiVmSyncRecoveryPoint', + * 'PerVmRecoveryPoint'. + */ + @JsonProperty(value = "recoveryPointSyncType") + private RecoveryPointSyncType recoveryPointSyncType; + + /** + * Get a value indicating whether the recovery point is multi VM consistent. Possible values include: 'MultiVmSyncRecoveryPoint', 'PerVmRecoveryPoint'. + * + * @return the recoveryPointSyncType value + */ + public RecoveryPointSyncType recoveryPointSyncType() { + return this.recoveryPointSyncType; + } + + /** + * Set a value indicating whether the recovery point is multi VM consistent. Possible values include: 'MultiVmSyncRecoveryPoint', 'PerVmRecoveryPoint'. + * + * @param recoveryPointSyncType the recoveryPointSyncType value to set + * @return the A2ARecoveryPointDetails object itself. + */ + public A2ARecoveryPointDetails withRecoveryPointSyncType(RecoveryPointSyncType recoveryPointSyncType) { + this.recoveryPointSyncType = recoveryPointSyncType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReplicationDetails.java new file mode 100644 index 0000000000000..dc91682cf39e2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReplicationDetails.java @@ -0,0 +1,837 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The fabric specific object Id of the virtual machine. + */ + @JsonProperty(value = "fabricObjectId") + private String fabricObjectId; + + /** + * The multi vm group Id. + */ + @JsonProperty(value = "multiVmGroupId") + private String multiVmGroupId; + + /** + * The multi vm group name. + */ + @JsonProperty(value = "multiVmGroupName") + private String multiVmGroupName; + + /** + * Whether Multi VM group is auto created or specified by user. Possible + * values include: 'AutoCreated', 'UserSpecified'. + */ + @JsonProperty(value = "multiVmGroupCreateOption") + private MultiVmGroupCreateOption multiVmGroupCreateOption; + + /** + * The management Id. + */ + @JsonProperty(value = "managementId") + private String managementId; + + /** + * The list of protected disks. + */ + @JsonProperty(value = "protectedDisks") + private List protectedDisks; + + /** + * The list of protected managed disks. + */ + @JsonProperty(value = "protectedManagedDisks") + private List protectedManagedDisks; + + /** + * The recovery boot diagnostic storage account Arm Id. + */ + @JsonProperty(value = "recoveryBootDiagStorageAccountId") + private String recoveryBootDiagStorageAccountId; + + /** + * Primary fabric location. + */ + @JsonProperty(value = "primaryFabricLocation") + private String primaryFabricLocation; + + /** + * The recovery fabric location. + */ + @JsonProperty(value = "recoveryFabricLocation") + private String recoveryFabricLocation; + + /** + * The type of operating system. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The size of recovery virtual machine. + */ + @JsonProperty(value = "recoveryAzureVMSize") + private String recoveryAzureVMSize; + + /** + * The name of recovery virtual machine. + */ + @JsonProperty(value = "recoveryAzureVMName") + private String recoveryAzureVMName; + + /** + * The recovery resource group. + */ + @JsonProperty(value = "recoveryAzureResourceGroupId") + private String recoveryAzureResourceGroupId; + + /** + * The recovery cloud service. + */ + @JsonProperty(value = "recoveryCloudService") + private String recoveryCloudService; + + /** + * The recovery availability set. + */ + @JsonProperty(value = "recoveryAvailabilitySet") + private String recoveryAvailabilitySet; + + /** + * The recovery virtual network. + */ + @JsonProperty(value = "selectedRecoveryAzureNetworkId") + private String selectedRecoveryAzureNetworkId; + + /** + * The virtual machine nic details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The synced configuration details. + */ + @JsonProperty(value = "vmSyncedConfigDetails") + private AzureToAzureVmSyncedConfigDetails vmSyncedConfigDetails; + + /** + * The percentage of the monitoring job. The type of the monitoring job is + * defined by MonitoringJobType property. + */ + @JsonProperty(value = "monitoringPercentageCompletion") + private Integer monitoringPercentageCompletion; + + /** + * The type of the monitoring job. The progress is contained in + * MonitoringPercentageCompletion property. + */ + @JsonProperty(value = "monitoringJobType") + private String monitoringJobType; + + /** + * The last heartbeat received from the source server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * The agent version. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * A value indicating whether replication agent update is required. + */ + @JsonProperty(value = "isReplicationAgentUpdateRequired") + private Boolean isReplicationAgentUpdateRequired; + + /** + * The recovery fabric object Id. + */ + @JsonProperty(value = "recoveryFabricObjectId") + private String recoveryFabricObjectId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * An id associated with the PE that survives actions like switch + * protection which change the backing PE/CPE objects internally.The + * lifecycle id gets carried forward to have a link/continuity in being + * able to have an Id that denotes the "same" protected item even though + * other internal Ids/ARM Id might be changing. + */ + @JsonProperty(value = "lifecycleId") + private String lifecycleId; + + /** + * The test failover fabric object Id. + */ + @JsonProperty(value = "testFailoverRecoveryFabricObjectId") + private String testFailoverRecoveryFabricObjectId; + + /** + * The last RPO value in seconds. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * The time (in UTC) when the last RPO value was calculated by Protection + * Service. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * Get the fabric specific object Id of the virtual machine. + * + * @return the fabricObjectId value + */ + public String fabricObjectId() { + return this.fabricObjectId; + } + + /** + * Set the fabric specific object Id of the virtual machine. + * + * @param fabricObjectId the fabricObjectId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withFabricObjectId(String fabricObjectId) { + this.fabricObjectId = fabricObjectId; + return this; + } + + /** + * Get the multi vm group Id. + * + * @return the multiVmGroupId value + */ + public String multiVmGroupId() { + return this.multiVmGroupId; + } + + /** + * Set the multi vm group Id. + * + * @param multiVmGroupId the multiVmGroupId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withMultiVmGroupId(String multiVmGroupId) { + this.multiVmGroupId = multiVmGroupId; + return this; + } + + /** + * Get the multi vm group name. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get whether Multi VM group is auto created or specified by user. Possible values include: 'AutoCreated', 'UserSpecified'. + * + * @return the multiVmGroupCreateOption value + */ + public MultiVmGroupCreateOption multiVmGroupCreateOption() { + return this.multiVmGroupCreateOption; + } + + /** + * Set whether Multi VM group is auto created or specified by user. Possible values include: 'AutoCreated', 'UserSpecified'. + * + * @param multiVmGroupCreateOption the multiVmGroupCreateOption value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withMultiVmGroupCreateOption(MultiVmGroupCreateOption multiVmGroupCreateOption) { + this.multiVmGroupCreateOption = multiVmGroupCreateOption; + return this; + } + + /** + * Get the management Id. + * + * @return the managementId value + */ + public String managementId() { + return this.managementId; + } + + /** + * Set the management Id. + * + * @param managementId the managementId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withManagementId(String managementId) { + this.managementId = managementId; + return this; + } + + /** + * Get the list of protected disks. + * + * @return the protectedDisks value + */ + public List protectedDisks() { + return this.protectedDisks; + } + + /** + * Set the list of protected disks. + * + * @param protectedDisks the protectedDisks value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withProtectedDisks(List protectedDisks) { + this.protectedDisks = protectedDisks; + return this; + } + + /** + * Get the list of protected managed disks. + * + * @return the protectedManagedDisks value + */ + public List protectedManagedDisks() { + return this.protectedManagedDisks; + } + + /** + * Set the list of protected managed disks. + * + * @param protectedManagedDisks the protectedManagedDisks value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withProtectedManagedDisks(List protectedManagedDisks) { + this.protectedManagedDisks = protectedManagedDisks; + return this; + } + + /** + * Get the recovery boot diagnostic storage account Arm Id. + * + * @return the recoveryBootDiagStorageAccountId value + */ + public String recoveryBootDiagStorageAccountId() { + return this.recoveryBootDiagStorageAccountId; + } + + /** + * Set the recovery boot diagnostic storage account Arm Id. + * + * @param recoveryBootDiagStorageAccountId the recoveryBootDiagStorageAccountId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryBootDiagStorageAccountId(String recoveryBootDiagStorageAccountId) { + this.recoveryBootDiagStorageAccountId = recoveryBootDiagStorageAccountId; + return this; + } + + /** + * Get primary fabric location. + * + * @return the primaryFabricLocation value + */ + public String primaryFabricLocation() { + return this.primaryFabricLocation; + } + + /** + * Set primary fabric location. + * + * @param primaryFabricLocation the primaryFabricLocation value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withPrimaryFabricLocation(String primaryFabricLocation) { + this.primaryFabricLocation = primaryFabricLocation; + return this; + } + + /** + * Get the recovery fabric location. + * + * @return the recoveryFabricLocation value + */ + public String recoveryFabricLocation() { + return this.recoveryFabricLocation; + } + + /** + * Set the recovery fabric location. + * + * @param recoveryFabricLocation the recoveryFabricLocation value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryFabricLocation(String recoveryFabricLocation) { + this.recoveryFabricLocation = recoveryFabricLocation; + return this; + } + + /** + * Get the type of operating system. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the type of operating system. + * + * @param osType the osType value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the size of recovery virtual machine. + * + * @return the recoveryAzureVMSize value + */ + public String recoveryAzureVMSize() { + return this.recoveryAzureVMSize; + } + + /** + * Set the size of recovery virtual machine. + * + * @param recoveryAzureVMSize the recoveryAzureVMSize value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryAzureVMSize(String recoveryAzureVMSize) { + this.recoveryAzureVMSize = recoveryAzureVMSize; + return this; + } + + /** + * Get the name of recovery virtual machine. + * + * @return the recoveryAzureVMName value + */ + public String recoveryAzureVMName() { + return this.recoveryAzureVMName; + } + + /** + * Set the name of recovery virtual machine. + * + * @param recoveryAzureVMName the recoveryAzureVMName value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryAzureVMName(String recoveryAzureVMName) { + this.recoveryAzureVMName = recoveryAzureVMName; + return this; + } + + /** + * Get the recovery resource group. + * + * @return the recoveryAzureResourceGroupId value + */ + public String recoveryAzureResourceGroupId() { + return this.recoveryAzureResourceGroupId; + } + + /** + * Set the recovery resource group. + * + * @param recoveryAzureResourceGroupId the recoveryAzureResourceGroupId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryAzureResourceGroupId(String recoveryAzureResourceGroupId) { + this.recoveryAzureResourceGroupId = recoveryAzureResourceGroupId; + return this; + } + + /** + * Get the recovery cloud service. + * + * @return the recoveryCloudService value + */ + public String recoveryCloudService() { + return this.recoveryCloudService; + } + + /** + * Set the recovery cloud service. + * + * @param recoveryCloudService the recoveryCloudService value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryCloudService(String recoveryCloudService) { + this.recoveryCloudService = recoveryCloudService; + return this; + } + + /** + * Get the recovery availability set. + * + * @return the recoveryAvailabilitySet value + */ + public String recoveryAvailabilitySet() { + return this.recoveryAvailabilitySet; + } + + /** + * Set the recovery availability set. + * + * @param recoveryAvailabilitySet the recoveryAvailabilitySet value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryAvailabilitySet(String recoveryAvailabilitySet) { + this.recoveryAvailabilitySet = recoveryAvailabilitySet; + return this; + } + + /** + * Get the recovery virtual network. + * + * @return the selectedRecoveryAzureNetworkId value + */ + public String selectedRecoveryAzureNetworkId() { + return this.selectedRecoveryAzureNetworkId; + } + + /** + * Set the recovery virtual network. + * + * @param selectedRecoveryAzureNetworkId the selectedRecoveryAzureNetworkId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withSelectedRecoveryAzureNetworkId(String selectedRecoveryAzureNetworkId) { + this.selectedRecoveryAzureNetworkId = selectedRecoveryAzureNetworkId; + return this; + } + + /** + * Get the virtual machine nic details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the virtual machine nic details. + * + * @param vmNics the vmNics value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the synced configuration details. + * + * @return the vmSyncedConfigDetails value + */ + public AzureToAzureVmSyncedConfigDetails vmSyncedConfigDetails() { + return this.vmSyncedConfigDetails; + } + + /** + * Set the synced configuration details. + * + * @param vmSyncedConfigDetails the vmSyncedConfigDetails value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withVmSyncedConfigDetails(AzureToAzureVmSyncedConfigDetails vmSyncedConfigDetails) { + this.vmSyncedConfigDetails = vmSyncedConfigDetails; + return this; + } + + /** + * Get the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @return the monitoringPercentageCompletion value + */ + public Integer monitoringPercentageCompletion() { + return this.monitoringPercentageCompletion; + } + + /** + * Set the percentage of the monitoring job. The type of the monitoring job is defined by MonitoringJobType property. + * + * @param monitoringPercentageCompletion the monitoringPercentageCompletion value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withMonitoringPercentageCompletion(Integer monitoringPercentageCompletion) { + this.monitoringPercentageCompletion = monitoringPercentageCompletion; + return this; + } + + /** + * Get the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @return the monitoringJobType value + */ + public String monitoringJobType() { + return this.monitoringJobType; + } + + /** + * Set the type of the monitoring job. The progress is contained in MonitoringPercentageCompletion property. + * + * @param monitoringJobType the monitoringJobType value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withMonitoringJobType(String monitoringJobType) { + this.monitoringJobType = monitoringJobType; + return this; + } + + /** + * Get the last heartbeat received from the source server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from the source server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get the agent version. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the agent version. + * + * @param agentVersion the agentVersion value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get a value indicating whether replication agent update is required. + * + * @return the isReplicationAgentUpdateRequired value + */ + public Boolean isReplicationAgentUpdateRequired() { + return this.isReplicationAgentUpdateRequired; + } + + /** + * Set a value indicating whether replication agent update is required. + * + * @param isReplicationAgentUpdateRequired the isReplicationAgentUpdateRequired value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withIsReplicationAgentUpdateRequired(Boolean isReplicationAgentUpdateRequired) { + this.isReplicationAgentUpdateRequired = isReplicationAgentUpdateRequired; + return this; + } + + /** + * Get the recovery fabric object Id. + * + * @return the recoveryFabricObjectId value + */ + public String recoveryFabricObjectId() { + return this.recoveryFabricObjectId; + } + + /** + * Set the recovery fabric object Id. + * + * @param recoveryFabricObjectId the recoveryFabricObjectId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRecoveryFabricObjectId(String recoveryFabricObjectId) { + this.recoveryFabricObjectId = recoveryFabricObjectId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get an id associated with the PE that survives actions like switch protection which change the backing PE/CPE objects internally.The lifecycle id gets carried forward to have a link/continuity in being able to have an Id that denotes the "same" protected item even though other internal Ids/ARM Id might be changing. + * + * @return the lifecycleId value + */ + public String lifecycleId() { + return this.lifecycleId; + } + + /** + * Set an id associated with the PE that survives actions like switch protection which change the backing PE/CPE objects internally.The lifecycle id gets carried forward to have a link/continuity in being able to have an Id that denotes the "same" protected item even though other internal Ids/ARM Id might be changing. + * + * @param lifecycleId the lifecycleId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withLifecycleId(String lifecycleId) { + this.lifecycleId = lifecycleId; + return this; + } + + /** + * Get the test failover fabric object Id. + * + * @return the testFailoverRecoveryFabricObjectId value + */ + public String testFailoverRecoveryFabricObjectId() { + return this.testFailoverRecoveryFabricObjectId; + } + + /** + * Set the test failover fabric object Id. + * + * @param testFailoverRecoveryFabricObjectId the testFailoverRecoveryFabricObjectId value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withTestFailoverRecoveryFabricObjectId(String testFailoverRecoveryFabricObjectId) { + this.testFailoverRecoveryFabricObjectId = testFailoverRecoveryFabricObjectId; + return this; + } + + /** + * Get the last RPO value in seconds. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set the last RPO value in seconds. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get the time (in UTC) when the last RPO value was calculated by Protection Service. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the time (in UTC) when the last RPO value was calculated by Protection Service. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the A2AReplicationDetails object itself. + */ + public A2AReplicationDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReprotectInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReprotectInput.java new file mode 100644 index 0000000000000..a29cebeb4f46d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AReprotectInput.java @@ -0,0 +1,178 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Azure specific reprotect input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AReprotectInput extends ReverseReplicationProviderSpecificInput { + /** + * The recovery container Id. + */ + @JsonProperty(value = "recoveryContainerId") + private String recoveryContainerId; + + /** + * The list of vm disk details. + */ + @JsonProperty(value = "vmDisks") + private List vmDisks; + + /** + * The recovery resource group Id. Valid for V2 scenarios. + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * The recovery cloud service Id. Valid for V1 scenarios. + */ + @JsonProperty(value = "recoveryCloudServiceId") + private String recoveryCloudServiceId; + + /** + * The recovery availability set. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * The Policy Id. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * Get the recovery container Id. + * + * @return the recoveryContainerId value + */ + public String recoveryContainerId() { + return this.recoveryContainerId; + } + + /** + * Set the recovery container Id. + * + * @param recoveryContainerId the recoveryContainerId value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withRecoveryContainerId(String recoveryContainerId) { + this.recoveryContainerId = recoveryContainerId; + return this; + } + + /** + * Get the list of vm disk details. + * + * @return the vmDisks value + */ + public List vmDisks() { + return this.vmDisks; + } + + /** + * Set the list of vm disk details. + * + * @param vmDisks the vmDisks value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withVmDisks(List vmDisks) { + this.vmDisks = vmDisks; + return this; + } + + /** + * Get the recovery resource group Id. Valid for V2 scenarios. + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the recovery resource group Id. Valid for V2 scenarios. + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get the recovery cloud service Id. Valid for V1 scenarios. + * + * @return the recoveryCloudServiceId value + */ + public String recoveryCloudServiceId() { + return this.recoveryCloudServiceId; + } + + /** + * Set the recovery cloud service Id. Valid for V1 scenarios. + * + * @param recoveryCloudServiceId the recoveryCloudServiceId value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withRecoveryCloudServiceId(String recoveryCloudServiceId) { + this.recoveryCloudServiceId = recoveryCloudServiceId; + return this; + } + + /** + * Get the recovery availability set. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the recovery availability set. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get the Policy Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the Policy Id. + * + * @param policyId the policyId value to set + * @return the A2AReprotectInput object itself. + */ + public A2AReprotectInput withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARpRecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARpRecoveryPointType.java new file mode 100644 index 0000000000000..5438ab51a0fc2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ARpRecoveryPointType.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for A2ARpRecoveryPointType. + */ +public final class A2ARpRecoveryPointType extends ExpandableStringEnum { + /** Static value Latest for A2ARpRecoveryPointType. */ + public static final A2ARpRecoveryPointType LATEST = fromString("Latest"); + + /** Static value LatestApplicationConsistent for A2ARpRecoveryPointType. */ + public static final A2ARpRecoveryPointType LATEST_APPLICATION_CONSISTENT = fromString("LatestApplicationConsistent"); + + /** Static value LatestCrashConsistent for A2ARpRecoveryPointType. */ + public static final A2ARpRecoveryPointType LATEST_CRASH_CONSISTENT = fromString("LatestCrashConsistent"); + + /** Static value LatestProcessed for A2ARpRecoveryPointType. */ + public static final A2ARpRecoveryPointType LATEST_PROCESSED = fromString("LatestProcessed"); + + /** + * Creates or finds a A2ARpRecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding A2ARpRecoveryPointType + */ + @JsonCreator + public static A2ARpRecoveryPointType fromString(String name) { + return fromString(name, A2ARpRecoveryPointType.class); + } + + /** + * @return known A2ARpRecoveryPointType values + */ + public static Collection values() { + return values(A2ARpRecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ASwitchProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ASwitchProtectionInput.java new file mode 100644 index 0000000000000..3b6688a7170aa --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2ASwitchProtectionInput.java @@ -0,0 +1,256 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A specific switch protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2ASwitchProtectionInput extends SwitchProtectionProviderSpecificInput { + /** + * The recovery container Id. + */ + @JsonProperty(value = "recoveryContainerId") + private String recoveryContainerId; + + /** + * The list of vm disk details. + */ + @JsonProperty(value = "vmDisks") + private List vmDisks; + + /** + * The list of vm managed disk details. + */ + @JsonProperty(value = "vmManagedDisks") + private List vmManagedDisks; + + /** + * The recovery resource group Id. Valid for V2 scenarios. + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * The recovery cloud service Id. Valid for V1 scenarios. + */ + @JsonProperty(value = "recoveryCloudServiceId") + private String recoveryCloudServiceId; + + /** + * The recovery availability set. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * The Policy Id. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * The boot diagnostic storage account. + */ + @JsonProperty(value = "recoveryBootDiagStorageAccountId") + private String recoveryBootDiagStorageAccountId; + + /** + * The recovery disk encryption information. + */ + @JsonProperty(value = "diskEncryptionInfo") + private DiskEncryptionInfo diskEncryptionInfo; + + /** + * Get the recovery container Id. + * + * @return the recoveryContainerId value + */ + public String recoveryContainerId() { + return this.recoveryContainerId; + } + + /** + * Set the recovery container Id. + * + * @param recoveryContainerId the recoveryContainerId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withRecoveryContainerId(String recoveryContainerId) { + this.recoveryContainerId = recoveryContainerId; + return this; + } + + /** + * Get the list of vm disk details. + * + * @return the vmDisks value + */ + public List vmDisks() { + return this.vmDisks; + } + + /** + * Set the list of vm disk details. + * + * @param vmDisks the vmDisks value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withVmDisks(List vmDisks) { + this.vmDisks = vmDisks; + return this; + } + + /** + * Get the list of vm managed disk details. + * + * @return the vmManagedDisks value + */ + public List vmManagedDisks() { + return this.vmManagedDisks; + } + + /** + * Set the list of vm managed disk details. + * + * @param vmManagedDisks the vmManagedDisks value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withVmManagedDisks(List vmManagedDisks) { + this.vmManagedDisks = vmManagedDisks; + return this; + } + + /** + * Get the recovery resource group Id. Valid for V2 scenarios. + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the recovery resource group Id. Valid for V2 scenarios. + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get the recovery cloud service Id. Valid for V1 scenarios. + * + * @return the recoveryCloudServiceId value + */ + public String recoveryCloudServiceId() { + return this.recoveryCloudServiceId; + } + + /** + * Set the recovery cloud service Id. Valid for V1 scenarios. + * + * @param recoveryCloudServiceId the recoveryCloudServiceId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withRecoveryCloudServiceId(String recoveryCloudServiceId) { + this.recoveryCloudServiceId = recoveryCloudServiceId; + return this; + } + + /** + * Get the recovery availability set. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the recovery availability set. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get the Policy Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the Policy Id. + * + * @param policyId the policyId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get the boot diagnostic storage account. + * + * @return the recoveryBootDiagStorageAccountId value + */ + public String recoveryBootDiagStorageAccountId() { + return this.recoveryBootDiagStorageAccountId; + } + + /** + * Set the boot diagnostic storage account. + * + * @param recoveryBootDiagStorageAccountId the recoveryBootDiagStorageAccountId value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withRecoveryBootDiagStorageAccountId(String recoveryBootDiagStorageAccountId) { + this.recoveryBootDiagStorageAccountId = recoveryBootDiagStorageAccountId; + return this; + } + + /** + * Get the recovery disk encryption information. + * + * @return the diskEncryptionInfo value + */ + public DiskEncryptionInfo diskEncryptionInfo() { + return this.diskEncryptionInfo; + } + + /** + * Set the recovery disk encryption information. + * + * @param diskEncryptionInfo the diskEncryptionInfo value to set + * @return the A2ASwitchProtectionInput object itself. + */ + public A2ASwitchProtectionInput withDiskEncryptionInfo(DiskEncryptionInfo diskEncryptionInfo) { + this.diskEncryptionInfo = diskEncryptionInfo; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateContainerMappingInput.java new file mode 100644 index 0000000000000..7a52e911ad65f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateContainerMappingInput.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A update protection container mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AUpdateContainerMappingInput extends ReplicationProviderSpecificUpdateContainerMappingInput { + /** + * A value indicating whether the auto update is enabled. Possible values + * include: 'Disabled', 'Enabled'. + */ + @JsonProperty(value = "agentAutoUpdateStatus") + private AgentAutoUpdateStatus agentAutoUpdateStatus; + + /** + * The automation account arm id. + */ + @JsonProperty(value = "automationAccountArmId") + private String automationAccountArmId; + + /** + * Get a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @return the agentAutoUpdateStatus value + */ + public AgentAutoUpdateStatus agentAutoUpdateStatus() { + return this.agentAutoUpdateStatus; + } + + /** + * Set a value indicating whether the auto update is enabled. Possible values include: 'Disabled', 'Enabled'. + * + * @param agentAutoUpdateStatus the agentAutoUpdateStatus value to set + * @return the A2AUpdateContainerMappingInput object itself. + */ + public A2AUpdateContainerMappingInput withAgentAutoUpdateStatus(AgentAutoUpdateStatus agentAutoUpdateStatus) { + this.agentAutoUpdateStatus = agentAutoUpdateStatus; + return this; + } + + /** + * Get the automation account arm id. + * + * @return the automationAccountArmId value + */ + public String automationAccountArmId() { + return this.automationAccountArmId; + } + + /** + * Set the automation account arm id. + * + * @param automationAccountArmId the automationAccountArmId value to set + * @return the A2AUpdateContainerMappingInput object itself. + */ + public A2AUpdateContainerMappingInput withAutomationAccountArmId(String automationAccountArmId) { + this.automationAccountArmId = automationAccountArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateReplicationProtectedItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateReplicationProtectedItemInput.java new file mode 100644 index 0000000000000..2224aaddfc39f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AUpdateReplicationProtectedItemInput.java @@ -0,0 +1,152 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage Azure V2 input to update replication protected item. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class A2AUpdateReplicationProtectedItemInput extends UpdateReplicationProtectedItemProviderInput { + /** + * The target cloud service ARM Id (for V1). + */ + @JsonProperty(value = "recoveryCloudServiceId") + private String recoveryCloudServiceId; + + /** + * The target resource group ARM Id (for V2). + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * Managed disk update details. + */ + @JsonProperty(value = "managedDiskUpdateDetails") + private List managedDiskUpdateDetails; + + /** + * The boot diagnostic storage account. + */ + @JsonProperty(value = "recoveryBootDiagStorageAccountId") + private String recoveryBootDiagStorageAccountId; + + /** + * The recovery os disk encryption information. + */ + @JsonProperty(value = "diskEncryptionInfo") + private DiskEncryptionInfo diskEncryptionInfo; + + /** + * Get the target cloud service ARM Id (for V1). + * + * @return the recoveryCloudServiceId value + */ + public String recoveryCloudServiceId() { + return this.recoveryCloudServiceId; + } + + /** + * Set the target cloud service ARM Id (for V1). + * + * @param recoveryCloudServiceId the recoveryCloudServiceId value to set + * @return the A2AUpdateReplicationProtectedItemInput object itself. + */ + public A2AUpdateReplicationProtectedItemInput withRecoveryCloudServiceId(String recoveryCloudServiceId) { + this.recoveryCloudServiceId = recoveryCloudServiceId; + return this; + } + + /** + * Get the target resource group ARM Id (for V2). + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the target resource group ARM Id (for V2). + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2AUpdateReplicationProtectedItemInput object itself. + */ + public A2AUpdateReplicationProtectedItemInput withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get managed disk update details. + * + * @return the managedDiskUpdateDetails value + */ + public List managedDiskUpdateDetails() { + return this.managedDiskUpdateDetails; + } + + /** + * Set managed disk update details. + * + * @param managedDiskUpdateDetails the managedDiskUpdateDetails value to set + * @return the A2AUpdateReplicationProtectedItemInput object itself. + */ + public A2AUpdateReplicationProtectedItemInput withManagedDiskUpdateDetails(List managedDiskUpdateDetails) { + this.managedDiskUpdateDetails = managedDiskUpdateDetails; + return this; + } + + /** + * Get the boot diagnostic storage account. + * + * @return the recoveryBootDiagStorageAccountId value + */ + public String recoveryBootDiagStorageAccountId() { + return this.recoveryBootDiagStorageAccountId; + } + + /** + * Set the boot diagnostic storage account. + * + * @param recoveryBootDiagStorageAccountId the recoveryBootDiagStorageAccountId value to set + * @return the A2AUpdateReplicationProtectedItemInput object itself. + */ + public A2AUpdateReplicationProtectedItemInput withRecoveryBootDiagStorageAccountId(String recoveryBootDiagStorageAccountId) { + this.recoveryBootDiagStorageAccountId = recoveryBootDiagStorageAccountId; + return this; + } + + /** + * Get the recovery os disk encryption information. + * + * @return the diskEncryptionInfo value + */ + public DiskEncryptionInfo diskEncryptionInfo() { + return this.diskEncryptionInfo; + } + + /** + * Set the recovery os disk encryption information. + * + * @param diskEncryptionInfo the diskEncryptionInfo value to set + * @return the A2AUpdateReplicationProtectedItemInput object itself. + */ + public A2AUpdateReplicationProtectedItemInput withDiskEncryptionInfo(DiskEncryptionInfo diskEncryptionInfo) { + this.diskEncryptionInfo = diskEncryptionInfo; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmDiskInputDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmDiskInputDetails.java new file mode 100644 index 0000000000000..9857b5ec7281a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmDiskInputDetails.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure VM disk input details. + */ +public class A2AVmDiskInputDetails { + /** + * The disk Uri. + */ + @JsonProperty(value = "diskUri") + private String diskUri; + + /** + * The recovery VHD storage account Id. + */ + @JsonProperty(value = "recoveryAzureStorageAccountId") + private String recoveryAzureStorageAccountId; + + /** + * The primary staging storage account Id. + */ + @JsonProperty(value = "primaryStagingAzureStorageAccountId") + private String primaryStagingAzureStorageAccountId; + + /** + * Get the disk Uri. + * + * @return the diskUri value + */ + public String diskUri() { + return this.diskUri; + } + + /** + * Set the disk Uri. + * + * @param diskUri the diskUri value to set + * @return the A2AVmDiskInputDetails object itself. + */ + public A2AVmDiskInputDetails withDiskUri(String diskUri) { + this.diskUri = diskUri; + return this; + } + + /** + * Get the recovery VHD storage account Id. + * + * @return the recoveryAzureStorageAccountId value + */ + public String recoveryAzureStorageAccountId() { + return this.recoveryAzureStorageAccountId; + } + + /** + * Set the recovery VHD storage account Id. + * + * @param recoveryAzureStorageAccountId the recoveryAzureStorageAccountId value to set + * @return the A2AVmDiskInputDetails object itself. + */ + public A2AVmDiskInputDetails withRecoveryAzureStorageAccountId(String recoveryAzureStorageAccountId) { + this.recoveryAzureStorageAccountId = recoveryAzureStorageAccountId; + return this; + } + + /** + * Get the primary staging storage account Id. + * + * @return the primaryStagingAzureStorageAccountId value + */ + public String primaryStagingAzureStorageAccountId() { + return this.primaryStagingAzureStorageAccountId; + } + + /** + * Set the primary staging storage account Id. + * + * @param primaryStagingAzureStorageAccountId the primaryStagingAzureStorageAccountId value to set + * @return the A2AVmDiskInputDetails object itself. + */ + public A2AVmDiskInputDetails withPrimaryStagingAzureStorageAccountId(String primaryStagingAzureStorageAccountId) { + this.primaryStagingAzureStorageAccountId = primaryStagingAzureStorageAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskInputDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskInputDetails.java new file mode 100644 index 0000000000000..8eb29d38eec30 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskInputDetails.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure VM managed disk input details. + */ +public class A2AVmManagedDiskInputDetails { + /** + * The disk Id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The primary staging storage account Arm Id. + */ + @JsonProperty(value = "primaryStagingAzureStorageAccountId") + private String primaryStagingAzureStorageAccountId; + + /** + * The target resource group Arm Id. + */ + @JsonProperty(value = "recoveryResourceGroupId") + private String recoveryResourceGroupId; + + /** + * The replica disk type. Its an optional value and will be same as source + * disk type if not user provided. + */ + @JsonProperty(value = "recoveryReplicaDiskAccountType") + private String recoveryReplicaDiskAccountType; + + /** + * The target disk type after failover. Its an optional value and will be + * same as source disk type if not user provided. + */ + @JsonProperty(value = "recoveryTargetDiskAccountType") + private String recoveryTargetDiskAccountType; + + /** + * Get the disk Id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk Id. + * + * @param diskId the diskId value to set + * @return the A2AVmManagedDiskInputDetails object itself. + */ + public A2AVmManagedDiskInputDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the primary staging storage account Arm Id. + * + * @return the primaryStagingAzureStorageAccountId value + */ + public String primaryStagingAzureStorageAccountId() { + return this.primaryStagingAzureStorageAccountId; + } + + /** + * Set the primary staging storage account Arm Id. + * + * @param primaryStagingAzureStorageAccountId the primaryStagingAzureStorageAccountId value to set + * @return the A2AVmManagedDiskInputDetails object itself. + */ + public A2AVmManagedDiskInputDetails withPrimaryStagingAzureStorageAccountId(String primaryStagingAzureStorageAccountId) { + this.primaryStagingAzureStorageAccountId = primaryStagingAzureStorageAccountId; + return this; + } + + /** + * Get the target resource group Arm Id. + * + * @return the recoveryResourceGroupId value + */ + public String recoveryResourceGroupId() { + return this.recoveryResourceGroupId; + } + + /** + * Set the target resource group Arm Id. + * + * @param recoveryResourceGroupId the recoveryResourceGroupId value to set + * @return the A2AVmManagedDiskInputDetails object itself. + */ + public A2AVmManagedDiskInputDetails withRecoveryResourceGroupId(String recoveryResourceGroupId) { + this.recoveryResourceGroupId = recoveryResourceGroupId; + return this; + } + + /** + * Get the replica disk type. Its an optional value and will be same as source disk type if not user provided. + * + * @return the recoveryReplicaDiskAccountType value + */ + public String recoveryReplicaDiskAccountType() { + return this.recoveryReplicaDiskAccountType; + } + + /** + * Set the replica disk type. Its an optional value and will be same as source disk type if not user provided. + * + * @param recoveryReplicaDiskAccountType the recoveryReplicaDiskAccountType value to set + * @return the A2AVmManagedDiskInputDetails object itself. + */ + public A2AVmManagedDiskInputDetails withRecoveryReplicaDiskAccountType(String recoveryReplicaDiskAccountType) { + this.recoveryReplicaDiskAccountType = recoveryReplicaDiskAccountType; + return this; + } + + /** + * Get the target disk type after failover. Its an optional value and will be same as source disk type if not user provided. + * + * @return the recoveryTargetDiskAccountType value + */ + public String recoveryTargetDiskAccountType() { + return this.recoveryTargetDiskAccountType; + } + + /** + * Set the target disk type after failover. Its an optional value and will be same as source disk type if not user provided. + * + * @param recoveryTargetDiskAccountType the recoveryTargetDiskAccountType value to set + * @return the A2AVmManagedDiskInputDetails object itself. + */ + public A2AVmManagedDiskInputDetails withRecoveryTargetDiskAccountType(String recoveryTargetDiskAccountType) { + this.recoveryTargetDiskAccountType = recoveryTargetDiskAccountType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskUpdateDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskUpdateDetails.java new file mode 100644 index 0000000000000..fa965587ed3e1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/A2AVmManagedDiskUpdateDetails.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure VM managed disk update input details. + */ +public class A2AVmManagedDiskUpdateDetails { + /** + * The disk Id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The target disk type before failover. + */ + @JsonProperty(value = "recoveryTargetDiskAccountType") + private String recoveryTargetDiskAccountType; + + /** + * The replica disk type before failover. + */ + @JsonProperty(value = "recoveryReplicaDiskAccountType") + private String recoveryReplicaDiskAccountType; + + /** + * Get the disk Id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk Id. + * + * @param diskId the diskId value to set + * @return the A2AVmManagedDiskUpdateDetails object itself. + */ + public A2AVmManagedDiskUpdateDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the target disk type before failover. + * + * @return the recoveryTargetDiskAccountType value + */ + public String recoveryTargetDiskAccountType() { + return this.recoveryTargetDiskAccountType; + } + + /** + * Set the target disk type before failover. + * + * @param recoveryTargetDiskAccountType the recoveryTargetDiskAccountType value to set + * @return the A2AVmManagedDiskUpdateDetails object itself. + */ + public A2AVmManagedDiskUpdateDetails withRecoveryTargetDiskAccountType(String recoveryTargetDiskAccountType) { + this.recoveryTargetDiskAccountType = recoveryTargetDiskAccountType; + return this; + } + + /** + * Get the replica disk type before failover. + * + * @return the recoveryReplicaDiskAccountType value + */ + public String recoveryReplicaDiskAccountType() { + return this.recoveryReplicaDiskAccountType; + } + + /** + * Set the replica disk type before failover. + * + * @param recoveryReplicaDiskAccountType the recoveryReplicaDiskAccountType value to set + * @return the A2AVmManagedDiskUpdateDetails object itself. + */ + public A2AVmManagedDiskUpdateDetails withRecoveryReplicaDiskAccountType(String recoveryReplicaDiskAccountType) { + this.recoveryReplicaDiskAccountType = recoveryReplicaDiskAccountType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ASRTask.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ASRTask.java new file mode 100644 index 0000000000000..c866c1408c4ad --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ASRTask.java @@ -0,0 +1,335 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Task of the Job. + */ +public class ASRTask { + /** + * The Id. + */ + @JsonProperty(value = "taskId") + private String taskId; + + /** + * The unique Task name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The start time. + */ + @JsonProperty(value = "startTime") + private DateTime startTime; + + /** + * The end time. + */ + @JsonProperty(value = "endTime") + private DateTime endTime; + + /** + * The state/actions applicable on this task. + */ + @JsonProperty(value = "allowedActions") + private List allowedActions; + + /** + * The name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The State. It is one of these values - NotStarted, InProgress, + * Succeeded, Failed, Cancelled, Suspended or Other. + */ + @JsonProperty(value = "state") + private String state; + + /** + * The description of the task state. For example - For Succeeded state, + * description can be Completed, PartiallySucceeded, + * CompletedWithInformation or Skipped. + */ + @JsonProperty(value = "stateDescription") + private String stateDescription; + + /** + * The type of task. Details in CustomDetails property depend on this type. + */ + @JsonProperty(value = "taskType") + private String taskType; + + /** + * The custom task details based on the task type. + */ + @JsonProperty(value = "customDetails") + private TaskTypeDetails customDetails; + + /** + * The custom task details based on the task type, if the task type is + * GroupTaskDetails or one of the types derived from it. + */ + @JsonProperty(value = "groupTaskCustomDetails") + private GroupTaskDetails groupTaskCustomDetails; + + /** + * The task error details. + */ + @JsonProperty(value = "errors") + private List errors; + + /** + * Get the Id. + * + * @return the taskId value + */ + public String taskId() { + return this.taskId; + } + + /** + * Set the Id. + * + * @param taskId the taskId value to set + * @return the ASRTask object itself. + */ + public ASRTask withTaskId(String taskId) { + this.taskId = taskId; + return this; + } + + /** + * Get the unique Task name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the unique Task name. + * + * @param name the name value to set + * @return the ASRTask object itself. + */ + public ASRTask withName(String name) { + this.name = name; + return this; + } + + /** + * Get the start time. + * + * @return the startTime value + */ + public DateTime startTime() { + return this.startTime; + } + + /** + * Set the start time. + * + * @param startTime the startTime value to set + * @return the ASRTask object itself. + */ + public ASRTask withStartTime(DateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * Get the end time. + * + * @return the endTime value + */ + public DateTime endTime() { + return this.endTime; + } + + /** + * Set the end time. + * + * @param endTime the endTime value to set + * @return the ASRTask object itself. + */ + public ASRTask withEndTime(DateTime endTime) { + this.endTime = endTime; + return this; + } + + /** + * Get the state/actions applicable on this task. + * + * @return the allowedActions value + */ + public List allowedActions() { + return this.allowedActions; + } + + /** + * Set the state/actions applicable on this task. + * + * @param allowedActions the allowedActions value to set + * @return the ASRTask object itself. + */ + public ASRTask withAllowedActions(List allowedActions) { + this.allowedActions = allowedActions; + return this; + } + + /** + * Get the name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the name. + * + * @param friendlyName the friendlyName value to set + * @return the ASRTask object itself. + */ + public ASRTask withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the State. It is one of these values - NotStarted, InProgress, Succeeded, Failed, Cancelled, Suspended or Other. + * + * @return the state value + */ + public String state() { + return this.state; + } + + /** + * Set the State. It is one of these values - NotStarted, InProgress, Succeeded, Failed, Cancelled, Suspended or Other. + * + * @param state the state value to set + * @return the ASRTask object itself. + */ + public ASRTask withState(String state) { + this.state = state; + return this; + } + + /** + * Get the description of the task state. For example - For Succeeded state, description can be Completed, PartiallySucceeded, CompletedWithInformation or Skipped. + * + * @return the stateDescription value + */ + public String stateDescription() { + return this.stateDescription; + } + + /** + * Set the description of the task state. For example - For Succeeded state, description can be Completed, PartiallySucceeded, CompletedWithInformation or Skipped. + * + * @param stateDescription the stateDescription value to set + * @return the ASRTask object itself. + */ + public ASRTask withStateDescription(String stateDescription) { + this.stateDescription = stateDescription; + return this; + } + + /** + * Get the type of task. Details in CustomDetails property depend on this type. + * + * @return the taskType value + */ + public String taskType() { + return this.taskType; + } + + /** + * Set the type of task. Details in CustomDetails property depend on this type. + * + * @param taskType the taskType value to set + * @return the ASRTask object itself. + */ + public ASRTask withTaskType(String taskType) { + this.taskType = taskType; + return this; + } + + /** + * Get the custom task details based on the task type. + * + * @return the customDetails value + */ + public TaskTypeDetails customDetails() { + return this.customDetails; + } + + /** + * Set the custom task details based on the task type. + * + * @param customDetails the customDetails value to set + * @return the ASRTask object itself. + */ + public ASRTask withCustomDetails(TaskTypeDetails customDetails) { + this.customDetails = customDetails; + return this; + } + + /** + * Get the custom task details based on the task type, if the task type is GroupTaskDetails or one of the types derived from it. + * + * @return the groupTaskCustomDetails value + */ + public GroupTaskDetails groupTaskCustomDetails() { + return this.groupTaskCustomDetails; + } + + /** + * Set the custom task details based on the task type, if the task type is GroupTaskDetails or one of the types derived from it. + * + * @param groupTaskCustomDetails the groupTaskCustomDetails value to set + * @return the ASRTask object itself. + */ + public ASRTask withGroupTaskCustomDetails(GroupTaskDetails groupTaskCustomDetails) { + this.groupTaskCustomDetails = groupTaskCustomDetails; + return this; + } + + /** + * Get the task error details. + * + * @return the errors value + */ + public List errors() { + return this.errors; + } + + /** + * Set the task error details. + * + * @param errors the errors value to set + * @return the ASRTask object itself. + */ + public ASRTask withErrors(List errors) { + this.errors = errors; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInput.java new file mode 100644 index 0000000000000..27dd4bed0b8f6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input required to add a provider. + */ +public class AddRecoveryServicesProviderInput { + /** + * The properties of an add provider request. + */ + @JsonProperty(value = "properties", required = true) + private AddRecoveryServicesProviderInputProperties properties; + + /** + * Get the properties of an add provider request. + * + * @return the properties value + */ + public AddRecoveryServicesProviderInputProperties properties() { + return this.properties; + } + + /** + * Set the properties of an add provider request. + * + * @param properties the properties value to set + * @return the AddRecoveryServicesProviderInput object itself. + */ + public AddRecoveryServicesProviderInput withProperties(AddRecoveryServicesProviderInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInputProperties.java new file mode 100644 index 0000000000000..ea1137050c9a7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddRecoveryServicesProviderInputProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of an add provider request. + */ +public class AddRecoveryServicesProviderInputProperties { + /** + * The name of the machine where the provider is getting added. + */ + @JsonProperty(value = "machineName", required = true) + private String machineName; + + /** + * The identity provider input for DRA authentication. + */ + @JsonProperty(value = "authenticationIdentityInput", required = true) + private IdentityProviderInput authenticationIdentityInput; + + /** + * The identity provider input for resource access. + */ + @JsonProperty(value = "resourceAccessIdentityInput", required = true) + private IdentityProviderInput resourceAccessIdentityInput; + + /** + * Get the name of the machine where the provider is getting added. + * + * @return the machineName value + */ + public String machineName() { + return this.machineName; + } + + /** + * Set the name of the machine where the provider is getting added. + * + * @param machineName the machineName value to set + * @return the AddRecoveryServicesProviderInputProperties object itself. + */ + public AddRecoveryServicesProviderInputProperties withMachineName(String machineName) { + this.machineName = machineName; + return this; + } + + /** + * Get the identity provider input for DRA authentication. + * + * @return the authenticationIdentityInput value + */ + public IdentityProviderInput authenticationIdentityInput() { + return this.authenticationIdentityInput; + } + + /** + * Set the identity provider input for DRA authentication. + * + * @param authenticationIdentityInput the authenticationIdentityInput value to set + * @return the AddRecoveryServicesProviderInputProperties object itself. + */ + public AddRecoveryServicesProviderInputProperties withAuthenticationIdentityInput(IdentityProviderInput authenticationIdentityInput) { + this.authenticationIdentityInput = authenticationIdentityInput; + return this; + } + + /** + * Get the identity provider input for resource access. + * + * @return the resourceAccessIdentityInput value + */ + public IdentityProviderInput resourceAccessIdentityInput() { + return this.resourceAccessIdentityInput; + } + + /** + * Set the identity provider input for resource access. + * + * @param resourceAccessIdentityInput the resourceAccessIdentityInput value to set + * @return the AddRecoveryServicesProviderInputProperties object itself. + */ + public AddRecoveryServicesProviderInputProperties withResourceAccessIdentityInput(IdentityProviderInput resourceAccessIdentityInput) { + this.resourceAccessIdentityInput = resourceAccessIdentityInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequest.java new file mode 100644 index 0000000000000..23123e93a27d1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input required to add vCenter. + */ +public class AddVCenterRequest { + /** + * The properties of an add vCenter request. + */ + @JsonProperty(value = "properties") + private AddVCenterRequestProperties properties; + + /** + * Get the properties of an add vCenter request. + * + * @return the properties value + */ + public AddVCenterRequestProperties properties() { + return this.properties; + } + + /** + * Set the properties of an add vCenter request. + * + * @param properties the properties value to set + * @return the AddVCenterRequest object itself. + */ + public AddVCenterRequest withProperties(AddVCenterRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequestProperties.java new file mode 100644 index 0000000000000..9b22ac46684ae --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AddVCenterRequestProperties.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of an add vCenter request. + */ +public class AddVCenterRequestProperties { + /** + * The friendly name of the vCenter. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The IP address of the vCenter to be discovered. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The process server Id from where the discovery is orchestrated. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The port number for discovery. + */ + @JsonProperty(value = "port") + private String port; + + /** + * The account Id which has privileges to discover the vCenter. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * Get the friendly name of the vCenter. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the friendly name of the vCenter. + * + * @param friendlyName the friendlyName value to set + * @return the AddVCenterRequestProperties object itself. + */ + public AddVCenterRequestProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the IP address of the vCenter to be discovered. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the vCenter to be discovered. + * + * @param ipAddress the ipAddress value to set + * @return the AddVCenterRequestProperties object itself. + */ + public AddVCenterRequestProperties withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the process server Id from where the discovery is orchestrated. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the process server Id from where the discovery is orchestrated. + * + * @param processServerId the processServerId value to set + * @return the AddVCenterRequestProperties object itself. + */ + public AddVCenterRequestProperties withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the port number for discovery. + * + * @return the port value + */ + public String port() { + return this.port; + } + + /** + * Set the port number for discovery. + * + * @param port the port value to set + * @return the AddVCenterRequestProperties object itself. + */ + public AddVCenterRequestProperties withPort(String port) { + this.port = port; + return this; + } + + /** + * Get the account Id which has privileges to discover the vCenter. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the account Id which has privileges to discover the vCenter. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the AddVCenterRequestProperties object itself. + */ + public AddVCenterRequestProperties withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentAutoUpdateStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentAutoUpdateStatus.java new file mode 100644 index 0000000000000..0d5b3f66dd109 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentAutoUpdateStatus.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for AgentAutoUpdateStatus. + */ +public final class AgentAutoUpdateStatus extends ExpandableStringEnum { + /** Static value Disabled for AgentAutoUpdateStatus. */ + public static final AgentAutoUpdateStatus DISABLED = fromString("Disabled"); + + /** Static value Enabled for AgentAutoUpdateStatus. */ + public static final AgentAutoUpdateStatus ENABLED = fromString("Enabled"); + + /** + * Creates or finds a AgentAutoUpdateStatus from its string representation. + * @param name a name to look for + * @return the corresponding AgentAutoUpdateStatus + */ + @JsonCreator + public static AgentAutoUpdateStatus fromString(String name) { + return fromString(name, AgentAutoUpdateStatus.class); + } + + /** + * @return known AgentAutoUpdateStatus values + */ + public static Collection values() { + return values(AgentAutoUpdateStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentVersionStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentVersionStatus.java new file mode 100644 index 0000000000000..04faf1a32810c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AgentVersionStatus.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for AgentVersionStatus. + */ +public final class AgentVersionStatus extends ExpandableStringEnum { + /** Static value Supported for AgentVersionStatus. */ + public static final AgentVersionStatus SUPPORTED = fromString("Supported"); + + /** Static value NotSupported for AgentVersionStatus. */ + public static final AgentVersionStatus NOT_SUPPORTED = fromString("NotSupported"); + + /** Static value Deprecated for AgentVersionStatus. */ + public static final AgentVersionStatus DEPRECATED = fromString("Deprecated"); + + /** Static value UpdateRequired for AgentVersionStatus. */ + public static final AgentVersionStatus UPDATE_REQUIRED = fromString("UpdateRequired"); + + /** Static value SecurityUpdateRequired for AgentVersionStatus. */ + public static final AgentVersionStatus SECURITY_UPDATE_REQUIRED = fromString("SecurityUpdateRequired"); + + /** + * Creates or finds a AgentVersionStatus from its string representation. + * @param name a name to look for + * @return the corresponding AgentVersionStatus + */ + @JsonCreator + public static AgentVersionStatus fromString(String name) { + return fromString(name, AgentVersionStatus.class); + } + + /** + * @return known AgentVersionStatus values + */ + public static Collection values() { + return values(AgentVersionStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Alert.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Alert.java new file mode 100644 index 0000000000000..9d42e41ac01ab --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Alert.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.AlertInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; +import java.util.List; + +/** + * Type representing Alert. + */ +public interface Alert extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + AlertProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the Alert definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithVault, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of Alert definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a Alert definition. + */ + interface Blank extends WithVault { + } + + /** + * The stage of the alert definition allowing to specify Vault. + */ + interface WithVault { + /** + * Specifies . + * @return the next definition stage + */ + WithProperties withExistingVault(); + } + + /** + * The stage of the alert definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The properties of a configure alert request + * @return the next definition stage + */ + WithCreate withProperties(ConfigureAlertRequestProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a Alert update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of Alert update stages. + */ + interface UpdateStages { + /** + * The stage of the alert update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The properties of a configure alert request + * @return the next update stage + */ + Update withProperties(ConfigureAlertRequestProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlertProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlertProperties.java new file mode 100644 index 0000000000000..3a8298cd632ee --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlertProperties.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of an alert. + */ +public class AlertProperties { + /** + * A value indicating whether to send email to subscription administrator. + */ + @JsonProperty(value = "sendToOwners") + private String sendToOwners; + + /** + * The custom email address for sending emails. + */ + @JsonProperty(value = "customEmailAddresses") + private List customEmailAddresses; + + /** + * The locale for the email notification. + */ + @JsonProperty(value = "locale") + private String locale; + + /** + * Get a value indicating whether to send email to subscription administrator. + * + * @return the sendToOwners value + */ + public String sendToOwners() { + return this.sendToOwners; + } + + /** + * Set a value indicating whether to send email to subscription administrator. + * + * @param sendToOwners the sendToOwners value to set + * @return the AlertProperties object itself. + */ + public AlertProperties withSendToOwners(String sendToOwners) { + this.sendToOwners = sendToOwners; + return this; + } + + /** + * Get the custom email address for sending emails. + * + * @return the customEmailAddresses value + */ + public List customEmailAddresses() { + return this.customEmailAddresses; + } + + /** + * Set the custom email address for sending emails. + * + * @param customEmailAddresses the customEmailAddresses value to set + * @return the AlertProperties object itself. + */ + public AlertProperties withCustomEmailAddresses(List customEmailAddresses) { + this.customEmailAddresses = customEmailAddresses; + return this; + } + + /** + * Get the locale for the email notification. + * + * @return the locale value + */ + public String locale() { + return this.locale; + } + + /** + * Set the locale for the email notification. + * + * @param locale the locale value to set + * @return the AlertProperties object itself. + */ + public AlertProperties withLocale(String locale) { + this.locale = locale; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlternateLocationRecoveryOption.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlternateLocationRecoveryOption.java new file mode 100644 index 0000000000000..57cb1912c4112 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AlternateLocationRecoveryOption.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for AlternateLocationRecoveryOption. + */ +public final class AlternateLocationRecoveryOption extends ExpandableStringEnum { + /** Static value CreateVmIfNotFound for AlternateLocationRecoveryOption. */ + public static final AlternateLocationRecoveryOption CREATE_VM_IF_NOT_FOUND = fromString("CreateVmIfNotFound"); + + /** Static value NoAction for AlternateLocationRecoveryOption. */ + public static final AlternateLocationRecoveryOption NO_ACTION = fromString("NoAction"); + + /** + * Creates or finds a AlternateLocationRecoveryOption from its string representation. + * @param name a name to look for + * @return the corresponding AlternateLocationRecoveryOption + */ + @JsonCreator + public static AlternateLocationRecoveryOption fromString(String name) { + return fromString(name, AlternateLocationRecoveryOption.class); + } + + /** + * @return known AlternateLocationRecoveryOption values + */ + public static Collection values() { + return values(AlternateLocationRecoveryOption.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInput.java new file mode 100644 index 0000000000000..115cff61f13a2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input to apply recovery point. + */ +public class ApplyRecoveryPointInput { + /** + * The input properties to apply recovery point. + */ + @JsonProperty(value = "properties") + private ApplyRecoveryPointInputProperties properties; + + /** + * Get the input properties to apply recovery point. + * + * @return the properties value + */ + public ApplyRecoveryPointInputProperties properties() { + return this.properties; + } + + /** + * Set the input properties to apply recovery point. + * + * @param properties the properties value to set + * @return the ApplyRecoveryPointInput object itself. + */ + public ApplyRecoveryPointInput withProperties(ApplyRecoveryPointInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInputProperties.java new file mode 100644 index 0000000000000..52e37c3893a27 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointInputProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input properties to apply recovery point. + */ +public class ApplyRecoveryPointInputProperties { + /** + * The recovery point Id. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * Provider specific input for applying recovery point. + */ + @JsonProperty(value = "providerSpecificDetails") + private ApplyRecoveryPointProviderSpecificInput providerSpecificDetails; + + /** + * Get the recovery point Id. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point Id. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the ApplyRecoveryPointInputProperties object itself. + */ + public ApplyRecoveryPointInputProperties withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + + /** + * Get provider specific input for applying recovery point. + * + * @return the providerSpecificDetails value + */ + public ApplyRecoveryPointProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific input for applying recovery point. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the ApplyRecoveryPointInputProperties object itself. + */ + public ApplyRecoveryPointInputProperties withProviderSpecificDetails(ApplyRecoveryPointProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointProviderSpecificInput.java new file mode 100644 index 0000000000000..8bc28ab08b6fd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ApplyRecoveryPointProviderSpecificInput.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific input for apply recovery point. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ApplyRecoveryPointProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AApplyRecoveryPointInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureApplyRecoveryPointInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2ApplyRecoveryPointInput.class) +}) +public class ApplyRecoveryPointProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AsrJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AsrJobDetails.java new file mode 100644 index 0000000000000..c0a2be27ac39e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AsrJobDetails.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents job details based on specific job type. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AsrJobDetails") +public class AsrJobDetails extends JobDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AutomationRunbookTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AutomationRunbookTaskDetails.java new file mode 100644 index 0000000000000..b00be4504ab98 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AutomationRunbookTaskDetails.java @@ -0,0 +1,255 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the task details for an automation runbook. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AutomationRunbookTaskDetails") +public class AutomationRunbookTaskDetails extends TaskTypeDetails { + /** + * The recovery plan task name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The cloud service of the automation runbook account. + */ + @JsonProperty(value = "cloudServiceName") + private String cloudServiceName; + + /** + * The subscription Id of the automation runbook account. + */ + @JsonProperty(value = "subscriptionId") + private String subscriptionId; + + /** + * The automation account name of the runbook. + */ + @JsonProperty(value = "accountName") + private String accountName; + + /** + * The runbook Id. + */ + @JsonProperty(value = "runbookId") + private String runbookId; + + /** + * The runbook name. + */ + @JsonProperty(value = "runbookName") + private String runbookName; + + /** + * The job Id of the runbook execution. + */ + @JsonProperty(value = "jobId") + private String jobId; + + /** + * The execution output of the runbook. + */ + @JsonProperty(value = "jobOutput") + private String jobOutput; + + /** + * A value indicating whether it is a primary side script or not. + */ + @JsonProperty(value = "isPrimarySideScript") + private Boolean isPrimarySideScript; + + /** + * Get the recovery plan task name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the recovery plan task name. + * + * @param name the name value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the cloud service of the automation runbook account. + * + * @return the cloudServiceName value + */ + public String cloudServiceName() { + return this.cloudServiceName; + } + + /** + * Set the cloud service of the automation runbook account. + * + * @param cloudServiceName the cloudServiceName value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withCloudServiceName(String cloudServiceName) { + this.cloudServiceName = cloudServiceName; + return this; + } + + /** + * Get the subscription Id of the automation runbook account. + * + * @return the subscriptionId value + */ + public String subscriptionId() { + return this.subscriptionId; + } + + /** + * Set the subscription Id of the automation runbook account. + * + * @param subscriptionId the subscriptionId value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + return this; + } + + /** + * Get the automation account name of the runbook. + * + * @return the accountName value + */ + public String accountName() { + return this.accountName; + } + + /** + * Set the automation account name of the runbook. + * + * @param accountName the accountName value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withAccountName(String accountName) { + this.accountName = accountName; + return this; + } + + /** + * Get the runbook Id. + * + * @return the runbookId value + */ + public String runbookId() { + return this.runbookId; + } + + /** + * Set the runbook Id. + * + * @param runbookId the runbookId value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withRunbookId(String runbookId) { + this.runbookId = runbookId; + return this; + } + + /** + * Get the runbook name. + * + * @return the runbookName value + */ + public String runbookName() { + return this.runbookName; + } + + /** + * Set the runbook name. + * + * @param runbookName the runbookName value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withRunbookName(String runbookName) { + this.runbookName = runbookName; + return this; + } + + /** + * Get the job Id of the runbook execution. + * + * @return the jobId value + */ + public String jobId() { + return this.jobId; + } + + /** + * Set the job Id of the runbook execution. + * + * @param jobId the jobId value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withJobId(String jobId) { + this.jobId = jobId; + return this; + } + + /** + * Get the execution output of the runbook. + * + * @return the jobOutput value + */ + public String jobOutput() { + return this.jobOutput; + } + + /** + * Set the execution output of the runbook. + * + * @param jobOutput the jobOutput value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withJobOutput(String jobOutput) { + this.jobOutput = jobOutput; + return this; + } + + /** + * Get a value indicating whether it is a primary side script or not. + * + * @return the isPrimarySideScript value + */ + public Boolean isPrimarySideScript() { + return this.isPrimarySideScript; + } + + /** + * Set a value indicating whether it is a primary side script or not. + * + * @param isPrimarySideScript the isPrimarySideScript value to set + * @return the AutomationRunbookTaskDetails object itself. + */ + public AutomationRunbookTaskDetails withIsPrimarySideScript(Boolean isPrimarySideScript) { + this.isPrimarySideScript = isPrimarySideScript; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricCreationInput.java new file mode 100644 index 0000000000000..a5b6e11fb93df --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricCreationInput.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Fabric provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("Azure") +public class AzureFabricCreationInput extends FabricSpecificCreationInput { + /** + * The Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set the Location. + * + * @param location the location value to set + * @return the AzureFabricCreationInput object itself. + */ + public AzureFabricCreationInput withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricSpecificDetails.java new file mode 100644 index 0000000000000..5c90ae41ff7b5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureFabricSpecificDetails.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Azure Fabric Specific Details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("Azure") +public class AzureFabricSpecificDetails extends FabricSpecificDetails { + /** + * The Location for the Azure fabric. + */ + @JsonProperty(value = "location") + private String location; + + /** + * The container Ids for the Azure fabric. + */ + @JsonProperty(value = "containerIds") + private List containerIds; + + /** + * Get the Location for the Azure fabric. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set the Location for the Azure fabric. + * + * @param location the location value to set + * @return the AzureFabricSpecificDetails object itself. + */ + public AzureFabricSpecificDetails withLocation(String location) { + this.location = location; + return this; + } + + /** + * Get the container Ids for the Azure fabric. + * + * @return the containerIds value + */ + public List containerIds() { + return this.containerIds; + } + + /** + * Set the container Ids for the Azure fabric. + * + * @param containerIds the containerIds value to set + * @return the AzureFabricSpecificDetails object itself. + */ + public AzureFabricSpecificDetails withContainerIds(List containerIds) { + this.containerIds = containerIds; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureCreateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureCreateNetworkMappingInput.java new file mode 100644 index 0000000000000..1bfa9a4d25132 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureCreateNetworkMappingInput.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Create network mappings input properties/behavior specific to Azure to Azure + * Network mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AzureToAzure") +public class AzureToAzureCreateNetworkMappingInput extends FabricSpecificCreateNetworkMappingInput { + /** + * The primary azure vnet Id. + */ + @JsonProperty(value = "primaryNetworkId") + private String primaryNetworkId; + + /** + * Get the primary azure vnet Id. + * + * @return the primaryNetworkId value + */ + public String primaryNetworkId() { + return this.primaryNetworkId; + } + + /** + * Set the primary azure vnet Id. + * + * @param primaryNetworkId the primaryNetworkId value to set + * @return the AzureToAzureCreateNetworkMappingInput object itself. + */ + public AzureToAzureCreateNetworkMappingInput withPrimaryNetworkId(String primaryNetworkId) { + this.primaryNetworkId = primaryNetworkId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureNetworkMappingSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureNetworkMappingSettings.java new file mode 100644 index 0000000000000..c135d7c5c53df --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureNetworkMappingSettings.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * A2A Network Mapping fabric specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AzureToAzure") +public class AzureToAzureNetworkMappingSettings extends NetworkMappingFabricSpecificSettings { + /** + * The primary fabric location. + */ + @JsonProperty(value = "primaryFabricLocation") + private String primaryFabricLocation; + + /** + * The recovery fabric location. + */ + @JsonProperty(value = "recoveryFabricLocation") + private String recoveryFabricLocation; + + /** + * Get the primary fabric location. + * + * @return the primaryFabricLocation value + */ + public String primaryFabricLocation() { + return this.primaryFabricLocation; + } + + /** + * Set the primary fabric location. + * + * @param primaryFabricLocation the primaryFabricLocation value to set + * @return the AzureToAzureNetworkMappingSettings object itself. + */ + public AzureToAzureNetworkMappingSettings withPrimaryFabricLocation(String primaryFabricLocation) { + this.primaryFabricLocation = primaryFabricLocation; + return this; + } + + /** + * Get the recovery fabric location. + * + * @return the recoveryFabricLocation value + */ + public String recoveryFabricLocation() { + return this.recoveryFabricLocation; + } + + /** + * Set the recovery fabric location. + * + * @param recoveryFabricLocation the recoveryFabricLocation value to set + * @return the AzureToAzureNetworkMappingSettings object itself. + */ + public AzureToAzureNetworkMappingSettings withRecoveryFabricLocation(String recoveryFabricLocation) { + this.recoveryFabricLocation = recoveryFabricLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureUpdateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureUpdateNetworkMappingInput.java new file mode 100644 index 0000000000000..aac96435edfa0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureUpdateNetworkMappingInput.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Updates network mappings input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AzureToAzure") +public class AzureToAzureUpdateNetworkMappingInput extends FabricSpecificUpdateNetworkMappingInput { + /** + * The primary azure vnet Id. + */ + @JsonProperty(value = "primaryNetworkId") + private String primaryNetworkId; + + /** + * Get the primary azure vnet Id. + * + * @return the primaryNetworkId value + */ + public String primaryNetworkId() { + return this.primaryNetworkId; + } + + /** + * Set the primary azure vnet Id. + * + * @param primaryNetworkId the primaryNetworkId value to set + * @return the AzureToAzureUpdateNetworkMappingInput object itself. + */ + public AzureToAzureUpdateNetworkMappingInput withPrimaryNetworkId(String primaryNetworkId) { + this.primaryNetworkId = primaryNetworkId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureVmSyncedConfigDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureVmSyncedConfigDetails.java new file mode 100644 index 0000000000000..171840bedf4e6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureToAzureVmSyncedConfigDetails.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Map; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure to Azure VM synced configuration details. + */ +public class AzureToAzureVmSyncedConfigDetails { + /** + * The Azure VM tags. + */ + @JsonProperty(value = "tags") + private Map tags; + + /** + * The Azure role assignments. + */ + @JsonProperty(value = "roleAssignments") + private List roleAssignments; + + /** + * The Azure VM input endpoints. + */ + @JsonProperty(value = "inputEndpoints") + private List inputEndpoints; + + /** + * Get the Azure VM tags. + * + * @return the tags value + */ + public Map tags() { + return this.tags; + } + + /** + * Set the Azure VM tags. + * + * @param tags the tags value to set + * @return the AzureToAzureVmSyncedConfigDetails object itself. + */ + public AzureToAzureVmSyncedConfigDetails withTags(Map tags) { + this.tags = tags; + return this; + } + + /** + * Get the Azure role assignments. + * + * @return the roleAssignments value + */ + public List roleAssignments() { + return this.roleAssignments; + } + + /** + * Set the Azure role assignments. + * + * @param roleAssignments the roleAssignments value to set + * @return the AzureToAzureVmSyncedConfigDetails object itself. + */ + public AzureToAzureVmSyncedConfigDetails withRoleAssignments(List roleAssignments) { + this.roleAssignments = roleAssignments; + return this; + } + + /** + * Get the Azure VM input endpoints. + * + * @return the inputEndpoints value + */ + public List inputEndpoints() { + return this.inputEndpoints; + } + + /** + * Set the Azure VM input endpoints. + * + * @param inputEndpoints the inputEndpoints value to set + * @return the AzureToAzureVmSyncedConfigDetails object itself. + */ + public AzureToAzureVmSyncedConfigDetails withInputEndpoints(List inputEndpoints) { + this.inputEndpoints = inputEndpoints; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureVmDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureVmDiskDetails.java new file mode 100644 index 0000000000000..a9bcacd4396f7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/AzureVmDiskDetails.java @@ -0,0 +1,199 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Disk details for E2A provider. + */ +public class AzureVmDiskDetails { + /** + * VHD type. + */ + @JsonProperty(value = "vhdType") + private String vhdType; + + /** + * The VHD id. + */ + @JsonProperty(value = "vhdId") + private String vhdId; + + /** + * VHD name. + */ + @JsonProperty(value = "vhdName") + private String vhdName; + + /** + * Max side in MB. + */ + @JsonProperty(value = "maxSizeMB") + private String maxSizeMB; + + /** + * Blob uri of the Azure disk. + */ + @JsonProperty(value = "targetDiskLocation") + private String targetDiskLocation; + + /** + * The target Azure disk name. + */ + @JsonProperty(value = "targetDiskName") + private String targetDiskName; + + /** + * Ordinal\LunId of the disk for the Azure VM. + */ + @JsonProperty(value = "lunId") + private String lunId; + + /** + * Get vHD type. + * + * @return the vhdType value + */ + public String vhdType() { + return this.vhdType; + } + + /** + * Set vHD type. + * + * @param vhdType the vhdType value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withVhdType(String vhdType) { + this.vhdType = vhdType; + return this; + } + + /** + * Get the VHD id. + * + * @return the vhdId value + */ + public String vhdId() { + return this.vhdId; + } + + /** + * Set the VHD id. + * + * @param vhdId the vhdId value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withVhdId(String vhdId) { + this.vhdId = vhdId; + return this; + } + + /** + * Get vHD name. + * + * @return the vhdName value + */ + public String vhdName() { + return this.vhdName; + } + + /** + * Set vHD name. + * + * @param vhdName the vhdName value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withVhdName(String vhdName) { + this.vhdName = vhdName; + return this; + } + + /** + * Get max side in MB. + * + * @return the maxSizeMB value + */ + public String maxSizeMB() { + return this.maxSizeMB; + } + + /** + * Set max side in MB. + * + * @param maxSizeMB the maxSizeMB value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withMaxSizeMB(String maxSizeMB) { + this.maxSizeMB = maxSizeMB; + return this; + } + + /** + * Get blob uri of the Azure disk. + * + * @return the targetDiskLocation value + */ + public String targetDiskLocation() { + return this.targetDiskLocation; + } + + /** + * Set blob uri of the Azure disk. + * + * @param targetDiskLocation the targetDiskLocation value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withTargetDiskLocation(String targetDiskLocation) { + this.targetDiskLocation = targetDiskLocation; + return this; + } + + /** + * Get the target Azure disk name. + * + * @return the targetDiskName value + */ + public String targetDiskName() { + return this.targetDiskName; + } + + /** + * Set the target Azure disk name. + * + * @param targetDiskName the targetDiskName value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withTargetDiskName(String targetDiskName) { + this.targetDiskName = targetDiskName; + return this; + } + + /** + * Get ordinal\LunId of the disk for the Azure VM. + * + * @return the lunId value + */ + public String lunId() { + return this.lunId; + } + + /** + * Set ordinal\LunId of the disk for the Azure VM. + * + * @param lunId the lunId value to set + * @return the AzureVmDiskDetails object itself. + */ + public AzureVmDiskDetails withLunId(String lunId) { + this.lunId = lunId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ComputeSizeErrorDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ComputeSizeErrorDetails.java new file mode 100644 index 0000000000000..4004f14a340ee --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ComputeSizeErrorDetails.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents the error used to indicate why the target compute size is not + * applicable. + */ +public class ComputeSizeErrorDetails { + /** + * The error message. + */ + @JsonProperty(value = "message") + private String message; + + /** + * The severity of the error. + */ + @JsonProperty(value = "severity") + private String severity; + + /** + * Get the error message. + * + * @return the message value + */ + public String message() { + return this.message; + } + + /** + * Set the error message. + * + * @param message the message value to set + * @return the ComputeSizeErrorDetails object itself. + */ + public ComputeSizeErrorDetails withMessage(String message) { + this.message = message; + return this; + } + + /** + * Get the severity of the error. + * + * @return the severity value + */ + public String severity() { + return this.severity; + } + + /** + * Set the severity of the error. + * + * @param severity the severity value to set + * @return the ComputeSizeErrorDetails object itself. + */ + public ComputeSizeErrorDetails withSeverity(String severity) { + this.severity = severity; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigurationSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigurationSettings.java new file mode 100644 index 0000000000000..a659422825b4c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigurationSettings.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Replication provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ConfigurationSettings") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "HyperVVirtualMachine", value = HyperVVirtualMachineDetails.class), + @JsonSubTypes.Type(name = "ReplicationGroupDetails", value = ReplicationGroupDetails.class), + @JsonSubTypes.Type(name = "VmmVirtualMachine", value = VmmVirtualMachineDetails.class), + @JsonSubTypes.Type(name = "VMwareVirtualMachine", value = VMwareVirtualMachineDetails.class) +}) +public class ConfigurationSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequest.java new file mode 100644 index 0000000000000..4240ac41ce64c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Request to configure alerts for the system. + */ +public class ConfigureAlertRequest { + /** + * The properties of a configure alert request. + */ + @JsonProperty(value = "properties") + private ConfigureAlertRequestProperties properties; + + /** + * Get the properties of a configure alert request. + * + * @return the properties value + */ + public ConfigureAlertRequestProperties properties() { + return this.properties; + } + + /** + * Set the properties of a configure alert request. + * + * @param properties the properties value to set + * @return the ConfigureAlertRequest object itself. + */ + public ConfigureAlertRequest withProperties(ConfigureAlertRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequestProperties.java new file mode 100644 index 0000000000000..978826ca3a524 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConfigureAlertRequestProperties.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Properties of a configure alert request. + */ +public class ConfigureAlertRequestProperties { + /** + * A value indicating whether to send email to subscription administrator. + */ + @JsonProperty(value = "sendToOwners") + private String sendToOwners; + + /** + * The custom email address for sending emails. + */ + @JsonProperty(value = "customEmailAddresses") + private List customEmailAddresses; + + /** + * The locale for the email notification. + */ + @JsonProperty(value = "locale") + private String locale; + + /** + * Get a value indicating whether to send email to subscription administrator. + * + * @return the sendToOwners value + */ + public String sendToOwners() { + return this.sendToOwners; + } + + /** + * Set a value indicating whether to send email to subscription administrator. + * + * @param sendToOwners the sendToOwners value to set + * @return the ConfigureAlertRequestProperties object itself. + */ + public ConfigureAlertRequestProperties withSendToOwners(String sendToOwners) { + this.sendToOwners = sendToOwners; + return this; + } + + /** + * Get the custom email address for sending emails. + * + * @return the customEmailAddresses value + */ + public List customEmailAddresses() { + return this.customEmailAddresses; + } + + /** + * Set the custom email address for sending emails. + * + * @param customEmailAddresses the customEmailAddresses value to set + * @return the ConfigureAlertRequestProperties object itself. + */ + public ConfigureAlertRequestProperties withCustomEmailAddresses(List customEmailAddresses) { + this.customEmailAddresses = customEmailAddresses; + return this; + } + + /** + * Get the locale for the email notification. + * + * @return the locale value + */ + public String locale() { + return this.locale; + } + + /** + * Set the locale for the email notification. + * + * @param locale the locale value to set + * @return the ConfigureAlertRequestProperties object itself. + */ + public ConfigureAlertRequestProperties withLocale(String locale) { + this.locale = locale; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConsistencyCheckTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConsistencyCheckTaskDetails.java new file mode 100644 index 0000000000000..1a35131a5668e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ConsistencyCheckTaskDetails.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class contains monitoring details of all the inconsistent Protected + * Entities in Vmm. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ConsistencyCheckTaskDetails") +public class ConsistencyCheckTaskDetails extends TaskTypeDetails { + /** + * The list of inconsistent Vm details. + */ + @JsonProperty(value = "vmDetails") + private List vmDetails; + + /** + * Get the list of inconsistent Vm details. + * + * @return the vmDetails value + */ + public List vmDetails() { + return this.vmDetails; + } + + /** + * Set the list of inconsistent Vm details. + * + * @param vmDetails the vmDetails value to set + * @return the ConsistencyCheckTaskDetails object itself. + */ + public ConsistencyCheckTaskDetails withVmDetails(List vmDetails) { + this.vmDetails = vmDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInput.java new file mode 100644 index 0000000000000..e7be2be163b26 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Create network mappings input. + */ +public class CreateNetworkMappingInput { + /** + * Input properties for creating network mapping. + */ + @JsonProperty(value = "properties") + private CreateNetworkMappingInputProperties properties; + + /** + * Get input properties for creating network mapping. + * + * @return the properties value + */ + public CreateNetworkMappingInputProperties properties() { + return this.properties; + } + + /** + * Set input properties for creating network mapping. + * + * @param properties the properties value to set + * @return the CreateNetworkMappingInput object itself. + */ + public CreateNetworkMappingInput withProperties(CreateNetworkMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInputProperties.java new file mode 100644 index 0000000000000..359b2a2ad5242 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateNetworkMappingInputProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Common input details for network mapping operation. + */ +public class CreateNetworkMappingInputProperties { + /** + * Recovery fabric Name. + */ + @JsonProperty(value = "recoveryFabricName") + private String recoveryFabricName; + + /** + * Recovery network Id. + */ + @JsonProperty(value = "recoveryNetworkId") + private String recoveryNetworkId; + + /** + * Fabric specific input properties. + */ + @JsonProperty(value = "fabricSpecificDetails") + private FabricSpecificCreateNetworkMappingInput fabricSpecificDetails; + + /** + * Get recovery fabric Name. + * + * @return the recoveryFabricName value + */ + public String recoveryFabricName() { + return this.recoveryFabricName; + } + + /** + * Set recovery fabric Name. + * + * @param recoveryFabricName the recoveryFabricName value to set + * @return the CreateNetworkMappingInputProperties object itself. + */ + public CreateNetworkMappingInputProperties withRecoveryFabricName(String recoveryFabricName) { + this.recoveryFabricName = recoveryFabricName; + return this; + } + + /** + * Get recovery network Id. + * + * @return the recoveryNetworkId value + */ + public String recoveryNetworkId() { + return this.recoveryNetworkId; + } + + /** + * Set recovery network Id. + * + * @param recoveryNetworkId the recoveryNetworkId value to set + * @return the CreateNetworkMappingInputProperties object itself. + */ + public CreateNetworkMappingInputProperties withRecoveryNetworkId(String recoveryNetworkId) { + this.recoveryNetworkId = recoveryNetworkId; + return this; + } + + /** + * Get fabric specific input properties. + * + * @return the fabricSpecificDetails value + */ + public FabricSpecificCreateNetworkMappingInput fabricSpecificDetails() { + return this.fabricSpecificDetails; + } + + /** + * Set fabric specific input properties. + * + * @param fabricSpecificDetails the fabricSpecificDetails value to set + * @return the CreateNetworkMappingInputProperties object itself. + */ + public CreateNetworkMappingInputProperties withFabricSpecificDetails(FabricSpecificCreateNetworkMappingInput fabricSpecificDetails) { + this.fabricSpecificDetails = fabricSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInput.java new file mode 100644 index 0000000000000..645cdcbd8c812 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Protection Policy input. + */ +public class CreatePolicyInput { + /** + * Policy creation properties. + */ + @JsonProperty(value = "properties") + private CreatePolicyInputProperties properties; + + /** + * Get policy creation properties. + * + * @return the properties value + */ + public CreatePolicyInputProperties properties() { + return this.properties; + } + + /** + * Set policy creation properties. + * + * @param properties the properties value to set + * @return the CreatePolicyInput object itself. + */ + public CreatePolicyInput withProperties(CreatePolicyInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInputProperties.java new file mode 100644 index 0000000000000..e9c927741f300 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreatePolicyInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Policy creation properties. + */ +public class CreatePolicyInputProperties { + /** + * The ReplicationProviderSettings. + */ + @JsonProperty(value = "providerSpecificInput") + private PolicyProviderSpecificInput providerSpecificInput; + + /** + * Get the ReplicationProviderSettings. + * + * @return the providerSpecificInput value + */ + public PolicyProviderSpecificInput providerSpecificInput() { + return this.providerSpecificInput; + } + + /** + * Set the ReplicationProviderSettings. + * + * @param providerSpecificInput the providerSpecificInput value to set + * @return the CreatePolicyInputProperties object itself. + */ + public CreatePolicyInputProperties withProviderSpecificInput(PolicyProviderSpecificInput providerSpecificInput) { + this.providerSpecificInput = providerSpecificInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInput.java new file mode 100644 index 0000000000000..1e545e4a10440 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Create protection container input. + */ +public class CreateProtectionContainerInput { + /** + * Create protection container input properties. + */ + @JsonProperty(value = "properties") + private CreateProtectionContainerInputProperties properties; + + /** + * Get create protection container input properties. + * + * @return the properties value + */ + public CreateProtectionContainerInputProperties properties() { + return this.properties; + } + + /** + * Set create protection container input properties. + * + * @param properties the properties value to set + * @return the CreateProtectionContainerInput object itself. + */ + public CreateProtectionContainerInput withProperties(CreateProtectionContainerInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInputProperties.java new file mode 100644 index 0000000000000..a7a6024f03d28 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerInputProperties.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Create protection container input properties. + */ +public class CreateProtectionContainerInputProperties { + /** + * Provider specific inputs for container creation. + */ + @JsonProperty(value = "providerSpecificInput") + private List providerSpecificInput; + + /** + * Get provider specific inputs for container creation. + * + * @return the providerSpecificInput value + */ + public List providerSpecificInput() { + return this.providerSpecificInput; + } + + /** + * Set provider specific inputs for container creation. + * + * @param providerSpecificInput the providerSpecificInput value to set + * @return the CreateProtectionContainerInputProperties object itself. + */ + public CreateProtectionContainerInputProperties withProviderSpecificInput(List providerSpecificInput) { + this.providerSpecificInput = providerSpecificInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInput.java new file mode 100644 index 0000000000000..ad4f9ad412628 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Configure pairing input. + */ +public class CreateProtectionContainerMappingInput { + /** + * Configure protection input properties. + */ + @JsonProperty(value = "properties") + private CreateProtectionContainerMappingInputProperties properties; + + /** + * Get configure protection input properties. + * + * @return the properties value + */ + public CreateProtectionContainerMappingInputProperties properties() { + return this.properties; + } + + /** + * Set configure protection input properties. + * + * @param properties the properties value to set + * @return the CreateProtectionContainerMappingInput object itself. + */ + public CreateProtectionContainerMappingInput withProperties(CreateProtectionContainerMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInputProperties.java new file mode 100644 index 0000000000000..71054881d0299 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateProtectionContainerMappingInputProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Configure pairing input properties. + */ +public class CreateProtectionContainerMappingInputProperties { + /** + * The target unique protection container name. + */ + @JsonProperty(value = "targetProtectionContainerId") + private String targetProtectionContainerId; + + /** + * Applicable policy. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * Provider specific input for pairing. + */ + @JsonProperty(value = "providerSpecificInput") + private ReplicationProviderSpecificContainerMappingInput providerSpecificInput; + + /** + * Get the target unique protection container name. + * + * @return the targetProtectionContainerId value + */ + public String targetProtectionContainerId() { + return this.targetProtectionContainerId; + } + + /** + * Set the target unique protection container name. + * + * @param targetProtectionContainerId the targetProtectionContainerId value to set + * @return the CreateProtectionContainerMappingInputProperties object itself. + */ + public CreateProtectionContainerMappingInputProperties withTargetProtectionContainerId(String targetProtectionContainerId) { + this.targetProtectionContainerId = targetProtectionContainerId; + return this; + } + + /** + * Get applicable policy. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set applicable policy. + * + * @param policyId the policyId value to set + * @return the CreateProtectionContainerMappingInputProperties object itself. + */ + public CreateProtectionContainerMappingInputProperties withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get provider specific input for pairing. + * + * @return the providerSpecificInput value + */ + public ReplicationProviderSpecificContainerMappingInput providerSpecificInput() { + return this.providerSpecificInput; + } + + /** + * Set provider specific input for pairing. + * + * @param providerSpecificInput the providerSpecificInput value to set + * @return the CreateProtectionContainerMappingInputProperties object itself. + */ + public CreateProtectionContainerMappingInputProperties withProviderSpecificInput(ReplicationProviderSpecificContainerMappingInput providerSpecificInput) { + this.providerSpecificInput = providerSpecificInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInput.java new file mode 100644 index 0000000000000..5756fff8dd1f6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Create recovery plan input class. + */ +public class CreateRecoveryPlanInput { + /** + * Recovery plan creation properties. + */ + @JsonProperty(value = "properties", required = true) + private CreateRecoveryPlanInputProperties properties; + + /** + * Get recovery plan creation properties. + * + * @return the properties value + */ + public CreateRecoveryPlanInputProperties properties() { + return this.properties; + } + + /** + * Set recovery plan creation properties. + * + * @param properties the properties value to set + * @return the CreateRecoveryPlanInput object itself. + */ + public CreateRecoveryPlanInput withProperties(CreateRecoveryPlanInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInputProperties.java new file mode 100644 index 0000000000000..1f6e4b7816e9d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CreateRecoveryPlanInputProperties.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan creation properties. + */ +public class CreateRecoveryPlanInputProperties { + /** + * The primary fabric Id. + */ + @JsonProperty(value = "primaryFabricId", required = true) + private String primaryFabricId; + + /** + * The recovery fabric Id. + */ + @JsonProperty(value = "recoveryFabricId", required = true) + private String recoveryFabricId; + + /** + * The failover deployment model. Possible values include: 'NotApplicable', + * 'Classic', 'ResourceManager'. + */ + @JsonProperty(value = "failoverDeploymentModel") + private FailoverDeploymentModel failoverDeploymentModel; + + /** + * The recovery plan groups. + */ + @JsonProperty(value = "groups", required = true) + private List groups; + + /** + * Get the primary fabric Id. + * + * @return the primaryFabricId value + */ + public String primaryFabricId() { + return this.primaryFabricId; + } + + /** + * Set the primary fabric Id. + * + * @param primaryFabricId the primaryFabricId value to set + * @return the CreateRecoveryPlanInputProperties object itself. + */ + public CreateRecoveryPlanInputProperties withPrimaryFabricId(String primaryFabricId) { + this.primaryFabricId = primaryFabricId; + return this; + } + + /** + * Get the recovery fabric Id. + * + * @return the recoveryFabricId value + */ + public String recoveryFabricId() { + return this.recoveryFabricId; + } + + /** + * Set the recovery fabric Id. + * + * @param recoveryFabricId the recoveryFabricId value to set + * @return the CreateRecoveryPlanInputProperties object itself. + */ + public CreateRecoveryPlanInputProperties withRecoveryFabricId(String recoveryFabricId) { + this.recoveryFabricId = recoveryFabricId; + return this; + } + + /** + * Get the failover deployment model. Possible values include: 'NotApplicable', 'Classic', 'ResourceManager'. + * + * @return the failoverDeploymentModel value + */ + public FailoverDeploymentModel failoverDeploymentModel() { + return this.failoverDeploymentModel; + } + + /** + * Set the failover deployment model. Possible values include: 'NotApplicable', 'Classic', 'ResourceManager'. + * + * @param failoverDeploymentModel the failoverDeploymentModel value to set + * @return the CreateRecoveryPlanInputProperties object itself. + */ + public CreateRecoveryPlanInputProperties withFailoverDeploymentModel(FailoverDeploymentModel failoverDeploymentModel) { + this.failoverDeploymentModel = failoverDeploymentModel; + return this; + } + + /** + * Get the recovery plan groups. + * + * @return the groups value + */ + public List groups() { + return this.groups; + } + + /** + * Set the recovery plan groups. + * + * @param groups the groups value to set + * @return the CreateRecoveryPlanInputProperties object itself. + */ + public CreateRecoveryPlanInputProperties withGroups(List groups) { + this.groups = groups; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentJobDetails.java new file mode 100644 index 0000000000000..156c4dacf2928 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentJobDetails.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Current job details of the migration item. + */ +public class CurrentJobDetails { + /** + * The job name. + */ + @JsonProperty(value = "jobName") + private String jobName; + + /** + * The ARM Id of the job being executed. + */ + @JsonProperty(value = "jobId") + private String jobId; + + /** + * The start time of the job. + */ + @JsonProperty(value = "startTime") + private DateTime startTime; + + /** + * Get the job name. + * + * @return the jobName value + */ + public String jobName() { + return this.jobName; + } + + /** + * Set the job name. + * + * @param jobName the jobName value to set + * @return the CurrentJobDetails object itself. + */ + public CurrentJobDetails withJobName(String jobName) { + this.jobName = jobName; + return this; + } + + /** + * Get the ARM Id of the job being executed. + * + * @return the jobId value + */ + public String jobId() { + return this.jobId; + } + + /** + * Set the ARM Id of the job being executed. + * + * @param jobId the jobId value to set + * @return the CurrentJobDetails object itself. + */ + public CurrentJobDetails withJobId(String jobId) { + this.jobId = jobId; + return this; + } + + /** + * Get the start time of the job. + * + * @return the startTime value + */ + public DateTime startTime() { + return this.startTime; + } + + /** + * Set the start time of the job. + * + * @param startTime the startTime value to set + * @return the CurrentJobDetails object itself. + */ + public CurrentJobDetails withStartTime(DateTime startTime) { + this.startTime = startTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentScenarioDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentScenarioDetails.java new file mode 100644 index 0000000000000..6ad4ad82c9286 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/CurrentScenarioDetails.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Current scenario details of the protected entity. + */ +public class CurrentScenarioDetails { + /** + * Scenario name. + */ + @JsonProperty(value = "scenarioName") + private String scenarioName; + + /** + * ARM Id of the job being executed. + */ + @JsonProperty(value = "jobId") + private String jobId; + + /** + * Start time of the workflow. + */ + @JsonProperty(value = "startTime") + private DateTime startTime; + + /** + * Get scenario name. + * + * @return the scenarioName value + */ + public String scenarioName() { + return this.scenarioName; + } + + /** + * Set scenario name. + * + * @param scenarioName the scenarioName value to set + * @return the CurrentScenarioDetails object itself. + */ + public CurrentScenarioDetails withScenarioName(String scenarioName) { + this.scenarioName = scenarioName; + return this; + } + + /** + * Get aRM Id of the job being executed. + * + * @return the jobId value + */ + public String jobId() { + return this.jobId; + } + + /** + * Set aRM Id of the job being executed. + * + * @param jobId the jobId value to set + * @return the CurrentScenarioDetails object itself. + */ + public CurrentScenarioDetails withJobId(String jobId) { + this.jobId = jobId; + return this; + } + + /** + * Get start time of the workflow. + * + * @return the startTime value + */ + public DateTime startTime() { + return this.startTime; + } + + /** + * Set start time of the workflow. + * + * @param startTime the startTime value to set + * @return the CurrentScenarioDetails object itself. + */ + public CurrentScenarioDetails withStartTime(DateTime startTime) { + this.startTime = startTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataStore.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataStore.java new file mode 100644 index 0000000000000..68c699c8f7e1f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataStore.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The data store details of the MT. + */ +public class DataStore { + /** + * The symbolic name of data store. + */ + @JsonProperty(value = "symbolicName") + private String symbolicName; + + /** + * The uuid of data store. + */ + @JsonProperty(value = "uuid") + private String uuid; + + /** + * The capacity of data store in GBs. + */ + @JsonProperty(value = "capacity") + private String capacity; + + /** + * The free space of data store in GBs. + */ + @JsonProperty(value = "freeSpace") + private String freeSpace; + + /** + * The type of data store. + */ + @JsonProperty(value = "type") + private String type; + + /** + * Get the symbolic name of data store. + * + * @return the symbolicName value + */ + public String symbolicName() { + return this.symbolicName; + } + + /** + * Set the symbolic name of data store. + * + * @param symbolicName the symbolicName value to set + * @return the DataStore object itself. + */ + public DataStore withSymbolicName(String symbolicName) { + this.symbolicName = symbolicName; + return this; + } + + /** + * Get the uuid of data store. + * + * @return the uuid value + */ + public String uuid() { + return this.uuid; + } + + /** + * Set the uuid of data store. + * + * @param uuid the uuid value to set + * @return the DataStore object itself. + */ + public DataStore withUuid(String uuid) { + this.uuid = uuid; + return this; + } + + /** + * Get the capacity of data store in GBs. + * + * @return the capacity value + */ + public String capacity() { + return this.capacity; + } + + /** + * Set the capacity of data store in GBs. + * + * @param capacity the capacity value to set + * @return the DataStore object itself. + */ + public DataStore withCapacity(String capacity) { + this.capacity = capacity; + return this; + } + + /** + * Get the free space of data store in GBs. + * + * @return the freeSpace value + */ + public String freeSpace() { + return this.freeSpace; + } + + /** + * Set the free space of data store in GBs. + * + * @param freeSpace the freeSpace value to set + * @return the DataStore object itself. + */ + public DataStore withFreeSpace(String freeSpace) { + this.freeSpace = freeSpace; + return this; + } + + /** + * Get the type of data store. + * + * @return the type value + */ + public String type() { + return this.type; + } + + /** + * Set the type of data store. + * + * @param type the type value to set + * @return the DataStore object itself. + */ + public DataStore withType(String type) { + this.type = type; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataSyncStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataSyncStatus.java new file mode 100644 index 0000000000000..01b6106726899 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DataSyncStatus.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for DataSyncStatus. + */ +public final class DataSyncStatus extends ExpandableStringEnum { + /** Static value ForDownTime for DataSyncStatus. */ + public static final DataSyncStatus FOR_DOWN_TIME = fromString("ForDownTime"); + + /** Static value ForSynchronization for DataSyncStatus. */ + public static final DataSyncStatus FOR_SYNCHRONIZATION = fromString("ForSynchronization"); + + /** + * Creates or finds a DataSyncStatus from its string representation. + * @param name a name to look for + * @return the corresponding DataSyncStatus + */ + @JsonCreator + public static DataSyncStatus fromString(String name) { + return fromString(name, DataSyncStatus.class); + } + + /** + * @return known DataSyncStatus values + */ + public static Collection values() { + return values(DataSyncStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInput.java new file mode 100644 index 0000000000000..044192abe2725 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Disable protection input. + */ +public class DisableProtectionInput { + /** + * Disable protection input properties. + */ + @JsonProperty(value = "properties") + private DisableProtectionInputProperties properties; + + /** + * Get disable protection input properties. + * + * @return the properties value + */ + public DisableProtectionInputProperties properties() { + return this.properties; + } + + /** + * Set disable protection input properties. + * + * @param properties the properties value to set + * @return the DisableProtectionInput object itself. + */ + public DisableProtectionInput withProperties(DisableProtectionInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInputProperties.java new file mode 100644 index 0000000000000..ffa6b832d65a5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionInputProperties.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Disable protection input properties. + */ +public class DisableProtectionInputProperties { + /** + * Disable protection reason. It can have values + * NotSpecified/MigrationComplete. Possible values include: 'NotSpecified', + * 'MigrationComplete'. + */ + @JsonProperty(value = "disableProtectionReason") + private DisableProtectionReason disableProtectionReason; + + /** + * Replication provider specific input. + */ + @JsonProperty(value = "replicationProviderInput") + private DisableProtectionProviderSpecificInput replicationProviderInput; + + /** + * Get disable protection reason. It can have values NotSpecified/MigrationComplete. Possible values include: 'NotSpecified', 'MigrationComplete'. + * + * @return the disableProtectionReason value + */ + public DisableProtectionReason disableProtectionReason() { + return this.disableProtectionReason; + } + + /** + * Set disable protection reason. It can have values NotSpecified/MigrationComplete. Possible values include: 'NotSpecified', 'MigrationComplete'. + * + * @param disableProtectionReason the disableProtectionReason value to set + * @return the DisableProtectionInputProperties object itself. + */ + public DisableProtectionInputProperties withDisableProtectionReason(DisableProtectionReason disableProtectionReason) { + this.disableProtectionReason = disableProtectionReason; + return this; + } + + /** + * Get replication provider specific input. + * + * @return the replicationProviderInput value + */ + public DisableProtectionProviderSpecificInput replicationProviderInput() { + return this.replicationProviderInput; + } + + /** + * Set replication provider specific input. + * + * @param replicationProviderInput the replicationProviderInput value to set + * @return the DisableProtectionInputProperties object itself. + */ + public DisableProtectionInputProperties withReplicationProviderInput(DisableProtectionProviderSpecificInput replicationProviderInput) { + this.replicationProviderInput = replicationProviderInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionProviderSpecificInput.java new file mode 100644 index 0000000000000..f711ade21b9ad --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Disable protection provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("DisableProtectionProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "InMage", value = InMageDisableProtectionProviderSpecificInput.class) +}) +public class DisableProtectionProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionReason.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionReason.java new file mode 100644 index 0000000000000..1b305235fc56e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DisableProtectionReason.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for DisableProtectionReason. + */ +public final class DisableProtectionReason extends ExpandableStringEnum { + /** Static value NotSpecified for DisableProtectionReason. */ + public static final DisableProtectionReason NOT_SPECIFIED = fromString("NotSpecified"); + + /** Static value MigrationComplete for DisableProtectionReason. */ + public static final DisableProtectionReason MIGRATION_COMPLETE = fromString("MigrationComplete"); + + /** + * Creates or finds a DisableProtectionReason from its string representation. + * @param name a name to look for + * @return the corresponding DisableProtectionReason + */ + @JsonCreator + public static DisableProtectionReason fromString(String name) { + return fromString(name, DisableProtectionReason.class); + } + + /** + * @return known DisableProtectionReason values + */ + public static Collection values() { + return values(DisableProtectionReason.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequest.java new file mode 100644 index 0000000000000..3ad952d53ac20 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Request to add a physical machine as a protectable item in a container. + */ +public class DiscoverProtectableItemRequest { + /** + * The properties of a discover protectable item request. + */ + @JsonProperty(value = "properties") + private DiscoverProtectableItemRequestProperties properties; + + /** + * Get the properties of a discover protectable item request. + * + * @return the properties value + */ + public DiscoverProtectableItemRequestProperties properties() { + return this.properties; + } + + /** + * Set the properties of a discover protectable item request. + * + * @param properties the properties value to set + * @return the DiscoverProtectableItemRequest object itself. + */ + public DiscoverProtectableItemRequest withProperties(DiscoverProtectableItemRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequestProperties.java new file mode 100644 index 0000000000000..f4c3670667d03 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiscoverProtectableItemRequestProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Discover protectable item properties. + */ +public class DiscoverProtectableItemRequestProperties { + /** + * The friendly name of the physical machine. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The IP address of the physical machine to be discovered. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The OS type on the physical machine. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * Get the friendly name of the physical machine. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the friendly name of the physical machine. + * + * @param friendlyName the friendlyName value to set + * @return the DiscoverProtectableItemRequestProperties object itself. + */ + public DiscoverProtectableItemRequestProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the IP address of the physical machine to be discovered. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the physical machine to be discovered. + * + * @param ipAddress the ipAddress value to set + * @return the DiscoverProtectableItemRequestProperties object itself. + */ + public DiscoverProtectableItemRequestProperties withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the OS type on the physical machine. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type on the physical machine. + * + * @param osType the osType value to set + * @return the DiscoverProtectableItemRequestProperties object itself. + */ + public DiscoverProtectableItemRequestProperties withOsType(String osType) { + this.osType = osType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskAccountType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskAccountType.java new file mode 100644 index 0000000000000..66aa62a33e921 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskAccountType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for DiskAccountType. + */ +public final class DiskAccountType extends ExpandableStringEnum { + /** Static value Standard_LRS for DiskAccountType. */ + public static final DiskAccountType STANDARD_LRS = fromString("Standard_LRS"); + + /** Static value Premium_LRS for DiskAccountType. */ + public static final DiskAccountType PREMIUM_LRS = fromString("Premium_LRS"); + + /** Static value StandardSSD_LRS for DiskAccountType. */ + public static final DiskAccountType STANDARD_SSD_LRS = fromString("StandardSSD_LRS"); + + /** + * Creates or finds a DiskAccountType from its string representation. + * @param name a name to look for + * @return the corresponding DiskAccountType + */ + @JsonCreator + public static DiskAccountType fromString(String name) { + return fromString(name, DiskAccountType.class); + } + + /** + * @return known DiskAccountType values + */ + public static Collection values() { + return values(DiskAccountType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskDetails.java new file mode 100644 index 0000000000000..26e86705a66d0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskDetails.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * On-prem disk details data. + */ +public class DiskDetails { + /** + * The hard disk max size in MB. + */ + @JsonProperty(value = "maxSizeMB") + private Long maxSizeMB; + + /** + * The type of the volume. + */ + @JsonProperty(value = "vhdType") + private String vhdType; + + /** + * The VHD Id. + */ + @JsonProperty(value = "vhdId") + private String vhdId; + + /** + * The VHD name. + */ + @JsonProperty(value = "vhdName") + private String vhdName; + + /** + * Get the hard disk max size in MB. + * + * @return the maxSizeMB value + */ + public Long maxSizeMB() { + return this.maxSizeMB; + } + + /** + * Set the hard disk max size in MB. + * + * @param maxSizeMB the maxSizeMB value to set + * @return the DiskDetails object itself. + */ + public DiskDetails withMaxSizeMB(Long maxSizeMB) { + this.maxSizeMB = maxSizeMB; + return this; + } + + /** + * Get the type of the volume. + * + * @return the vhdType value + */ + public String vhdType() { + return this.vhdType; + } + + /** + * Set the type of the volume. + * + * @param vhdType the vhdType value to set + * @return the DiskDetails object itself. + */ + public DiskDetails withVhdType(String vhdType) { + this.vhdType = vhdType; + return this; + } + + /** + * Get the VHD Id. + * + * @return the vhdId value + */ + public String vhdId() { + return this.vhdId; + } + + /** + * Set the VHD Id. + * + * @param vhdId the vhdId value to set + * @return the DiskDetails object itself. + */ + public DiskDetails withVhdId(String vhdId) { + this.vhdId = vhdId; + return this; + } + + /** + * Get the VHD name. + * + * @return the vhdName value + */ + public String vhdName() { + return this.vhdName; + } + + /** + * Set the VHD name. + * + * @param vhdName the vhdName value to set + * @return the DiskDetails object itself. + */ + public DiskDetails withVhdName(String vhdName) { + this.vhdName = vhdName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionInfo.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionInfo.java new file mode 100644 index 0000000000000..afcc68d8d0337 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionInfo.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery disk encryption info (BEK and KEK). + */ +public class DiskEncryptionInfo { + /** + * The recovery KeyVault reference for secret. + */ + @JsonProperty(value = "diskEncryptionKeyInfo") + private DiskEncryptionKeyInfo diskEncryptionKeyInfo; + + /** + * The recovery KeyVault reference for key. + */ + @JsonProperty(value = "keyEncryptionKeyInfo") + private KeyEncryptionKeyInfo keyEncryptionKeyInfo; + + /** + * Get the recovery KeyVault reference for secret. + * + * @return the diskEncryptionKeyInfo value + */ + public DiskEncryptionKeyInfo diskEncryptionKeyInfo() { + return this.diskEncryptionKeyInfo; + } + + /** + * Set the recovery KeyVault reference for secret. + * + * @param diskEncryptionKeyInfo the diskEncryptionKeyInfo value to set + * @return the DiskEncryptionInfo object itself. + */ + public DiskEncryptionInfo withDiskEncryptionKeyInfo(DiskEncryptionKeyInfo diskEncryptionKeyInfo) { + this.diskEncryptionKeyInfo = diskEncryptionKeyInfo; + return this; + } + + /** + * Get the recovery KeyVault reference for key. + * + * @return the keyEncryptionKeyInfo value + */ + public KeyEncryptionKeyInfo keyEncryptionKeyInfo() { + return this.keyEncryptionKeyInfo; + } + + /** + * Set the recovery KeyVault reference for key. + * + * @param keyEncryptionKeyInfo the keyEncryptionKeyInfo value to set + * @return the DiskEncryptionInfo object itself. + */ + public DiskEncryptionInfo withKeyEncryptionKeyInfo(KeyEncryptionKeyInfo keyEncryptionKeyInfo) { + this.keyEncryptionKeyInfo = keyEncryptionKeyInfo; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionKeyInfo.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionKeyInfo.java new file mode 100644 index 0000000000000..73070281019d8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskEncryptionKeyInfo.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Disk Encryption Key Information (BitLocker Encryption Key (BEK) on Windows). + */ +public class DiskEncryptionKeyInfo { + /** + * The secret url / identifier. + */ + @JsonProperty(value = "secretIdentifier") + private String secretIdentifier; + + /** + * The KeyVault resource ARM id for secret. + */ + @JsonProperty(value = "keyVaultResourceArmId") + private String keyVaultResourceArmId; + + /** + * Get the secret url / identifier. + * + * @return the secretIdentifier value + */ + public String secretIdentifier() { + return this.secretIdentifier; + } + + /** + * Set the secret url / identifier. + * + * @param secretIdentifier the secretIdentifier value to set + * @return the DiskEncryptionKeyInfo object itself. + */ + public DiskEncryptionKeyInfo withSecretIdentifier(String secretIdentifier) { + this.secretIdentifier = secretIdentifier; + return this; + } + + /** + * Get the KeyVault resource ARM id for secret. + * + * @return the keyVaultResourceArmId value + */ + public String keyVaultResourceArmId() { + return this.keyVaultResourceArmId; + } + + /** + * Set the KeyVault resource ARM id for secret. + * + * @param keyVaultResourceArmId the keyVaultResourceArmId value to set + * @return the DiskEncryptionKeyInfo object itself. + */ + public DiskEncryptionKeyInfo withKeyVaultResourceArmId(String keyVaultResourceArmId) { + this.keyVaultResourceArmId = keyVaultResourceArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskType.java new file mode 100644 index 0000000000000..d75d14e034b39 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for DiskType. + */ +public final class DiskType extends ExpandableStringEnum { + /** Static value Standard_LRS for DiskType. */ + public static final DiskType STANDARD_LRS = fromString("Standard_LRS"); + + /** Static value Premium_LRS for DiskType. */ + public static final DiskType PREMIUM_LRS = fromString("Premium_LRS"); + + /** Static value StandardSSD_LRS for DiskType. */ + public static final DiskType STANDARD_SSD_LRS = fromString("StandardSSD_LRS"); + + /** + * Creates or finds a DiskType from its string representation. + * @param name a name to look for + * @return the corresponding DiskType + */ + @JsonCreator + public static DiskType fromString(String name) { + return fromString(name, DiskType.class); + } + + /** + * @return known DiskType values + */ + public static Collection values() { + return values(DiskType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskVolumeDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskVolumeDetails.java new file mode 100644 index 0000000000000..413cf38fe1a3a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/DiskVolumeDetails.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Volume details. + */ +public class DiskVolumeDetails { + /** + * The volume label. + */ + @JsonProperty(value = "label") + private String label; + + /** + * The volume name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Get the volume label. + * + * @return the label value + */ + public String label() { + return this.label; + } + + /** + * Set the volume label. + * + * @param label the label value to set + * @return the DiskVolumeDetails object itself. + */ + public DiskVolumeDetails withLabel(String label) { + this.label = label; + return this; + } + + /** + * Get the volume name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the volume name. + * + * @param name the name value to set + * @return the DiskVolumeDetails object itself. + */ + public DiskVolumeDetails withName(String name) { + this.name = name; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Display.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Display.java new file mode 100644 index 0000000000000..a590bf3e57231 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Display.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Contains the localized display information for this particular operation / + * action. These value will be used by several clients for (1) custom role + * definitions for RBAC; (2) complex query filters for the event service; and + * (3) audit history / records for management operations. + */ +public class Display { + /** + * The provider. The localized friendly form of the resource provider name + * – it is expected to also include the publisher/company responsible. It + * should use Title Casing and begin with "Microsoft" for 1st party + * services. e.g. "Microsoft Monitoring Insights" or "Microsoft Compute.". + */ + @JsonProperty(value = "provider") + private String provider; + + /** + * The resource. The localized friendly form of the resource related to + * this action/operation – it should match the public documentation for the + * resource provider. It should use Title Casing. This value should be + * unique for a particular URL type (e.g. nested types should *not* reuse + * their parent’s display.resource field). e.g. "Virtual Machines" or + * "Scheduler Job Collections", or "Virtual Machine VM Sizes" or "Scheduler + * Jobs". + */ + @JsonProperty(value = "resource") + private String resource; + + /** + * The operation. The localized friendly name for the operation, as it + * should be shown to the user. It should be concise (to fit in drop downs) + * but clear (i.e. self-documenting). It should use Title Casing. + * Prescriptive guidance: Read Create or Update Delete 'ActionName'. + */ + @JsonProperty(value = "operation") + private String operation; + + /** + * The description. The localized friendly description for the operation, + * as it should be shown to the user. It should be thorough, yet concise – + * it will be used in tool tips and detailed views. Prescriptive guidance + * for namespaces: Read any 'display.provider' resource Create or Update + * any 'display.provider' resource Delete any 'display.provider' resource + * Perform any other action on any 'display.provider' resource Prescriptive + * guidance for namespaces: Read any 'display.resource' Create or Update + * any 'display.resource' Delete any 'display.resource' 'ActionName' any + * 'display.resources'. + */ + @JsonProperty(value = "description") + private String description; + + /** + * Get the provider. The localized friendly form of the resource provider name – it is expected to also include the publisher/company responsible. It should use Title Casing and begin with "Microsoft" for 1st party services. e.g. "Microsoft Monitoring Insights" or "Microsoft Compute.". + * + * @return the provider value + */ + public String provider() { + return this.provider; + } + + /** + * Set the provider. The localized friendly form of the resource provider name – it is expected to also include the publisher/company responsible. It should use Title Casing and begin with "Microsoft" for 1st party services. e.g. "Microsoft Monitoring Insights" or "Microsoft Compute.". + * + * @param provider the provider value to set + * @return the Display object itself. + */ + public Display withProvider(String provider) { + this.provider = provider; + return this; + } + + /** + * Get the resource. The localized friendly form of the resource related to this action/operation – it should match the public documentation for the resource provider. It should use Title Casing. This value should be unique for a particular URL type (e.g. nested types should *not* reuse their parent’s display.resource field). e.g. "Virtual Machines" or "Scheduler Job Collections", or "Virtual Machine VM Sizes" or "Scheduler Jobs". + * + * @return the resource value + */ + public String resource() { + return this.resource; + } + + /** + * Set the resource. The localized friendly form of the resource related to this action/operation – it should match the public documentation for the resource provider. It should use Title Casing. This value should be unique for a particular URL type (e.g. nested types should *not* reuse their parent’s display.resource field). e.g. "Virtual Machines" or "Scheduler Job Collections", or "Virtual Machine VM Sizes" or "Scheduler Jobs". + * + * @param resource the resource value to set + * @return the Display object itself. + */ + public Display withResource(String resource) { + this.resource = resource; + return this; + } + + /** + * Get the operation. The localized friendly name for the operation, as it should be shown to the user. It should be concise (to fit in drop downs) but clear (i.e. self-documenting). It should use Title Casing. Prescriptive guidance: Read Create or Update Delete 'ActionName'. + * + * @return the operation value + */ + public String operation() { + return this.operation; + } + + /** + * Set the operation. The localized friendly name for the operation, as it should be shown to the user. It should be concise (to fit in drop downs) but clear (i.e. self-documenting). It should use Title Casing. Prescriptive guidance: Read Create or Update Delete 'ActionName'. + * + * @param operation the operation value to set + * @return the Display object itself. + */ + public Display withOperation(String operation) { + this.operation = operation; + return this; + } + + /** + * Get the description. The localized friendly description for the operation, as it should be shown to the user. It should be thorough, yet concise – it will be used in tool tips and detailed views. Prescriptive guidance for namespaces: Read any 'display.provider' resource Create or Update any 'display.provider' resource Delete any 'display.provider' resource Perform any other action on any 'display.provider' resource Prescriptive guidance for namespaces: Read any 'display.resource' Create or Update any 'display.resource' Delete any 'display.resource' 'ActionName' any 'display.resources'. + * + * @return the description value + */ + public String description() { + return this.description; + } + + /** + * Set the description. The localized friendly description for the operation, as it should be shown to the user. It should be thorough, yet concise – it will be used in tool tips and detailed views. Prescriptive guidance for namespaces: Read any 'display.provider' resource Create or Update any 'display.provider' resource Delete any 'display.provider' resource Perform any other action on any 'display.provider' resource Prescriptive guidance for namespaces: Read any 'display.resource' Create or Update any 'display.resource' Delete any 'display.resource' 'ActionName' any 'display.resources'. + * + * @param description the description value to set + * @return the Display object itself. + */ + public Display withDescription(String description) { + this.description = description; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInput.java new file mode 100644 index 0000000000000..7c008e59bfe10 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Enable migration input. + */ +public class EnableMigrationInput { + /** + * Enable migration input properties. + */ + @JsonProperty(value = "properties", required = true) + private EnableMigrationInputProperties properties; + + /** + * Get enable migration input properties. + * + * @return the properties value + */ + public EnableMigrationInputProperties properties() { + return this.properties; + } + + /** + * Set enable migration input properties. + * + * @param properties the properties value to set + * @return the EnableMigrationInput object itself. + */ + public EnableMigrationInput withProperties(EnableMigrationInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInputProperties.java new file mode 100644 index 0000000000000..3952691ad398a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationInputProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Enable migration input properties. + */ +public class EnableMigrationInputProperties { + /** + * The policy Id. + */ + @JsonProperty(value = "policyId", required = true) + private String policyId; + + /** + * The provider specific details. + */ + @JsonProperty(value = "providerSpecificDetails", required = true) + private EnableMigrationProviderSpecificInput providerSpecificDetails; + + /** + * Get the policy Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the policy Id. + * + * @param policyId the policyId value to set + * @return the EnableMigrationInputProperties object itself. + */ + public EnableMigrationInputProperties withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get the provider specific details. + * + * @return the providerSpecificDetails value + */ + public EnableMigrationProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific details. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the EnableMigrationInputProperties object itself. + */ + public EnableMigrationInputProperties withProviderSpecificDetails(EnableMigrationProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationProviderSpecificInput.java new file mode 100644 index 0000000000000..66d26dca0b382 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableMigrationProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Enable migration provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("EnableMigrationProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtEnableMigrationInput.class) +}) +public class EnableMigrationProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInput.java new file mode 100644 index 0000000000000..de3af51dd93d2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Enable protection input. + */ +public class EnableProtectionInput { + /** + * Enable protection input properties. + */ + @JsonProperty(value = "properties") + private EnableProtectionInputProperties properties; + + /** + * Get enable protection input properties. + * + * @return the properties value + */ + public EnableProtectionInputProperties properties() { + return this.properties; + } + + /** + * Set enable protection input properties. + * + * @param properties the properties value to set + * @return the EnableProtectionInput object itself. + */ + public EnableProtectionInput withProperties(EnableProtectionInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInputProperties.java new file mode 100644 index 0000000000000..5684f633e59de --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionInputProperties.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Enable protection input properties. + */ +public class EnableProtectionInputProperties { + /** + * The Policy Id. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * The protectable item Id. + */ + @JsonProperty(value = "protectableItemId") + private String protectableItemId; + + /** + * The ReplicationProviderInput. For HyperVReplicaAzure provider, it will + * be AzureEnableProtectionInput object. For San provider, it will be + * SanEnableProtectionInput object. For HyperVReplicaAzure provider, it can + * be null. + */ + @JsonProperty(value = "providerSpecificDetails") + private EnableProtectionProviderSpecificInput providerSpecificDetails; + + /** + * Get the Policy Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the Policy Id. + * + * @param policyId the policyId value to set + * @return the EnableProtectionInputProperties object itself. + */ + public EnableProtectionInputProperties withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get the protectable item Id. + * + * @return the protectableItemId value + */ + public String protectableItemId() { + return this.protectableItemId; + } + + /** + * Set the protectable item Id. + * + * @param protectableItemId the protectableItemId value to set + * @return the EnableProtectionInputProperties object itself. + */ + public EnableProtectionInputProperties withProtectableItemId(String protectableItemId) { + this.protectableItemId = protectableItemId; + return this; + } + + /** + * Get the ReplicationProviderInput. For HyperVReplicaAzure provider, it will be AzureEnableProtectionInput object. For San provider, it will be SanEnableProtectionInput object. For HyperVReplicaAzure provider, it can be null. + * + * @return the providerSpecificDetails value + */ + public EnableProtectionProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the ReplicationProviderInput. For HyperVReplicaAzure provider, it will be AzureEnableProtectionInput object. For San provider, it will be SanEnableProtectionInput object. For HyperVReplicaAzure provider, it can be null. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the EnableProtectionInputProperties object itself. + */ + public EnableProtectionInputProperties withProviderSpecificDetails(EnableProtectionProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionProviderSpecificInput.java new file mode 100644 index 0000000000000..4c25e83bd9b8d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EnableProtectionProviderSpecificInput.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Enable protection provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("EnableProtectionProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AEnableProtectionInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureEnableProtectionInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2EnableProtectionInput.class), + @JsonSubTypes.Type(name = "InMage", value = InMageEnableProtectionInput.class), + @JsonSubTypes.Type(name = "San", value = SanEnableProtectionInput.class) +}) +public class EnableProtectionProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EncryptionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EncryptionDetails.java new file mode 100644 index 0000000000000..443a5c64ee7dd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EncryptionDetails.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Encryption details for the fabric. + */ +public class EncryptionDetails { + /** + * The key encryption key state for the Vmm. + */ + @JsonProperty(value = "kekState") + private String kekState; + + /** + * The key encryption key certificate thumbprint. + */ + @JsonProperty(value = "kekCertThumbprint") + private String kekCertThumbprint; + + /** + * The key encryption key certificate expiry date. + */ + @JsonProperty(value = "kekCertExpiryDate") + private DateTime kekCertExpiryDate; + + /** + * Get the key encryption key state for the Vmm. + * + * @return the kekState value + */ + public String kekState() { + return this.kekState; + } + + /** + * Set the key encryption key state for the Vmm. + * + * @param kekState the kekState value to set + * @return the EncryptionDetails object itself. + */ + public EncryptionDetails withKekState(String kekState) { + this.kekState = kekState; + return this; + } + + /** + * Get the key encryption key certificate thumbprint. + * + * @return the kekCertThumbprint value + */ + public String kekCertThumbprint() { + return this.kekCertThumbprint; + } + + /** + * Set the key encryption key certificate thumbprint. + * + * @param kekCertThumbprint the kekCertThumbprint value to set + * @return the EncryptionDetails object itself. + */ + public EncryptionDetails withKekCertThumbprint(String kekCertThumbprint) { + this.kekCertThumbprint = kekCertThumbprint; + return this; + } + + /** + * Get the key encryption key certificate expiry date. + * + * @return the kekCertExpiryDate value + */ + public DateTime kekCertExpiryDate() { + return this.kekCertExpiryDate; + } + + /** + * Set the key encryption key certificate expiry date. + * + * @param kekCertExpiryDate the kekCertExpiryDate value to set + * @return the EncryptionDetails object itself. + */ + public EncryptionDetails withKekCertExpiryDate(DateTime kekCertExpiryDate) { + this.kekCertExpiryDate = kekCertExpiryDate; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EthernetAddressType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EthernetAddressType.java new file mode 100644 index 0000000000000..a4b0edb0550a9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EthernetAddressType.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for EthernetAddressType. + */ +public final class EthernetAddressType extends ExpandableStringEnum { + /** Static value Dynamic for EthernetAddressType. */ + public static final EthernetAddressType DYNAMIC = fromString("Dynamic"); + + /** Static value Static for EthernetAddressType. */ + public static final EthernetAddressType STATIC = fromString("Static"); + + /** + * Creates or finds a EthernetAddressType from its string representation. + * @param name a name to look for + * @return the corresponding EthernetAddressType + */ + @JsonCreator + public static EthernetAddressType fromString(String name) { + return fromString(name, EthernetAddressType.class); + } + + /** + * @return known EthernetAddressType values + */ + public static Collection values() { + return values(EthernetAddressType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Event.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Event.java new file mode 100644 index 0000000000000..773983ab15801 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Event.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.EventInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing Event. + */ +public interface Event extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + EventProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProperties.java new file mode 100644 index 0000000000000..36d5892d9d3ba --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProperties.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of a monitoring event. + */ +public class EventProperties { + /** + * The Id of the monitoring event. + */ + @JsonProperty(value = "eventCode") + private String eventCode; + + /** + * The event name. + */ + @JsonProperty(value = "description") + private String description; + + /** + * The type of the event. for example: VM Health, Server Health, Job + * Failure etc. + */ + @JsonProperty(value = "eventType") + private String eventType; + + /** + * The friendly name of the source of the event on which it is raised (for + * example, VM, VMM etc). + */ + @JsonProperty(value = "affectedObjectFriendlyName") + private String affectedObjectFriendlyName; + + /** + * The severity of the event. + */ + @JsonProperty(value = "severity") + private String severity; + + /** + * The time of occurrence of the event. + */ + @JsonProperty(value = "timeOfOccurrence") + private DateTime timeOfOccurrence; + + /** + * The ARM ID of the fabric. + */ + @JsonProperty(value = "fabricId") + private String fabricId; + + /** + * The provider specific settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private EventProviderSpecificDetails providerSpecificDetails; + + /** + * The event specific settings. + */ + @JsonProperty(value = "eventSpecificDetails") + private EventSpecificDetails eventSpecificDetails; + + /** + * The list of errors / warnings capturing details associated with the + * issue(s). + */ + @JsonProperty(value = "healthErrors") + private List healthErrors; + + /** + * Get the Id of the monitoring event. + * + * @return the eventCode value + */ + public String eventCode() { + return this.eventCode; + } + + /** + * Set the Id of the monitoring event. + * + * @param eventCode the eventCode value to set + * @return the EventProperties object itself. + */ + public EventProperties withEventCode(String eventCode) { + this.eventCode = eventCode; + return this; + } + + /** + * Get the event name. + * + * @return the description value + */ + public String description() { + return this.description; + } + + /** + * Set the event name. + * + * @param description the description value to set + * @return the EventProperties object itself. + */ + public EventProperties withDescription(String description) { + this.description = description; + return this; + } + + /** + * Get the type of the event. for example: VM Health, Server Health, Job Failure etc. + * + * @return the eventType value + */ + public String eventType() { + return this.eventType; + } + + /** + * Set the type of the event. for example: VM Health, Server Health, Job Failure etc. + * + * @param eventType the eventType value to set + * @return the EventProperties object itself. + */ + public EventProperties withEventType(String eventType) { + this.eventType = eventType; + return this; + } + + /** + * Get the friendly name of the source of the event on which it is raised (for example, VM, VMM etc). + * + * @return the affectedObjectFriendlyName value + */ + public String affectedObjectFriendlyName() { + return this.affectedObjectFriendlyName; + } + + /** + * Set the friendly name of the source of the event on which it is raised (for example, VM, VMM etc). + * + * @param affectedObjectFriendlyName the affectedObjectFriendlyName value to set + * @return the EventProperties object itself. + */ + public EventProperties withAffectedObjectFriendlyName(String affectedObjectFriendlyName) { + this.affectedObjectFriendlyName = affectedObjectFriendlyName; + return this; + } + + /** + * Get the severity of the event. + * + * @return the severity value + */ + public String severity() { + return this.severity; + } + + /** + * Set the severity of the event. + * + * @param severity the severity value to set + * @return the EventProperties object itself. + */ + public EventProperties withSeverity(String severity) { + this.severity = severity; + return this; + } + + /** + * Get the time of occurrence of the event. + * + * @return the timeOfOccurrence value + */ + public DateTime timeOfOccurrence() { + return this.timeOfOccurrence; + } + + /** + * Set the time of occurrence of the event. + * + * @param timeOfOccurrence the timeOfOccurrence value to set + * @return the EventProperties object itself. + */ + public EventProperties withTimeOfOccurrence(DateTime timeOfOccurrence) { + this.timeOfOccurrence = timeOfOccurrence; + return this; + } + + /** + * Get the ARM ID of the fabric. + * + * @return the fabricId value + */ + public String fabricId() { + return this.fabricId; + } + + /** + * Set the ARM ID of the fabric. + * + * @param fabricId the fabricId value to set + * @return the EventProperties object itself. + */ + public EventProperties withFabricId(String fabricId) { + this.fabricId = fabricId; + return this; + } + + /** + * Get the provider specific settings. + * + * @return the providerSpecificDetails value + */ + public EventProviderSpecificDetails providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the EventProperties object itself. + */ + public EventProperties withProviderSpecificDetails(EventProviderSpecificDetails providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + + /** + * Get the event specific settings. + * + * @return the eventSpecificDetails value + */ + public EventSpecificDetails eventSpecificDetails() { + return this.eventSpecificDetails; + } + + /** + * Set the event specific settings. + * + * @param eventSpecificDetails the eventSpecificDetails value to set + * @return the EventProperties object itself. + */ + public EventProperties withEventSpecificDetails(EventSpecificDetails eventSpecificDetails) { + this.eventSpecificDetails = eventSpecificDetails; + return this; + } + + /** + * Get the list of errors / warnings capturing details associated with the issue(s). + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Set the list of errors / warnings capturing details associated with the issue(s). + * + * @param healthErrors the healthErrors value to set + * @return the EventProperties object itself. + */ + public EventProperties withHealthErrors(List healthErrors) { + this.healthErrors = healthErrors; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProviderSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProviderSpecificDetails.java new file mode 100644 index 0000000000000..a00eb3e27debf --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventProviderSpecificDetails.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Model class for provider specific details for an event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("EventProviderSpecificDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AEventDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012", value = HyperVReplica2012EventDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012R2", value = HyperVReplica2012R2EventDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureEventDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaBaseEventDetails", value = HyperVReplicaBaseEventDetails.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2EventDetails.class) +}) +public class EventProviderSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventQueryParameter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventQueryParameter.java new file mode 100644 index 0000000000000..17fe45f39f270 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventQueryParameter.java @@ -0,0 +1,202 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Implements the event query parameter. + */ +public class EventQueryParameter { + /** + * The source id of the events to be queried. + */ + @JsonProperty(value = "eventCode") + private String eventCode; + + /** + * The severity of the events to be queried. + */ + @JsonProperty(value = "severity") + private String severity; + + /** + * The type of the events to be queried. + */ + @JsonProperty(value = "eventType") + private String eventType; + + /** + * The affected object server id of the events to be queried. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The affected object name of the events to be queried. + */ + @JsonProperty(value = "affectedObjectFriendlyName") + private String affectedObjectFriendlyName; + + /** + * The start time of the time range within which the events are to be + * queried. + */ + @JsonProperty(value = "startTime") + private DateTime startTime; + + /** + * The end time of the time range within which the events are to be + * queried. + */ + @JsonProperty(value = "endTime") + private DateTime endTime; + + /** + * Get the source id of the events to be queried. + * + * @return the eventCode value + */ + public String eventCode() { + return this.eventCode; + } + + /** + * Set the source id of the events to be queried. + * + * @param eventCode the eventCode value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withEventCode(String eventCode) { + this.eventCode = eventCode; + return this; + } + + /** + * Get the severity of the events to be queried. + * + * @return the severity value + */ + public String severity() { + return this.severity; + } + + /** + * Set the severity of the events to be queried. + * + * @param severity the severity value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withSeverity(String severity) { + this.severity = severity; + return this; + } + + /** + * Get the type of the events to be queried. + * + * @return the eventType value + */ + public String eventType() { + return this.eventType; + } + + /** + * Set the type of the events to be queried. + * + * @param eventType the eventType value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withEventType(String eventType) { + this.eventType = eventType; + return this; + } + + /** + * Get the affected object server id of the events to be queried. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set the affected object server id of the events to be queried. + * + * @param fabricName the fabricName value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the affected object name of the events to be queried. + * + * @return the affectedObjectFriendlyName value + */ + public String affectedObjectFriendlyName() { + return this.affectedObjectFriendlyName; + } + + /** + * Set the affected object name of the events to be queried. + * + * @param affectedObjectFriendlyName the affectedObjectFriendlyName value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withAffectedObjectFriendlyName(String affectedObjectFriendlyName) { + this.affectedObjectFriendlyName = affectedObjectFriendlyName; + return this; + } + + /** + * Get the start time of the time range within which the events are to be queried. + * + * @return the startTime value + */ + public DateTime startTime() { + return this.startTime; + } + + /** + * Set the start time of the time range within which the events are to be queried. + * + * @param startTime the startTime value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withStartTime(DateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * Get the end time of the time range within which the events are to be queried. + * + * @return the endTime value + */ + public DateTime endTime() { + return this.endTime; + } + + /** + * Set the end time of the time range within which the events are to be queried. + * + * @param endTime the endTime value to set + * @return the EventQueryParameter object itself. + */ + public EventQueryParameter withEndTime(DateTime endTime) { + this.endTime = endTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventSpecificDetails.java new file mode 100644 index 0000000000000..76784fc4c1f2a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/EventSpecificDetails.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Model class for event specific details for an event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("EventSpecificDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "JobStatus", value = JobStatusEventDetails.class) +}) +public class EventSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ExportJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ExportJobDetails.java new file mode 100644 index 0000000000000..d089eec7e8348 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ExportJobDetails.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents details for export jobs workflow. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ExportJobDetails") +public class ExportJobDetails extends JobDetails { + /** + * BlobUri of the exported jobs. + */ + @JsonProperty(value = "blobUri") + private String blobUri; + + /** + * The sas token to access blob. + */ + @JsonProperty(value = "sasToken") + private String sasToken; + + /** + * Get blobUri of the exported jobs. + * + * @return the blobUri value + */ + public String blobUri() { + return this.blobUri; + } + + /** + * Set blobUri of the exported jobs. + * + * @param blobUri the blobUri value to set + * @return the ExportJobDetails object itself. + */ + public ExportJobDetails withBlobUri(String blobUri) { + this.blobUri = blobUri; + return this; + } + + /** + * Get the sas token to access blob. + * + * @return the sasToken value + */ + public String sasToken() { + return this.sasToken; + } + + /** + * Set the sas token to access blob. + * + * @param sasToken the sasToken value to set + * @return the ExportJobDetails object itself. + */ + public ExportJobDetails withSasToken(String sasToken) { + this.sasToken = sasToken; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Fabric.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Fabric.java new file mode 100644 index 0000000000000..c70720d12d1ec --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Fabric.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.FabricInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing Fabric. + */ +public interface Fabric extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + FabricProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the Fabric definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithVault, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of Fabric definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a Fabric definition. + */ + interface Blank extends WithVault { + } + + /** + * The stage of the fabric definition allowing to specify Vault. + */ + interface WithVault { + /** + * Specifies . + * @return the next definition stage + */ + WithProperties withExistingVault(); + } + + /** + * The stage of the fabric definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Fabric creation input + * @return the next definition stage + */ + WithCreate withProperties(FabricCreationInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a Fabric update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of Fabric update stages. + */ + interface UpdateStages { + /** + * The stage of the fabric update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Fabric creation input + * @return the next update stage + */ + Update withProperties(FabricCreationInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInput.java new file mode 100644 index 0000000000000..4c70c5e4f1328 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Site details provided during the time of site creation. + */ +public class FabricCreationInput { + /** + * Fabric creation input. + */ + @JsonProperty(value = "properties") + private FabricCreationInputProperties properties; + + /** + * Get fabric creation input. + * + * @return the properties value + */ + public FabricCreationInputProperties properties() { + return this.properties; + } + + /** + * Set fabric creation input. + * + * @param properties the properties value to set + * @return the FabricCreationInput object itself. + */ + public FabricCreationInput withProperties(FabricCreationInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInputProperties.java new file mode 100644 index 0000000000000..c94d806e5877a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricCreationInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Properties of site details provided during the time of site creation. + */ +public class FabricCreationInputProperties { + /** + * Fabric provider specific creation input. + */ + @JsonProperty(value = "customDetails") + private FabricSpecificCreationInput customDetails; + + /** + * Get fabric provider specific creation input. + * + * @return the customDetails value + */ + public FabricSpecificCreationInput customDetails() { + return this.customDetails; + } + + /** + * Set fabric provider specific creation input. + * + * @param customDetails the customDetails value to set + * @return the FabricCreationInputProperties object itself. + */ + public FabricCreationInputProperties withCustomDetails(FabricSpecificCreationInput customDetails) { + this.customDetails = customDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricProperties.java new file mode 100644 index 0000000000000..24485df830e6a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricProperties.java @@ -0,0 +1,226 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Fabric properties. + */ +public class FabricProperties { + /** + * Friendly name of the fabric. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * Encryption details for the fabric. + */ + @JsonProperty(value = "encryptionDetails") + private EncryptionDetails encryptionDetails; + + /** + * Rollover encryption details for the fabric. + */ + @JsonProperty(value = "rolloverEncryptionDetails") + private EncryptionDetails rolloverEncryptionDetails; + + /** + * Dra Registration Id. + */ + @JsonProperty(value = "internalIdentifier") + private String internalIdentifier; + + /** + * BCDR state of the fabric. + */ + @JsonProperty(value = "bcdrState") + private String bcdrState; + + /** + * Fabric specific settings. + */ + @JsonProperty(value = "customDetails") + private FabricSpecificDetails customDetails; + + /** + * Fabric health error details. + */ + @JsonProperty(value = "healthErrorDetails") + private List healthErrorDetails; + + /** + * Health of fabric. + */ + @JsonProperty(value = "health") + private String health; + + /** + * Get friendly name of the fabric. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set friendly name of the fabric. + * + * @param friendlyName the friendlyName value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get encryption details for the fabric. + * + * @return the encryptionDetails value + */ + public EncryptionDetails encryptionDetails() { + return this.encryptionDetails; + } + + /** + * Set encryption details for the fabric. + * + * @param encryptionDetails the encryptionDetails value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withEncryptionDetails(EncryptionDetails encryptionDetails) { + this.encryptionDetails = encryptionDetails; + return this; + } + + /** + * Get rollover encryption details for the fabric. + * + * @return the rolloverEncryptionDetails value + */ + public EncryptionDetails rolloverEncryptionDetails() { + return this.rolloverEncryptionDetails; + } + + /** + * Set rollover encryption details for the fabric. + * + * @param rolloverEncryptionDetails the rolloverEncryptionDetails value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withRolloverEncryptionDetails(EncryptionDetails rolloverEncryptionDetails) { + this.rolloverEncryptionDetails = rolloverEncryptionDetails; + return this; + } + + /** + * Get dra Registration Id. + * + * @return the internalIdentifier value + */ + public String internalIdentifier() { + return this.internalIdentifier; + } + + /** + * Set dra Registration Id. + * + * @param internalIdentifier the internalIdentifier value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withInternalIdentifier(String internalIdentifier) { + this.internalIdentifier = internalIdentifier; + return this; + } + + /** + * Get bCDR state of the fabric. + * + * @return the bcdrState value + */ + public String bcdrState() { + return this.bcdrState; + } + + /** + * Set bCDR state of the fabric. + * + * @param bcdrState the bcdrState value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withBcdrState(String bcdrState) { + this.bcdrState = bcdrState; + return this; + } + + /** + * Get fabric specific settings. + * + * @return the customDetails value + */ + public FabricSpecificDetails customDetails() { + return this.customDetails; + } + + /** + * Set fabric specific settings. + * + * @param customDetails the customDetails value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withCustomDetails(FabricSpecificDetails customDetails) { + this.customDetails = customDetails; + return this; + } + + /** + * Get fabric health error details. + * + * @return the healthErrorDetails value + */ + public List healthErrorDetails() { + return this.healthErrorDetails; + } + + /** + * Set fabric health error details. + * + * @param healthErrorDetails the healthErrorDetails value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withHealthErrorDetails(List healthErrorDetails) { + this.healthErrorDetails = healthErrorDetails; + return this; + } + + /** + * Get health of fabric. + * + * @return the health value + */ + public String health() { + return this.health; + } + + /** + * Set health of fabric. + * + * @param health the health value to set + * @return the FabricProperties object itself. + */ + public FabricProperties withHealth(String health) { + this.health = health; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricReplicationGroupTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricReplicationGroupTaskDetails.java new file mode 100644 index 0000000000000..dd38966fea89e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricReplicationGroupTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the fabric replication group task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FabricReplicationGroupTaskDetails") +public class FabricReplicationGroupTaskDetails extends TaskTypeDetails { + /** + * The skipped reason. + */ + @JsonProperty(value = "skippedReason") + private String skippedReason; + + /** + * The skipped reason string. + */ + @JsonProperty(value = "skippedReasonString") + private String skippedReasonString; + + /** + * The job entity. + */ + @JsonProperty(value = "jobTask") + private JobEntity jobTask; + + /** + * Get the skipped reason. + * + * @return the skippedReason value + */ + public String skippedReason() { + return this.skippedReason; + } + + /** + * Set the skipped reason. + * + * @param skippedReason the skippedReason value to set + * @return the FabricReplicationGroupTaskDetails object itself. + */ + public FabricReplicationGroupTaskDetails withSkippedReason(String skippedReason) { + this.skippedReason = skippedReason; + return this; + } + + /** + * Get the skipped reason string. + * + * @return the skippedReasonString value + */ + public String skippedReasonString() { + return this.skippedReasonString; + } + + /** + * Set the skipped reason string. + * + * @param skippedReasonString the skippedReasonString value to set + * @return the FabricReplicationGroupTaskDetails object itself. + */ + public FabricReplicationGroupTaskDetails withSkippedReasonString(String skippedReasonString) { + this.skippedReasonString = skippedReasonString; + return this; + } + + /** + * Get the job entity. + * + * @return the jobTask value + */ + public JobEntity jobTask() { + return this.jobTask; + } + + /** + * Set the job entity. + * + * @param jobTask the jobTask value to set + * @return the FabricReplicationGroupTaskDetails object itself. + */ + public FabricReplicationGroupTaskDetails withJobTask(JobEntity jobTask) { + this.jobTask = jobTask; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreateNetworkMappingInput.java new file mode 100644 index 0000000000000..d0bc7974d4366 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreateNetworkMappingInput.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Input details specific to fabrics during Network Mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FabricSpecificCreateNetworkMappingInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AzureToAzure", value = AzureToAzureCreateNetworkMappingInput.class), + @JsonSubTypes.Type(name = "VmmToAzure", value = VmmToAzureCreateNetworkMappingInput.class), + @JsonSubTypes.Type(name = "VmmToVmm", value = VmmToVmmCreateNetworkMappingInput.class) +}) +public class FabricSpecificCreateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreationInput.java new file mode 100644 index 0000000000000..38f4d5e50555f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificCreationInput.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Fabric provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FabricSpecificCreationInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "Azure", value = AzureFabricCreationInput.class), + @JsonSubTypes.Type(name = "VMwareV2", value = VMwareV2FabricCreationInput.class) +}) +public class FabricSpecificCreationInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificDetails.java new file mode 100644 index 0000000000000..c1a7c96ff9ffd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificDetails.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Fabric specific details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FabricSpecificDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "Azure", value = AzureFabricSpecificDetails.class), + @JsonSubTypes.Type(name = "HyperVSite", value = HyperVSiteDetails.class), + @JsonSubTypes.Type(name = "VMM", value = VmmDetails.class), + @JsonSubTypes.Type(name = "VMware", value = VMwareDetails.class), + @JsonSubTypes.Type(name = "VMwareV2", value = VMwareV2FabricSpecificDetails.class) +}) +public class FabricSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificUpdateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificUpdateNetworkMappingInput.java new file mode 100644 index 0000000000000..819dce093fe91 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FabricSpecificUpdateNetworkMappingInput.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Input details specific to fabrics during Network Mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FabricSpecificUpdateNetworkMappingInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AzureToAzure", value = AzureToAzureUpdateNetworkMappingInput.class), + @JsonSubTypes.Type(name = "VmmToAzure", value = VmmToAzureUpdateNetworkMappingInput.class), + @JsonSubTypes.Type(name = "VmmToVmm", value = VmmToVmmUpdateNetworkMappingInput.class) +}) +public class FabricSpecificUpdateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverDeploymentModel.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverDeploymentModel.java new file mode 100644 index 0000000000000..0e7e2004f60af --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverDeploymentModel.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for FailoverDeploymentModel. + */ +public final class FailoverDeploymentModel extends ExpandableStringEnum { + /** Static value NotApplicable for FailoverDeploymentModel. */ + public static final FailoverDeploymentModel NOT_APPLICABLE = fromString("NotApplicable"); + + /** Static value Classic for FailoverDeploymentModel. */ + public static final FailoverDeploymentModel CLASSIC = fromString("Classic"); + + /** Static value ResourceManager for FailoverDeploymentModel. */ + public static final FailoverDeploymentModel RESOURCE_MANAGER = fromString("ResourceManager"); + + /** + * Creates or finds a FailoverDeploymentModel from its string representation. + * @param name a name to look for + * @return the corresponding FailoverDeploymentModel + */ + @JsonCreator + public static FailoverDeploymentModel fromString(String name) { + return fromString(name, FailoverDeploymentModel.class); + } + + /** + * @return known FailoverDeploymentModel values + */ + public static Collection values() { + return values(FailoverDeploymentModel.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverJobDetails.java new file mode 100644 index 0000000000000..6124671bc3484 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverJobDetails.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the details for a failover job. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("FailoverJobDetails") +public class FailoverJobDetails extends JobDetails { + /** + * The test VM details. + */ + @JsonProperty(value = "protectedItemDetails") + private List protectedItemDetails; + + /** + * Get the test VM details. + * + * @return the protectedItemDetails value + */ + public List protectedItemDetails() { + return this.protectedItemDetails; + } + + /** + * Set the test VM details. + * + * @param protectedItemDetails the protectedItemDetails value to set + * @return the FailoverJobDetails object itself. + */ + public FailoverJobDetails withProtectedItemDetails(List protectedItemDetails) { + this.protectedItemDetails = protectedItemDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequest.java new file mode 100644 index 0000000000000..983a972050876 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Request to failover a process server. + */ +public class FailoverProcessServerRequest { + /** + * The properties of the PS Failover request. + */ + @JsonProperty(value = "properties") + private FailoverProcessServerRequestProperties properties; + + /** + * Get the properties of the PS Failover request. + * + * @return the properties value + */ + public FailoverProcessServerRequestProperties properties() { + return this.properties; + } + + /** + * Set the properties of the PS Failover request. + * + * @param properties the properties value to set + * @return the FailoverProcessServerRequest object itself. + */ + public FailoverProcessServerRequest withProperties(FailoverProcessServerRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequestProperties.java new file mode 100644 index 0000000000000..45293e889626c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverProcessServerRequestProperties.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of the Failover Process Server request. + */ +public class FailoverProcessServerRequestProperties { + /** + * The container identifier. + */ + @JsonProperty(value = "containerName") + private String containerName; + + /** + * The source process server. + */ + @JsonProperty(value = "sourceProcessServerId") + private String sourceProcessServerId; + + /** + * The new process server. + */ + @JsonProperty(value = "targetProcessServerId") + private String targetProcessServerId; + + /** + * The VMS to migrate. + */ + @JsonProperty(value = "vmsToMigrate") + private List vmsToMigrate; + + /** + * A value for failover type. It can be systemlevel/serverlevel. + */ + @JsonProperty(value = "updateType") + private String updateType; + + /** + * Get the container identifier. + * + * @return the containerName value + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the container identifier. + * + * @param containerName the containerName value to set + * @return the FailoverProcessServerRequestProperties object itself. + */ + public FailoverProcessServerRequestProperties withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the source process server. + * + * @return the sourceProcessServerId value + */ + public String sourceProcessServerId() { + return this.sourceProcessServerId; + } + + /** + * Set the source process server. + * + * @param sourceProcessServerId the sourceProcessServerId value to set + * @return the FailoverProcessServerRequestProperties object itself. + */ + public FailoverProcessServerRequestProperties withSourceProcessServerId(String sourceProcessServerId) { + this.sourceProcessServerId = sourceProcessServerId; + return this; + } + + /** + * Get the new process server. + * + * @return the targetProcessServerId value + */ + public String targetProcessServerId() { + return this.targetProcessServerId; + } + + /** + * Set the new process server. + * + * @param targetProcessServerId the targetProcessServerId value to set + * @return the FailoverProcessServerRequestProperties object itself. + */ + public FailoverProcessServerRequestProperties withTargetProcessServerId(String targetProcessServerId) { + this.targetProcessServerId = targetProcessServerId; + return this; + } + + /** + * Get the VMS to migrate. + * + * @return the vmsToMigrate value + */ + public List vmsToMigrate() { + return this.vmsToMigrate; + } + + /** + * Set the VMS to migrate. + * + * @param vmsToMigrate the vmsToMigrate value to set + * @return the FailoverProcessServerRequestProperties object itself. + */ + public FailoverProcessServerRequestProperties withVmsToMigrate(List vmsToMigrate) { + this.vmsToMigrate = vmsToMigrate; + return this; + } + + /** + * Get a value for failover type. It can be systemlevel/serverlevel. + * + * @return the updateType value + */ + public String updateType() { + return this.updateType; + } + + /** + * Set a value for failover type. It can be systemlevel/serverlevel. + * + * @param updateType the updateType value to set + * @return the FailoverProcessServerRequestProperties object itself. + */ + public FailoverProcessServerRequestProperties withUpdateType(String updateType) { + this.updateType = updateType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverReplicationProtectedItemDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverReplicationProtectedItemDetails.java new file mode 100644 index 0000000000000..69f20f4b2d4a2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/FailoverReplicationProtectedItemDetails.java @@ -0,0 +1,252 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Failover details for a replication protected item. + */ +public class FailoverReplicationProtectedItemDetails { + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The friendly name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The test Vm name. + */ + @JsonProperty(value = "testVmName") + private String testVmName; + + /** + * The test Vm friendly name. + */ + @JsonProperty(value = "testVmFriendlyName") + private String testVmFriendlyName; + + /** + * The network connection status. + */ + @JsonProperty(value = "networkConnectionStatus") + private String networkConnectionStatus; + + /** + * The network friendly name. + */ + @JsonProperty(value = "networkFriendlyName") + private String networkFriendlyName; + + /** + * The network subnet. + */ + @JsonProperty(value = "subnet") + private String subnet; + + /** + * The recovery point Id. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * The recovery point time. + */ + @JsonProperty(value = "recoveryPointTime") + private DateTime recoveryPointTime; + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the friendly name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the friendly name. + * + * @param friendlyName the friendlyName value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the test Vm name. + * + * @return the testVmName value + */ + public String testVmName() { + return this.testVmName; + } + + /** + * Set the test Vm name. + * + * @param testVmName the testVmName value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withTestVmName(String testVmName) { + this.testVmName = testVmName; + return this; + } + + /** + * Get the test Vm friendly name. + * + * @return the testVmFriendlyName value + */ + public String testVmFriendlyName() { + return this.testVmFriendlyName; + } + + /** + * Set the test Vm friendly name. + * + * @param testVmFriendlyName the testVmFriendlyName value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withTestVmFriendlyName(String testVmFriendlyName) { + this.testVmFriendlyName = testVmFriendlyName; + return this; + } + + /** + * Get the network connection status. + * + * @return the networkConnectionStatus value + */ + public String networkConnectionStatus() { + return this.networkConnectionStatus; + } + + /** + * Set the network connection status. + * + * @param networkConnectionStatus the networkConnectionStatus value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withNetworkConnectionStatus(String networkConnectionStatus) { + this.networkConnectionStatus = networkConnectionStatus; + return this; + } + + /** + * Get the network friendly name. + * + * @return the networkFriendlyName value + */ + public String networkFriendlyName() { + return this.networkFriendlyName; + } + + /** + * Set the network friendly name. + * + * @param networkFriendlyName the networkFriendlyName value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withNetworkFriendlyName(String networkFriendlyName) { + this.networkFriendlyName = networkFriendlyName; + return this; + } + + /** + * Get the network subnet. + * + * @return the subnet value + */ + public String subnet() { + return this.subnet; + } + + /** + * Set the network subnet. + * + * @param subnet the subnet value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withSubnet(String subnet) { + this.subnet = subnet; + return this; + } + + /** + * Get the recovery point Id. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point Id. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + + /** + * Get the recovery point time. + * + * @return the recoveryPointTime value + */ + public DateTime recoveryPointTime() { + return this.recoveryPointTime; + } + + /** + * Set the recovery point time. + * + * @param recoveryPointTime the recoveryPointTime value to set + * @return the FailoverReplicationProtectedItemDetails object itself. + */ + public FailoverReplicationProtectedItemDetails withRecoveryPointTime(DateTime recoveryPointTime) { + this.recoveryPointTime = recoveryPointTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/GroupTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/GroupTaskDetails.java new file mode 100644 index 0000000000000..b838076fa6afb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/GroupTaskDetails.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * This class represents the group task details when parent child relationship + * exists in the drill down. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("GroupTaskDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "InlineWorkflowTaskDetails", value = InlineWorkflowTaskDetails.class), + @JsonSubTypes.Type(name = "RecoveryPlanGroupTaskDetails", value = RecoveryPlanGroupTaskDetails.class), + @JsonSubTypes.Type(name = "RecoveryPlanShutdownGroupTaskDetails", value = RecoveryPlanShutdownGroupTaskDetails.class) +}) +public class GroupTaskDetails { + /** + * The child tasks. + */ + @JsonProperty(value = "childTasks") + private List childTasks; + + /** + * Get the child tasks. + * + * @return the childTasks value + */ + public List childTasks() { + return this.childTasks; + } + + /** + * Set the child tasks. + * + * @param childTasks the childTasks value to set + * @return the GroupTaskDetails object itself. + */ + public GroupTaskDetails withChildTasks(List childTasks) { + this.childTasks = childTasks; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthError.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthError.java new file mode 100644 index 0000000000000..8ff55a03a19d5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthError.java @@ -0,0 +1,362 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Health Error. + */ +public class HealthError { + /** + * The inner health errors. HealthError having a list of HealthError as + * child errors is problematic. InnerHealthError is used because this will + * prevent an infinite loop of structures when Hydra tries to auto-generate + * the contract. We are exposing the related health errors as inner health + * errors and all API consumers can utilize this in the same fashion as + * Exception -&gt; InnerException. + */ + @JsonProperty(value = "innerHealthErrors") + private List innerHealthErrors; + + /** + * Source of error. + */ + @JsonProperty(value = "errorSource") + private String errorSource; + + /** + * Type of error. + */ + @JsonProperty(value = "errorType") + private String errorType; + + /** + * Level of error. + */ + @JsonProperty(value = "errorLevel") + private String errorLevel; + + /** + * Category of error. + */ + @JsonProperty(value = "errorCategory") + private String errorCategory; + + /** + * Error code. + */ + @JsonProperty(value = "errorCode") + private String errorCode; + + /** + * Summary message of the entity. + */ + @JsonProperty(value = "summaryMessage") + private String summaryMessage; + + /** + * Error message. + */ + @JsonProperty(value = "errorMessage") + private String errorMessage; + + /** + * Possible causes of error. + */ + @JsonProperty(value = "possibleCauses") + private String possibleCauses; + + /** + * Recommended action to resolve error. + */ + @JsonProperty(value = "recommendedAction") + private String recommendedAction; + + /** + * Error creation time (UTC). + */ + @JsonProperty(value = "creationTimeUtc") + private DateTime creationTimeUtc; + + /** + * DRA error message. + */ + @JsonProperty(value = "recoveryProviderErrorMessage") + private String recoveryProviderErrorMessage; + + /** + * ID of the entity. + */ + @JsonProperty(value = "entityId") + private String entityId; + + /** + * Get the inner health errors. HealthError having a list of HealthError as child errors is problematic. InnerHealthError is used because this will prevent an infinite loop of structures when Hydra tries to auto-generate the contract. We are exposing the related health errors as inner health errors and all API consumers can utilize this in the same fashion as Exception -&gt; InnerException. + * + * @return the innerHealthErrors value + */ + public List innerHealthErrors() { + return this.innerHealthErrors; + } + + /** + * Set the inner health errors. HealthError having a list of HealthError as child errors is problematic. InnerHealthError is used because this will prevent an infinite loop of structures when Hydra tries to auto-generate the contract. We are exposing the related health errors as inner health errors and all API consumers can utilize this in the same fashion as Exception -&gt; InnerException. + * + * @param innerHealthErrors the innerHealthErrors value to set + * @return the HealthError object itself. + */ + public HealthError withInnerHealthErrors(List innerHealthErrors) { + this.innerHealthErrors = innerHealthErrors; + return this; + } + + /** + * Get source of error. + * + * @return the errorSource value + */ + public String errorSource() { + return this.errorSource; + } + + /** + * Set source of error. + * + * @param errorSource the errorSource value to set + * @return the HealthError object itself. + */ + public HealthError withErrorSource(String errorSource) { + this.errorSource = errorSource; + return this; + } + + /** + * Get type of error. + * + * @return the errorType value + */ + public String errorType() { + return this.errorType; + } + + /** + * Set type of error. + * + * @param errorType the errorType value to set + * @return the HealthError object itself. + */ + public HealthError withErrorType(String errorType) { + this.errorType = errorType; + return this; + } + + /** + * Get level of error. + * + * @return the errorLevel value + */ + public String errorLevel() { + return this.errorLevel; + } + + /** + * Set level of error. + * + * @param errorLevel the errorLevel value to set + * @return the HealthError object itself. + */ + public HealthError withErrorLevel(String errorLevel) { + this.errorLevel = errorLevel; + return this; + } + + /** + * Get category of error. + * + * @return the errorCategory value + */ + public String errorCategory() { + return this.errorCategory; + } + + /** + * Set category of error. + * + * @param errorCategory the errorCategory value to set + * @return the HealthError object itself. + */ + public HealthError withErrorCategory(String errorCategory) { + this.errorCategory = errorCategory; + return this; + } + + /** + * Get error code. + * + * @return the errorCode value + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set error code. + * + * @param errorCode the errorCode value to set + * @return the HealthError object itself. + */ + public HealthError withErrorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * Get summary message of the entity. + * + * @return the summaryMessage value + */ + public String summaryMessage() { + return this.summaryMessage; + } + + /** + * Set summary message of the entity. + * + * @param summaryMessage the summaryMessage value to set + * @return the HealthError object itself. + */ + public HealthError withSummaryMessage(String summaryMessage) { + this.summaryMessage = summaryMessage; + return this; + } + + /** + * Get error message. + * + * @return the errorMessage value + */ + public String errorMessage() { + return this.errorMessage; + } + + /** + * Set error message. + * + * @param errorMessage the errorMessage value to set + * @return the HealthError object itself. + */ + public HealthError withErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + return this; + } + + /** + * Get possible causes of error. + * + * @return the possibleCauses value + */ + public String possibleCauses() { + return this.possibleCauses; + } + + /** + * Set possible causes of error. + * + * @param possibleCauses the possibleCauses value to set + * @return the HealthError object itself. + */ + public HealthError withPossibleCauses(String possibleCauses) { + this.possibleCauses = possibleCauses; + return this; + } + + /** + * Get recommended action to resolve error. + * + * @return the recommendedAction value + */ + public String recommendedAction() { + return this.recommendedAction; + } + + /** + * Set recommended action to resolve error. + * + * @param recommendedAction the recommendedAction value to set + * @return the HealthError object itself. + */ + public HealthError withRecommendedAction(String recommendedAction) { + this.recommendedAction = recommendedAction; + return this; + } + + /** + * Get error creation time (UTC). + * + * @return the creationTimeUtc value + */ + public DateTime creationTimeUtc() { + return this.creationTimeUtc; + } + + /** + * Set error creation time (UTC). + * + * @param creationTimeUtc the creationTimeUtc value to set + * @return the HealthError object itself. + */ + public HealthError withCreationTimeUtc(DateTime creationTimeUtc) { + this.creationTimeUtc = creationTimeUtc; + return this; + } + + /** + * Get dRA error message. + * + * @return the recoveryProviderErrorMessage value + */ + public String recoveryProviderErrorMessage() { + return this.recoveryProviderErrorMessage; + } + + /** + * Set dRA error message. + * + * @param recoveryProviderErrorMessage the recoveryProviderErrorMessage value to set + * @return the HealthError object itself. + */ + public HealthError withRecoveryProviderErrorMessage(String recoveryProviderErrorMessage) { + this.recoveryProviderErrorMessage = recoveryProviderErrorMessage; + return this; + } + + /** + * Get iD of the entity. + * + * @return the entityId value + */ + public String entityId() { + return this.entityId; + } + + /** + * Set iD of the entity. + * + * @param entityId the entityId value to set + * @return the HealthError object itself. + */ + public HealthError withEntityId(String entityId) { + this.entityId = entityId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorCategory.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorCategory.java new file mode 100644 index 0000000000000..e63142156b898 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorCategory.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for HealthErrorCategory. + */ +public final class HealthErrorCategory extends ExpandableStringEnum { + /** Static value None for HealthErrorCategory. */ + public static final HealthErrorCategory NONE = fromString("None"); + + /** Static value Replication for HealthErrorCategory. */ + public static final HealthErrorCategory REPLICATION = fromString("Replication"); + + /** Static value TestFailover for HealthErrorCategory. */ + public static final HealthErrorCategory TEST_FAILOVER = fromString("TestFailover"); + + /** Static value Configuration for HealthErrorCategory. */ + public static final HealthErrorCategory CONFIGURATION = fromString("Configuration"); + + /** Static value FabricInfrastructure for HealthErrorCategory. */ + public static final HealthErrorCategory FABRIC_INFRASTRUCTURE = fromString("FabricInfrastructure"); + + /** Static value VersionExpiry for HealthErrorCategory. */ + public static final HealthErrorCategory VERSION_EXPIRY = fromString("VersionExpiry"); + + /** Static value AgentAutoUpdate for HealthErrorCategory. */ + public static final HealthErrorCategory AGENT_AUTO_UPDATE = fromString("AgentAutoUpdate"); + + /** + * Creates or finds a HealthErrorCategory from its string representation. + * @param name a name to look for + * @return the corresponding HealthErrorCategory + */ + @JsonCreator + public static HealthErrorCategory fromString(String name) { + return fromString(name, HealthErrorCategory.class); + } + + /** + * @return known HealthErrorCategory values + */ + public static Collection values() { + return values(HealthErrorCategory.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorSummary.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorSummary.java new file mode 100644 index 0000000000000..1f471245e2043 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HealthErrorSummary.java @@ -0,0 +1,206 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * class to define the summary of the health error details. + */ +public class HealthErrorSummary { + /** + * The code of the health error. + */ + @JsonProperty(value = "summaryCode") + private String summaryCode; + + /** + * The category of the health error. Possible values include: 'None', + * 'Replication', 'TestFailover', 'Configuration', 'FabricInfrastructure', + * 'VersionExpiry', 'AgentAutoUpdate'. + */ + @JsonProperty(value = "category") + private HealthErrorCategory category; + + /** + * Severity of error. Possible values include: 'NONE', 'Warning', 'Error', + * 'Info'. + */ + @JsonProperty(value = "severity") + private Severity severity; + + /** + * The summary message of the health error. + */ + @JsonProperty(value = "summaryMessage") + private String summaryMessage; + + /** + * The type of affected ARM resource. + */ + @JsonProperty(value = "affectedResourceType") + private String affectedResourceType; + + /** + * The sub type of any subcomponent within the ARM resource that this might + * be applicable. Value remains null if not applicable. + */ + @JsonProperty(value = "affectedResourceSubtype") + private String affectedResourceSubtype; + + /** + * The list of affected resource correlation Ids. This can be used to + * uniquely identify the count of items affected by a specific category and + * severity as well as count of item affected by an specific issue. + */ + @JsonProperty(value = "affectedResourceCorrelationIds") + private List affectedResourceCorrelationIds; + + /** + * Get the code of the health error. + * + * @return the summaryCode value + */ + public String summaryCode() { + return this.summaryCode; + } + + /** + * Set the code of the health error. + * + * @param summaryCode the summaryCode value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withSummaryCode(String summaryCode) { + this.summaryCode = summaryCode; + return this; + } + + /** + * Get the category of the health error. Possible values include: 'None', 'Replication', 'TestFailover', 'Configuration', 'FabricInfrastructure', 'VersionExpiry', 'AgentAutoUpdate'. + * + * @return the category value + */ + public HealthErrorCategory category() { + return this.category; + } + + /** + * Set the category of the health error. Possible values include: 'None', 'Replication', 'TestFailover', 'Configuration', 'FabricInfrastructure', 'VersionExpiry', 'AgentAutoUpdate'. + * + * @param category the category value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withCategory(HealthErrorCategory category) { + this.category = category; + return this; + } + + /** + * Get severity of error. Possible values include: 'NONE', 'Warning', 'Error', 'Info'. + * + * @return the severity value + */ + public Severity severity() { + return this.severity; + } + + /** + * Set severity of error. Possible values include: 'NONE', 'Warning', 'Error', 'Info'. + * + * @param severity the severity value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withSeverity(Severity severity) { + this.severity = severity; + return this; + } + + /** + * Get the summary message of the health error. + * + * @return the summaryMessage value + */ + public String summaryMessage() { + return this.summaryMessage; + } + + /** + * Set the summary message of the health error. + * + * @param summaryMessage the summaryMessage value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withSummaryMessage(String summaryMessage) { + this.summaryMessage = summaryMessage; + return this; + } + + /** + * Get the type of affected ARM resource. + * + * @return the affectedResourceType value + */ + public String affectedResourceType() { + return this.affectedResourceType; + } + + /** + * Set the type of affected ARM resource. + * + * @param affectedResourceType the affectedResourceType value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withAffectedResourceType(String affectedResourceType) { + this.affectedResourceType = affectedResourceType; + return this; + } + + /** + * Get the sub type of any subcomponent within the ARM resource that this might be applicable. Value remains null if not applicable. + * + * @return the affectedResourceSubtype value + */ + public String affectedResourceSubtype() { + return this.affectedResourceSubtype; + } + + /** + * Set the sub type of any subcomponent within the ARM resource that this might be applicable. Value remains null if not applicable. + * + * @param affectedResourceSubtype the affectedResourceSubtype value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withAffectedResourceSubtype(String affectedResourceSubtype) { + this.affectedResourceSubtype = affectedResourceSubtype; + return this; + } + + /** + * Get the list of affected resource correlation Ids. This can be used to uniquely identify the count of items affected by a specific category and severity as well as count of item affected by an specific issue. + * + * @return the affectedResourceCorrelationIds value + */ + public List affectedResourceCorrelationIds() { + return this.affectedResourceCorrelationIds; + } + + /** + * Set the list of affected resource correlation Ids. This can be used to uniquely identify the count of items affected by a specific category and severity as well as count of item affected by an specific issue. + * + * @param affectedResourceCorrelationIds the affectedResourceCorrelationIds value to set + * @return the HealthErrorSummary object itself. + */ + public HealthErrorSummary withAffectedResourceCorrelationIds(List affectedResourceCorrelationIds) { + this.affectedResourceCorrelationIds = affectedResourceCorrelationIds; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012EventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012EventDetails.java new file mode 100644 index 0000000000000..bde002947d04f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012EventDetails.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a HyperVReplica E2E event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012") +public class HyperVReplica2012EventDetails extends EventProviderSpecificDetails { + /** + * The container friendly name. + */ + @JsonProperty(value = "containerName") + private String containerName; + + /** + * The fabric friendly name. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The remote container name. + */ + @JsonProperty(value = "remoteContainerName") + private String remoteContainerName; + + /** + * The remote fabric name. + */ + @JsonProperty(value = "remoteFabricName") + private String remoteFabricName; + + /** + * Get the container friendly name. + * + * @return the containerName value + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the container friendly name. + * + * @param containerName the containerName value to set + * @return the HyperVReplica2012EventDetails object itself. + */ + public HyperVReplica2012EventDetails withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the fabric friendly name. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set the fabric friendly name. + * + * @param fabricName the fabricName value to set + * @return the HyperVReplica2012EventDetails object itself. + */ + public HyperVReplica2012EventDetails withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the remote container name. + * + * @return the remoteContainerName value + */ + public String remoteContainerName() { + return this.remoteContainerName; + } + + /** + * Set the remote container name. + * + * @param remoteContainerName the remoteContainerName value to set + * @return the HyperVReplica2012EventDetails object itself. + */ + public HyperVReplica2012EventDetails withRemoteContainerName(String remoteContainerName) { + this.remoteContainerName = remoteContainerName; + return this; + } + + /** + * Get the remote fabric name. + * + * @return the remoteFabricName value + */ + public String remoteFabricName() { + return this.remoteFabricName; + } + + /** + * Set the remote fabric name. + * + * @param remoteFabricName the remoteFabricName value to set + * @return the HyperVReplica2012EventDetails object itself. + */ + public HyperVReplica2012EventDetails withRemoteFabricName(String remoteFabricName) { + this.remoteFabricName = remoteFabricName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012R2EventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012R2EventDetails.java new file mode 100644 index 0000000000000..f1519f0a82ce8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplica2012R2EventDetails.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a HyperVReplica blue E2E event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012R2") +public class HyperVReplica2012R2EventDetails extends EventProviderSpecificDetails { + /** + * The container friendly name. + */ + @JsonProperty(value = "containerName") + private String containerName; + + /** + * The fabric friendly name. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The remote container name. + */ + @JsonProperty(value = "remoteContainerName") + private String remoteContainerName; + + /** + * The remote fabric name. + */ + @JsonProperty(value = "remoteFabricName") + private String remoteFabricName; + + /** + * Get the container friendly name. + * + * @return the containerName value + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the container friendly name. + * + * @param containerName the containerName value to set + * @return the HyperVReplica2012R2EventDetails object itself. + */ + public HyperVReplica2012R2EventDetails withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the fabric friendly name. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set the fabric friendly name. + * + * @param fabricName the fabricName value to set + * @return the HyperVReplica2012R2EventDetails object itself. + */ + public HyperVReplica2012R2EventDetails withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the remote container name. + * + * @return the remoteContainerName value + */ + public String remoteContainerName() { + return this.remoteContainerName; + } + + /** + * Set the remote container name. + * + * @param remoteContainerName the remoteContainerName value to set + * @return the HyperVReplica2012R2EventDetails object itself. + */ + public HyperVReplica2012R2EventDetails withRemoteContainerName(String remoteContainerName) { + this.remoteContainerName = remoteContainerName; + return this; + } + + /** + * Get the remote fabric name. + * + * @return the remoteFabricName value + */ + public String remoteFabricName() { + return this.remoteFabricName; + } + + /** + * Set the remote fabric name. + * + * @param remoteFabricName the remoteFabricName value to set + * @return the HyperVReplica2012R2EventDetails object itself. + */ + public HyperVReplica2012R2EventDetails withRemoteFabricName(String remoteFabricName) { + this.remoteFabricName = remoteFabricName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureApplyRecoveryPointInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureApplyRecoveryPointInput.java new file mode 100644 index 0000000000000..59de305a56969 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureApplyRecoveryPointInput.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ApplyRecoveryPoint input specific to HyperVReplicaAzure provider. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureApplyRecoveryPointInput extends ApplyRecoveryPointProviderSpecificInput { + /** + * The vault location where the recovery Vm resides. + */ + @JsonProperty(value = "vaultLocation") + private String vaultLocation; + + /** + * The primary kek certificate pfx. + */ + @JsonProperty(value = "primaryKekCertificatePfx") + private String primaryKekCertificatePfx; + + /** + * The secondary kek certificate pfx. + */ + @JsonProperty(value = "secondaryKekCertificatePfx") + private String secondaryKekCertificatePfx; + + /** + * Get the vault location where the recovery Vm resides. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set the vault location where the recovery Vm resides. + * + * @param vaultLocation the vaultLocation value to set + * @return the HyperVReplicaAzureApplyRecoveryPointInput object itself. + */ + public HyperVReplicaAzureApplyRecoveryPointInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + + /** + * Get the primary kek certificate pfx. + * + * @return the primaryKekCertificatePfx value + */ + public String primaryKekCertificatePfx() { + return this.primaryKekCertificatePfx; + } + + /** + * Set the primary kek certificate pfx. + * + * @param primaryKekCertificatePfx the primaryKekCertificatePfx value to set + * @return the HyperVReplicaAzureApplyRecoveryPointInput object itself. + */ + public HyperVReplicaAzureApplyRecoveryPointInput withPrimaryKekCertificatePfx(String primaryKekCertificatePfx) { + this.primaryKekCertificatePfx = primaryKekCertificatePfx; + return this; + } + + /** + * Get the secondary kek certificate pfx. + * + * @return the secondaryKekCertificatePfx value + */ + public String secondaryKekCertificatePfx() { + return this.secondaryKekCertificatePfx; + } + + /** + * Set the secondary kek certificate pfx. + * + * @param secondaryKekCertificatePfx the secondaryKekCertificatePfx value to set + * @return the HyperVReplicaAzureApplyRecoveryPointInput object itself. + */ + public HyperVReplicaAzureApplyRecoveryPointInput withSecondaryKekCertificatePfx(String secondaryKekCertificatePfx) { + this.secondaryKekCertificatePfx = secondaryKekCertificatePfx; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEnableProtectionInput.java new file mode 100644 index 0000000000000..1e31ba569cc00 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEnableProtectionInput.java @@ -0,0 +1,389 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Azure specific enable protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureEnableProtectionInput extends EnableProtectionProviderSpecificInput { + /** + * The Hyper-V host Vm Id. + */ + @JsonProperty(value = "hvHostVmId") + private String hvHostVmId; + + /** + * The Vm Name. + */ + @JsonProperty(value = "vmName") + private String vmName; + + /** + * The OS type associated with vm. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The OS disk VHD id associated with vm. + */ + @JsonProperty(value = "vhdId") + private String vhdId; + + /** + * The storage account name. + */ + @JsonProperty(value = "targetStorageAccountId") + private String targetStorageAccountId; + + /** + * The selected target Azure network Id. + */ + @JsonProperty(value = "targetAzureNetworkId") + private String targetAzureNetworkId; + + /** + * The selected target Azure subnet Id. + */ + @JsonProperty(value = "targetAzureSubnetId") + private String targetAzureSubnetId; + + /** + * The selected option to enable RDP\SSH on target vm after failover. + * String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + */ + @JsonProperty(value = "enableRdpOnTargetOption") + private String enableRdpOnTargetOption; + + /** + * The target azure Vm Name. + */ + @JsonProperty(value = "targetAzureVmName") + private String targetAzureVmName; + + /** + * The storage account to be used for logging during replication. + */ + @JsonProperty(value = "logStorageAccountId") + private String logStorageAccountId; + + /** + * The list of VHD IDs of disks to be protected. + */ + @JsonProperty(value = "disksToInclude") + private List disksToInclude; + + /** + * The Id of the target resource group (for classic deployment) in which + * the failover VM is to be created. + */ + @JsonProperty(value = "targetAzureV1ResourceGroupId") + private String targetAzureV1ResourceGroupId; + + /** + * The Id of the target resource group (for resource manager deployment) in + * which the failover VM is to be created. + */ + @JsonProperty(value = "targetAzureV2ResourceGroupId") + private String targetAzureV2ResourceGroupId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * Get the Hyper-V host Vm Id. + * + * @return the hvHostVmId value + */ + public String hvHostVmId() { + return this.hvHostVmId; + } + + /** + * Set the Hyper-V host Vm Id. + * + * @param hvHostVmId the hvHostVmId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withHvHostVmId(String hvHostVmId) { + this.hvHostVmId = hvHostVmId; + return this; + } + + /** + * Get the Vm Name. + * + * @return the vmName value + */ + public String vmName() { + return this.vmName; + } + + /** + * Set the Vm Name. + * + * @param vmName the vmName value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withVmName(String vmName) { + this.vmName = vmName; + return this; + } + + /** + * Get the OS type associated with vm. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type associated with vm. + * + * @param osType the osType value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the OS disk VHD id associated with vm. + * + * @return the vhdId value + */ + public String vhdId() { + return this.vhdId; + } + + /** + * Set the OS disk VHD id associated with vm. + * + * @param vhdId the vhdId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withVhdId(String vhdId) { + this.vhdId = vhdId; + return this; + } + + /** + * Get the storage account name. + * + * @return the targetStorageAccountId value + */ + public String targetStorageAccountId() { + return this.targetStorageAccountId; + } + + /** + * Set the storage account name. + * + * @param targetStorageAccountId the targetStorageAccountId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetStorageAccountId(String targetStorageAccountId) { + this.targetStorageAccountId = targetStorageAccountId; + return this; + } + + /** + * Get the selected target Azure network Id. + * + * @return the targetAzureNetworkId value + */ + public String targetAzureNetworkId() { + return this.targetAzureNetworkId; + } + + /** + * Set the selected target Azure network Id. + * + * @param targetAzureNetworkId the targetAzureNetworkId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetAzureNetworkId(String targetAzureNetworkId) { + this.targetAzureNetworkId = targetAzureNetworkId; + return this; + } + + /** + * Get the selected target Azure subnet Id. + * + * @return the targetAzureSubnetId value + */ + public String targetAzureSubnetId() { + return this.targetAzureSubnetId; + } + + /** + * Set the selected target Azure subnet Id. + * + * @param targetAzureSubnetId the targetAzureSubnetId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetAzureSubnetId(String targetAzureSubnetId) { + this.targetAzureSubnetId = targetAzureSubnetId; + return this; + } + + /** + * Get the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @return the enableRdpOnTargetOption value + */ + public String enableRdpOnTargetOption() { + return this.enableRdpOnTargetOption; + } + + /** + * Set the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @param enableRdpOnTargetOption the enableRdpOnTargetOption value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withEnableRdpOnTargetOption(String enableRdpOnTargetOption) { + this.enableRdpOnTargetOption = enableRdpOnTargetOption; + return this; + } + + /** + * Get the target azure Vm Name. + * + * @return the targetAzureVmName value + */ + public String targetAzureVmName() { + return this.targetAzureVmName; + } + + /** + * Set the target azure Vm Name. + * + * @param targetAzureVmName the targetAzureVmName value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetAzureVmName(String targetAzureVmName) { + this.targetAzureVmName = targetAzureVmName; + return this; + } + + /** + * Get the storage account to be used for logging during replication. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Set the storage account to be used for logging during replication. + * + * @param logStorageAccountId the logStorageAccountId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withLogStorageAccountId(String logStorageAccountId) { + this.logStorageAccountId = logStorageAccountId; + return this; + } + + /** + * Get the list of VHD IDs of disks to be protected. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the list of VHD IDs of disks to be protected. + * + * @param disksToInclude the disksToInclude value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + + /** + * Get the Id of the target resource group (for classic deployment) in which the failover VM is to be created. + * + * @return the targetAzureV1ResourceGroupId value + */ + public String targetAzureV1ResourceGroupId() { + return this.targetAzureV1ResourceGroupId; + } + + /** + * Set the Id of the target resource group (for classic deployment) in which the failover VM is to be created. + * + * @param targetAzureV1ResourceGroupId the targetAzureV1ResourceGroupId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetAzureV1ResourceGroupId(String targetAzureV1ResourceGroupId) { + this.targetAzureV1ResourceGroupId = targetAzureV1ResourceGroupId; + return this; + } + + /** + * Get the Id of the target resource group (for resource manager deployment) in which the failover VM is to be created. + * + * @return the targetAzureV2ResourceGroupId value + */ + public String targetAzureV2ResourceGroupId() { + return this.targetAzureV2ResourceGroupId; + } + + /** + * Set the Id of the target resource group (for resource manager deployment) in which the failover VM is to be created. + * + * @param targetAzureV2ResourceGroupId the targetAzureV2ResourceGroupId value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withTargetAzureV2ResourceGroupId(String targetAzureV2ResourceGroupId) { + this.targetAzureV2ResourceGroupId = targetAzureV2ResourceGroupId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the HyperVReplicaAzureEnableProtectionInput object itself. + */ + public HyperVReplicaAzureEnableProtectionInput withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEventDetails.java new file mode 100644 index 0000000000000..dcf85b599fe4a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureEventDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a HyperVReplica E2A event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureEventDetails extends EventProviderSpecificDetails { + /** + * The container friendly name. + */ + @JsonProperty(value = "containerName") + private String containerName; + + /** + * The fabric friendly name. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The remote container name. + */ + @JsonProperty(value = "remoteContainerName") + private String remoteContainerName; + + /** + * Get the container friendly name. + * + * @return the containerName value + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the container friendly name. + * + * @param containerName the containerName value to set + * @return the HyperVReplicaAzureEventDetails object itself. + */ + public HyperVReplicaAzureEventDetails withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the fabric friendly name. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set the fabric friendly name. + * + * @param fabricName the fabricName value to set + * @return the HyperVReplicaAzureEventDetails object itself. + */ + public HyperVReplicaAzureEventDetails withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the remote container name. + * + * @return the remoteContainerName value + */ + public String remoteContainerName() { + return this.remoteContainerName; + } + + /** + * Set the remote container name. + * + * @param remoteContainerName the remoteContainerName value to set + * @return the HyperVReplicaAzureEventDetails object itself. + */ + public HyperVReplicaAzureEventDetails withRemoteContainerName(String remoteContainerName) { + this.remoteContainerName = remoteContainerName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailbackProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailbackProviderInput.java new file mode 100644 index 0000000000000..5a6a362dd08f3 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailbackProviderInput.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HvrA provider specific input for failback. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzureFailback") +public class HyperVReplicaAzureFailbackProviderInput extends ProviderSpecificFailoverInput { + /** + * Data sync option. + */ + @JsonProperty(value = "dataSyncOption") + private String dataSyncOption; + + /** + * ALR options to create alternate recovery. + */ + @JsonProperty(value = "recoveryVmCreationOption") + private String recoveryVmCreationOption; + + /** + * Provider ID for alternate location. + */ + @JsonProperty(value = "providerIdForAlternateRecovery") + private String providerIdForAlternateRecovery; + + /** + * Get data sync option. + * + * @return the dataSyncOption value + */ + public String dataSyncOption() { + return this.dataSyncOption; + } + + /** + * Set data sync option. + * + * @param dataSyncOption the dataSyncOption value to set + * @return the HyperVReplicaAzureFailbackProviderInput object itself. + */ + public HyperVReplicaAzureFailbackProviderInput withDataSyncOption(String dataSyncOption) { + this.dataSyncOption = dataSyncOption; + return this; + } + + /** + * Get aLR options to create alternate recovery. + * + * @return the recoveryVmCreationOption value + */ + public String recoveryVmCreationOption() { + return this.recoveryVmCreationOption; + } + + /** + * Set aLR options to create alternate recovery. + * + * @param recoveryVmCreationOption the recoveryVmCreationOption value to set + * @return the HyperVReplicaAzureFailbackProviderInput object itself. + */ + public HyperVReplicaAzureFailbackProviderInput withRecoveryVmCreationOption(String recoveryVmCreationOption) { + this.recoveryVmCreationOption = recoveryVmCreationOption; + return this; + } + + /** + * Get provider ID for alternate location. + * + * @return the providerIdForAlternateRecovery value + */ + public String providerIdForAlternateRecovery() { + return this.providerIdForAlternateRecovery; + } + + /** + * Set provider ID for alternate location. + * + * @param providerIdForAlternateRecovery the providerIdForAlternateRecovery value to set + * @return the HyperVReplicaAzureFailbackProviderInput object itself. + */ + public HyperVReplicaAzureFailbackProviderInput withProviderIdForAlternateRecovery(String providerIdForAlternateRecovery) { + this.providerIdForAlternateRecovery = providerIdForAlternateRecovery; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailoverProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailoverProviderInput.java new file mode 100644 index 0000000000000..880bbe4dec174 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureFailoverProviderInput.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HvrA provider specific input for failover. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureFailoverProviderInput extends ProviderSpecificFailoverInput { + /** + * Location of the vault. + */ + @JsonProperty(value = "vaultLocation") + private String vaultLocation; + + /** + * Primary kek certificate pfx. + */ + @JsonProperty(value = "primaryKekCertificatePfx") + private String primaryKekCertificatePfx; + + /** + * Secondary kek certificate pfx. + */ + @JsonProperty(value = "secondaryKekCertificatePfx") + private String secondaryKekCertificatePfx; + + /** + * The recovery point id to be passed to failover to a particular recovery + * point. In case of latest recovery point, null should be passed. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * Get location of the vault. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set location of the vault. + * + * @param vaultLocation the vaultLocation value to set + * @return the HyperVReplicaAzureFailoverProviderInput object itself. + */ + public HyperVReplicaAzureFailoverProviderInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + + /** + * Get primary kek certificate pfx. + * + * @return the primaryKekCertificatePfx value + */ + public String primaryKekCertificatePfx() { + return this.primaryKekCertificatePfx; + } + + /** + * Set primary kek certificate pfx. + * + * @param primaryKekCertificatePfx the primaryKekCertificatePfx value to set + * @return the HyperVReplicaAzureFailoverProviderInput object itself. + */ + public HyperVReplicaAzureFailoverProviderInput withPrimaryKekCertificatePfx(String primaryKekCertificatePfx) { + this.primaryKekCertificatePfx = primaryKekCertificatePfx; + return this; + } + + /** + * Get secondary kek certificate pfx. + * + * @return the secondaryKekCertificatePfx value + */ + public String secondaryKekCertificatePfx() { + return this.secondaryKekCertificatePfx; + } + + /** + * Set secondary kek certificate pfx. + * + * @param secondaryKekCertificatePfx the secondaryKekCertificatePfx value to set + * @return the HyperVReplicaAzureFailoverProviderInput object itself. + */ + public HyperVReplicaAzureFailoverProviderInput withSecondaryKekCertificatePfx(String secondaryKekCertificatePfx) { + this.secondaryKekCertificatePfx = secondaryKekCertificatePfx; + return this; + } + + /** + * Get the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the HyperVReplicaAzureFailoverProviderInput object itself. + */ + public HyperVReplicaAzureFailoverProviderInput withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyDetails.java new file mode 100644 index 0000000000000..e5187c7f14c8b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyDetails.java @@ -0,0 +1,181 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper-V Replica Azure specific protection profile details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzurePolicyDetails extends PolicyProviderSpecificDetails { + /** + * The duration (in hours) to which point the recovery history needs to be + * maintained. + */ + @JsonProperty(value = "recoveryPointHistoryDurationInHours") + private Integer recoveryPointHistoryDurationInHours; + + /** + * The interval (in hours) at which Hyper-V Replica should create an + * application consistent snapshot within the VM. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * The replication interval. + */ + @JsonProperty(value = "replicationInterval") + private Integer replicationInterval; + + /** + * The scheduled start time for the initial replication. If this parameter + * is Null, the initial replication starts immediately. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating whether encryption is enabled for virtual machines in + * this cloud. + */ + @JsonProperty(value = "encryption") + private String encryption; + + /** + * The active storage account Id. + */ + @JsonProperty(value = "activeStorageAccountId") + private String activeStorageAccountId; + + /** + * Get the duration (in hours) to which point the recovery history needs to be maintained. + * + * @return the recoveryPointHistoryDurationInHours value + */ + public Integer recoveryPointHistoryDurationInHours() { + return this.recoveryPointHistoryDurationInHours; + } + + /** + * Set the duration (in hours) to which point the recovery history needs to be maintained. + * + * @param recoveryPointHistoryDurationInHours the recoveryPointHistoryDurationInHours value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withRecoveryPointHistoryDurationInHours(Integer recoveryPointHistoryDurationInHours) { + this.recoveryPointHistoryDurationInHours = recoveryPointHistoryDurationInHours; + return this; + } + + /** + * Get the interval (in hours) at which Hyper-V Replica should create an application consistent snapshot within the VM. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set the interval (in hours) at which Hyper-V Replica should create an application consistent snapshot within the VM. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get the replication interval. + * + * @return the replicationInterval value + */ + public Integer replicationInterval() { + return this.replicationInterval; + } + + /** + * Set the replication interval. + * + * @param replicationInterval the replicationInterval value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withReplicationInterval(Integer replicationInterval) { + this.replicationInterval = replicationInterval; + return this; + } + + /** + * Get the scheduled start time for the initial replication. If this parameter is Null, the initial replication starts immediately. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set the scheduled start time for the initial replication. If this parameter is Null, the initial replication starts immediately. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating whether encryption is enabled for virtual machines in this cloud. + * + * @return the encryption value + */ + public String encryption() { + return this.encryption; + } + + /** + * Set a value indicating whether encryption is enabled for virtual machines in this cloud. + * + * @param encryption the encryption value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withEncryption(String encryption) { + this.encryption = encryption; + return this; + } + + /** + * Get the active storage account Id. + * + * @return the activeStorageAccountId value + */ + public String activeStorageAccountId() { + return this.activeStorageAccountId; + } + + /** + * Set the active storage account Id. + * + * @param activeStorageAccountId the activeStorageAccountId value to set + * @return the HyperVReplicaAzurePolicyDetails object itself. + */ + public HyperVReplicaAzurePolicyDetails withActiveStorageAccountId(String activeStorageAccountId) { + this.activeStorageAccountId = activeStorageAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyInput.java new file mode 100644 index 0000000000000..de31d7a9c5a28 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzurePolicyInput.java @@ -0,0 +1,156 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper-V Replica Azure specific input for creating a protection profile. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzurePolicyInput extends PolicyProviderSpecificInput { + /** + * The duration (in hours) to which point the recovery history needs to be + * maintained. + */ + @JsonProperty(value = "recoveryPointHistoryDuration") + private Integer recoveryPointHistoryDuration; + + /** + * The interval (in hours) at which Hyper-V Replica should create an + * application consistent snapshot within the VM. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * The replication interval. + */ + @JsonProperty(value = "replicationInterval") + private Integer replicationInterval; + + /** + * The scheduled start time for the initial replication. If this parameter + * is Null, the initial replication starts immediately. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * The list of storage accounts to which the VMs in the primary cloud can + * replicate to. + */ + @JsonProperty(value = "storageAccounts") + private List storageAccounts; + + /** + * Get the duration (in hours) to which point the recovery history needs to be maintained. + * + * @return the recoveryPointHistoryDuration value + */ + public Integer recoveryPointHistoryDuration() { + return this.recoveryPointHistoryDuration; + } + + /** + * Set the duration (in hours) to which point the recovery history needs to be maintained. + * + * @param recoveryPointHistoryDuration the recoveryPointHistoryDuration value to set + * @return the HyperVReplicaAzurePolicyInput object itself. + */ + public HyperVReplicaAzurePolicyInput withRecoveryPointHistoryDuration(Integer recoveryPointHistoryDuration) { + this.recoveryPointHistoryDuration = recoveryPointHistoryDuration; + return this; + } + + /** + * Get the interval (in hours) at which Hyper-V Replica should create an application consistent snapshot within the VM. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set the interval (in hours) at which Hyper-V Replica should create an application consistent snapshot within the VM. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaAzurePolicyInput object itself. + */ + public HyperVReplicaAzurePolicyInput withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get the replication interval. + * + * @return the replicationInterval value + */ + public Integer replicationInterval() { + return this.replicationInterval; + } + + /** + * Set the replication interval. + * + * @param replicationInterval the replicationInterval value to set + * @return the HyperVReplicaAzurePolicyInput object itself. + */ + public HyperVReplicaAzurePolicyInput withReplicationInterval(Integer replicationInterval) { + this.replicationInterval = replicationInterval; + return this; + } + + /** + * Get the scheduled start time for the initial replication. If this parameter is Null, the initial replication starts immediately. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set the scheduled start time for the initial replication. If this parameter is Null, the initial replication starts immediately. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaAzurePolicyInput object itself. + */ + public HyperVReplicaAzurePolicyInput withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get the list of storage accounts to which the VMs in the primary cloud can replicate to. + * + * @return the storageAccounts value + */ + public List storageAccounts() { + return this.storageAccounts; + } + + /** + * Set the list of storage accounts to which the VMs in the primary cloud can replicate to. + * + * @param storageAccounts the storageAccounts value to set + * @return the HyperVReplicaAzurePolicyInput object itself. + */ + public HyperVReplicaAzurePolicyInput withStorageAccounts(List storageAccounts) { + this.storageAccounts = storageAccounts; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReplicationDetails.java new file mode 100644 index 0000000000000..dd77e48a2c78d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReplicationDetails.java @@ -0,0 +1,651 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper V Replica Azure provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * Azure VM Disk details. + */ + @JsonProperty(value = "azureVmDiskDetails") + private List azureVmDiskDetails; + + /** + * Recovery Azure given name. + */ + @JsonProperty(value = "recoveryAzureVmName") + private String recoveryAzureVmName; + + /** + * The Recovery Azure VM size. + */ + @JsonProperty(value = "recoveryAzureVMSize") + private String recoveryAzureVMSize; + + /** + * The recovery Azure storage account. + */ + @JsonProperty(value = "recoveryAzureStorageAccount") + private String recoveryAzureStorageAccount; + + /** + * The ARM id of the log storage account used for replication. This will be + * set to null if no log storage account was provided during enable + * protection. + */ + @JsonProperty(value = "recoveryAzureLogStorageAccountId") + private String recoveryAzureLogStorageAccountId; + + /** + * The Last replication time. + */ + @JsonProperty(value = "lastReplicatedTime") + private DateTime lastReplicatedTime; + + /** + * Last RPO value. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * The last RPO calculated time. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * Initial replication details. + */ + @JsonProperty(value = "initialReplicationDetails") + private InitialReplicationDetails initialReplicationDetails; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The selected recovery azure network Id. + */ + @JsonProperty(value = "selectedRecoveryAzureNetworkId") + private String selectedRecoveryAzureNetworkId; + + /** + * The selected source nic Id which will be used as the primary nic during + * failover. + */ + @JsonProperty(value = "selectedSourceNicId") + private String selectedSourceNicId; + + /** + * The encryption info. + */ + @JsonProperty(value = "encryption") + private String encryption; + + /** + * The operating system info. + */ + @JsonProperty(value = "oSDetails") + private OSDetails oSDetails; + + /** + * The RAM size of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmRamSizeInMB") + private Integer sourceVmRamSizeInMB; + + /** + * The CPU count of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmCpuCount") + private Integer sourceVmCpuCount; + + /** + * The selected option to enable RDP\SSH on target vm after failover. + * String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + */ + @JsonProperty(value = "enableRdpOnTargetOption") + private String enableRdpOnTargetOption; + + /** + * The target resource group Id. + */ + @JsonProperty(value = "recoveryAzureResourceGroupId") + private String recoveryAzureResourceGroupId; + + /** + * The recovery availability set Id. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * License Type of the VM to be used. + */ + @JsonProperty(value = "licenseType") + private String licenseType; + + /** + * Get azure VM Disk details. + * + * @return the azureVmDiskDetails value + */ + public List azureVmDiskDetails() { + return this.azureVmDiskDetails; + } + + /** + * Set azure VM Disk details. + * + * @param azureVmDiskDetails the azureVmDiskDetails value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withAzureVmDiskDetails(List azureVmDiskDetails) { + this.azureVmDiskDetails = azureVmDiskDetails; + return this; + } + + /** + * Get recovery Azure given name. + * + * @return the recoveryAzureVmName value + */ + public String recoveryAzureVmName() { + return this.recoveryAzureVmName; + } + + /** + * Set recovery Azure given name. + * + * @param recoveryAzureVmName the recoveryAzureVmName value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAzureVmName(String recoveryAzureVmName) { + this.recoveryAzureVmName = recoveryAzureVmName; + return this; + } + + /** + * Get the Recovery Azure VM size. + * + * @return the recoveryAzureVMSize value + */ + public String recoveryAzureVMSize() { + return this.recoveryAzureVMSize; + } + + /** + * Set the Recovery Azure VM size. + * + * @param recoveryAzureVMSize the recoveryAzureVMSize value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAzureVMSize(String recoveryAzureVMSize) { + this.recoveryAzureVMSize = recoveryAzureVMSize; + return this; + } + + /** + * Get the recovery Azure storage account. + * + * @return the recoveryAzureStorageAccount value + */ + public String recoveryAzureStorageAccount() { + return this.recoveryAzureStorageAccount; + } + + /** + * Set the recovery Azure storage account. + * + * @param recoveryAzureStorageAccount the recoveryAzureStorageAccount value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAzureStorageAccount(String recoveryAzureStorageAccount) { + this.recoveryAzureStorageAccount = recoveryAzureStorageAccount; + return this; + } + + /** + * Get the ARM id of the log storage account used for replication. This will be set to null if no log storage account was provided during enable protection. + * + * @return the recoveryAzureLogStorageAccountId value + */ + public String recoveryAzureLogStorageAccountId() { + return this.recoveryAzureLogStorageAccountId; + } + + /** + * Set the ARM id of the log storage account used for replication. This will be set to null if no log storage account was provided during enable protection. + * + * @param recoveryAzureLogStorageAccountId the recoveryAzureLogStorageAccountId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAzureLogStorageAccountId(String recoveryAzureLogStorageAccountId) { + this.recoveryAzureLogStorageAccountId = recoveryAzureLogStorageAccountId; + return this; + } + + /** + * Get the Last replication time. + * + * @return the lastReplicatedTime value + */ + public DateTime lastReplicatedTime() { + return this.lastReplicatedTime; + } + + /** + * Set the Last replication time. + * + * @param lastReplicatedTime the lastReplicatedTime value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withLastReplicatedTime(DateTime lastReplicatedTime) { + this.lastReplicatedTime = lastReplicatedTime; + return this; + } + + /** + * Get last RPO value. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set last RPO value. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get the last RPO calculated time. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the last RPO calculated time. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get initial replication details. + * + * @return the initialReplicationDetails value + */ + public InitialReplicationDetails initialReplicationDetails() { + return this.initialReplicationDetails; + } + + /** + * Set initial replication details. + * + * @param initialReplicationDetails the initialReplicationDetails value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withInitialReplicationDetails(InitialReplicationDetails initialReplicationDetails) { + this.initialReplicationDetails = initialReplicationDetails; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the selected recovery azure network Id. + * + * @return the selectedRecoveryAzureNetworkId value + */ + public String selectedRecoveryAzureNetworkId() { + return this.selectedRecoveryAzureNetworkId; + } + + /** + * Set the selected recovery azure network Id. + * + * @param selectedRecoveryAzureNetworkId the selectedRecoveryAzureNetworkId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withSelectedRecoveryAzureNetworkId(String selectedRecoveryAzureNetworkId) { + this.selectedRecoveryAzureNetworkId = selectedRecoveryAzureNetworkId; + return this; + } + + /** + * Get the selected source nic Id which will be used as the primary nic during failover. + * + * @return the selectedSourceNicId value + */ + public String selectedSourceNicId() { + return this.selectedSourceNicId; + } + + /** + * Set the selected source nic Id which will be used as the primary nic during failover. + * + * @param selectedSourceNicId the selectedSourceNicId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withSelectedSourceNicId(String selectedSourceNicId) { + this.selectedSourceNicId = selectedSourceNicId; + return this; + } + + /** + * Get the encryption info. + * + * @return the encryption value + */ + public String encryption() { + return this.encryption; + } + + /** + * Set the encryption info. + * + * @param encryption the encryption value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withEncryption(String encryption) { + this.encryption = encryption; + return this; + } + + /** + * Get the operating system info. + * + * @return the oSDetails value + */ + public OSDetails oSDetails() { + return this.oSDetails; + } + + /** + * Set the operating system info. + * + * @param oSDetails the oSDetails value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withOSDetails(OSDetails oSDetails) { + this.oSDetails = oSDetails; + return this; + } + + /** + * Get the RAM size of the VM on the primary side. + * + * @return the sourceVmRamSizeInMB value + */ + public Integer sourceVmRamSizeInMB() { + return this.sourceVmRamSizeInMB; + } + + /** + * Set the RAM size of the VM on the primary side. + * + * @param sourceVmRamSizeInMB the sourceVmRamSizeInMB value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withSourceVmRamSizeInMB(Integer sourceVmRamSizeInMB) { + this.sourceVmRamSizeInMB = sourceVmRamSizeInMB; + return this; + } + + /** + * Get the CPU count of the VM on the primary side. + * + * @return the sourceVmCpuCount value + */ + public Integer sourceVmCpuCount() { + return this.sourceVmCpuCount; + } + + /** + * Set the CPU count of the VM on the primary side. + * + * @param sourceVmCpuCount the sourceVmCpuCount value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withSourceVmCpuCount(Integer sourceVmCpuCount) { + this.sourceVmCpuCount = sourceVmCpuCount; + return this; + } + + /** + * Get the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @return the enableRdpOnTargetOption value + */ + public String enableRdpOnTargetOption() { + return this.enableRdpOnTargetOption; + } + + /** + * Set the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @param enableRdpOnTargetOption the enableRdpOnTargetOption value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withEnableRdpOnTargetOption(String enableRdpOnTargetOption) { + this.enableRdpOnTargetOption = enableRdpOnTargetOption; + return this; + } + + /** + * Get the target resource group Id. + * + * @return the recoveryAzureResourceGroupId value + */ + public String recoveryAzureResourceGroupId() { + return this.recoveryAzureResourceGroupId; + } + + /** + * Set the target resource group Id. + * + * @param recoveryAzureResourceGroupId the recoveryAzureResourceGroupId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAzureResourceGroupId(String recoveryAzureResourceGroupId) { + this.recoveryAzureResourceGroupId = recoveryAzureResourceGroupId; + return this; + } + + /** + * Get the recovery availability set Id. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the recovery availability set Id. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + + /** + * Get license Type of the VM to be used. + * + * @return the licenseType value + */ + public String licenseType() { + return this.licenseType; + } + + /** + * Set license Type of the VM to be used. + * + * @param licenseType the licenseType value to set + * @return the HyperVReplicaAzureReplicationDetails object itself. + */ + public HyperVReplicaAzureReplicationDetails withLicenseType(String licenseType) { + this.licenseType = licenseType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReprotectInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReprotectInput.java new file mode 100644 index 0000000000000..cb888b7f5f44f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureReprotectInput.java @@ -0,0 +1,177 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Azure specific reprotect input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureReprotectInput extends ReverseReplicationProviderSpecificInput { + /** + * The Hyper-V host Vm Id. + */ + @JsonProperty(value = "hvHostVmId") + private String hvHostVmId; + + /** + * The Vm Name. + */ + @JsonProperty(value = "vmName") + private String vmName; + + /** + * The OS type associated with vm. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The OS disk VHD id associated with vm. + */ + @JsonProperty(value = "vHDId") + private String vHDId; + + /** + * The storage account name. + */ + @JsonProperty(value = "storageAccountId") + private String storageAccountId; + + /** + * The storage account to be used for logging during replication. + */ + @JsonProperty(value = "logStorageAccountId") + private String logStorageAccountId; + + /** + * Get the Hyper-V host Vm Id. + * + * @return the hvHostVmId value + */ + public String hvHostVmId() { + return this.hvHostVmId; + } + + /** + * Set the Hyper-V host Vm Id. + * + * @param hvHostVmId the hvHostVmId value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withHvHostVmId(String hvHostVmId) { + this.hvHostVmId = hvHostVmId; + return this; + } + + /** + * Get the Vm Name. + * + * @return the vmName value + */ + public String vmName() { + return this.vmName; + } + + /** + * Set the Vm Name. + * + * @param vmName the vmName value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withVmName(String vmName) { + this.vmName = vmName; + return this; + } + + /** + * Get the OS type associated with vm. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type associated with vm. + * + * @param osType the osType value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the OS disk VHD id associated with vm. + * + * @return the vHDId value + */ + public String vHDId() { + return this.vHDId; + } + + /** + * Set the OS disk VHD id associated with vm. + * + * @param vHDId the vHDId value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withVHDId(String vHDId) { + this.vHDId = vHDId; + return this; + } + + /** + * Get the storage account name. + * + * @return the storageAccountId value + */ + public String storageAccountId() { + return this.storageAccountId; + } + + /** + * Set the storage account name. + * + * @param storageAccountId the storageAccountId value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withStorageAccountId(String storageAccountId) { + this.storageAccountId = storageAccountId; + return this; + } + + /** + * Get the storage account to be used for logging during replication. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Set the storage account to be used for logging during replication. + * + * @param logStorageAccountId the logStorageAccountId value to set + * @return the HyperVReplicaAzureReprotectInput object itself. + */ + public HyperVReplicaAzureReprotectInput withLogStorageAccountId(String logStorageAccountId) { + this.logStorageAccountId = logStorageAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureRpRecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureRpRecoveryPointType.java new file mode 100644 index 0000000000000..dfeb6ed3d1972 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureRpRecoveryPointType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for HyperVReplicaAzureRpRecoveryPointType. + */ +public final class HyperVReplicaAzureRpRecoveryPointType extends ExpandableStringEnum { + /** Static value Latest for HyperVReplicaAzureRpRecoveryPointType. */ + public static final HyperVReplicaAzureRpRecoveryPointType LATEST = fromString("Latest"); + + /** Static value LatestApplicationConsistent for HyperVReplicaAzureRpRecoveryPointType. */ + public static final HyperVReplicaAzureRpRecoveryPointType LATEST_APPLICATION_CONSISTENT = fromString("LatestApplicationConsistent"); + + /** Static value LatestProcessed for HyperVReplicaAzureRpRecoveryPointType. */ + public static final HyperVReplicaAzureRpRecoveryPointType LATEST_PROCESSED = fromString("LatestProcessed"); + + /** + * Creates or finds a HyperVReplicaAzureRpRecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding HyperVReplicaAzureRpRecoveryPointType + */ + @JsonCreator + public static HyperVReplicaAzureRpRecoveryPointType fromString(String name) { + return fromString(name, HyperVReplicaAzureRpRecoveryPointType.class); + } + + /** + * @return known HyperVReplicaAzureRpRecoveryPointType values + */ + public static Collection values() { + return values(HyperVReplicaAzureRpRecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureUpdateReplicationProtectedItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureUpdateReplicationProtectedItemInput.java new file mode 100644 index 0000000000000..ee3295d99a74c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaAzureUpdateReplicationProtectedItemInput.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HyperV replica Azure input to update replication protected item. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class HyperVReplicaAzureUpdateReplicationProtectedItemInput extends UpdateReplicationProtectedItemProviderInput { + /** + * The recovery Azure resource group Id for classic deployment. + */ + @JsonProperty(value = "recoveryAzureV1ResourceGroupId") + private String recoveryAzureV1ResourceGroupId; + + /** + * The recovery Azure resource group Id for resource manager deployment. + */ + @JsonProperty(value = "recoveryAzureV2ResourceGroupId") + private String recoveryAzureV2ResourceGroupId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * Get the recovery Azure resource group Id for classic deployment. + * + * @return the recoveryAzureV1ResourceGroupId value + */ + public String recoveryAzureV1ResourceGroupId() { + return this.recoveryAzureV1ResourceGroupId; + } + + /** + * Set the recovery Azure resource group Id for classic deployment. + * + * @param recoveryAzureV1ResourceGroupId the recoveryAzureV1ResourceGroupId value to set + * @return the HyperVReplicaAzureUpdateReplicationProtectedItemInput object itself. + */ + public HyperVReplicaAzureUpdateReplicationProtectedItemInput withRecoveryAzureV1ResourceGroupId(String recoveryAzureV1ResourceGroupId) { + this.recoveryAzureV1ResourceGroupId = recoveryAzureV1ResourceGroupId; + return this; + } + + /** + * Get the recovery Azure resource group Id for resource manager deployment. + * + * @return the recoveryAzureV2ResourceGroupId value + */ + public String recoveryAzureV2ResourceGroupId() { + return this.recoveryAzureV2ResourceGroupId; + } + + /** + * Set the recovery Azure resource group Id for resource manager deployment. + * + * @param recoveryAzureV2ResourceGroupId the recoveryAzureV2ResourceGroupId value to set + * @return the HyperVReplicaAzureUpdateReplicationProtectedItemInput object itself. + */ + public HyperVReplicaAzureUpdateReplicationProtectedItemInput withRecoveryAzureV2ResourceGroupId(String recoveryAzureV2ResourceGroupId) { + this.recoveryAzureV2ResourceGroupId = recoveryAzureV2ResourceGroupId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the HyperVReplicaAzureUpdateReplicationProtectedItemInput object itself. + */ + public HyperVReplicaAzureUpdateReplicationProtectedItemInput withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseEventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseEventDetails.java new file mode 100644 index 0000000000000..200f5903d6cb7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseEventDetails.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Abstract model class for event details of a HyperVReplica E2E event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaBaseEventDetails") +public class HyperVReplicaBaseEventDetails extends EventProviderSpecificDetails { + /** + * The container friendly name. + */ + @JsonProperty(value = "containerName") + private String containerName; + + /** + * The fabric friendly name. + */ + @JsonProperty(value = "fabricName") + private String fabricName; + + /** + * The remote container name. + */ + @JsonProperty(value = "remoteContainerName") + private String remoteContainerName; + + /** + * The remote fabric name. + */ + @JsonProperty(value = "remoteFabricName") + private String remoteFabricName; + + /** + * Get the container friendly name. + * + * @return the containerName value + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the container friendly name. + * + * @param containerName the containerName value to set + * @return the HyperVReplicaBaseEventDetails object itself. + */ + public HyperVReplicaBaseEventDetails withContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the fabric friendly name. + * + * @return the fabricName value + */ + public String fabricName() { + return this.fabricName; + } + + /** + * Set the fabric friendly name. + * + * @param fabricName the fabricName value to set + * @return the HyperVReplicaBaseEventDetails object itself. + */ + public HyperVReplicaBaseEventDetails withFabricName(String fabricName) { + this.fabricName = fabricName; + return this; + } + + /** + * Get the remote container name. + * + * @return the remoteContainerName value + */ + public String remoteContainerName() { + return this.remoteContainerName; + } + + /** + * Set the remote container name. + * + * @param remoteContainerName the remoteContainerName value to set + * @return the HyperVReplicaBaseEventDetails object itself. + */ + public HyperVReplicaBaseEventDetails withRemoteContainerName(String remoteContainerName) { + this.remoteContainerName = remoteContainerName; + return this; + } + + /** + * Get the remote fabric name. + * + * @return the remoteFabricName value + */ + public String remoteFabricName() { + return this.remoteFabricName; + } + + /** + * Set the remote fabric name. + * + * @param remoteFabricName the remoteFabricName value to set + * @return the HyperVReplicaBaseEventDetails object itself. + */ + public HyperVReplicaBaseEventDetails withRemoteFabricName(String remoteFabricName) { + this.remoteFabricName = remoteFabricName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBasePolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBasePolicyDetails.java new file mode 100644 index 0000000000000..2828de2490601 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBasePolicyDetails.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Base class for HyperVReplica policy details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaBasePolicyDetails") +public class HyperVReplicaBasePolicyDetails extends PolicyProviderSpecificDetails { + /** + * A value indicating the number of recovery points. + */ + @JsonProperty(value = "recoveryPoints") + private Integer recoveryPoints; + + /** + * A value indicating the application consistent frequency. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * A value indicating whether compression has to be enabled. + */ + @JsonProperty(value = "compression") + private String compression; + + /** + * A value indicating whether IR is online. + */ + @JsonProperty(value = "initialReplicationMethod") + private String initialReplicationMethod; + + /** + * A value indicating the online IR start time. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating the offline IR import path. + */ + @JsonProperty(value = "offlineReplicationImportPath") + private String offlineReplicationImportPath; + + /** + * A value indicating the offline IR export path. + */ + @JsonProperty(value = "offlineReplicationExportPath") + private String offlineReplicationExportPath; + + /** + * A value indicating the recovery HTTPS port. + */ + @JsonProperty(value = "replicationPort") + private Integer replicationPort; + + /** + * A value indicating the authentication type. + */ + @JsonProperty(value = "allowedAuthenticationType") + private Integer allowedAuthenticationType; + + /** + * A value indicating whether the VM has to be auto deleted. Supported + * Values: String.Empty, None, OnRecoveryCloud. + */ + @JsonProperty(value = "replicaDeletionOption") + private String replicaDeletionOption; + + /** + * Get a value indicating the number of recovery points. + * + * @return the recoveryPoints value + */ + public Integer recoveryPoints() { + return this.recoveryPoints; + } + + /** + * Set a value indicating the number of recovery points. + * + * @param recoveryPoints the recoveryPoints value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withRecoveryPoints(Integer recoveryPoints) { + this.recoveryPoints = recoveryPoints; + return this; + } + + /** + * Get a value indicating the application consistent frequency. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set a value indicating the application consistent frequency. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get a value indicating whether compression has to be enabled. + * + * @return the compression value + */ + public String compression() { + return this.compression; + } + + /** + * Set a value indicating whether compression has to be enabled. + * + * @param compression the compression value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withCompression(String compression) { + this.compression = compression; + return this; + } + + /** + * Get a value indicating whether IR is online. + * + * @return the initialReplicationMethod value + */ + public String initialReplicationMethod() { + return this.initialReplicationMethod; + } + + /** + * Set a value indicating whether IR is online. + * + * @param initialReplicationMethod the initialReplicationMethod value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withInitialReplicationMethod(String initialReplicationMethod) { + this.initialReplicationMethod = initialReplicationMethod; + return this; + } + + /** + * Get a value indicating the online IR start time. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set a value indicating the online IR start time. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating the offline IR import path. + * + * @return the offlineReplicationImportPath value + */ + public String offlineReplicationImportPath() { + return this.offlineReplicationImportPath; + } + + /** + * Set a value indicating the offline IR import path. + * + * @param offlineReplicationImportPath the offlineReplicationImportPath value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withOfflineReplicationImportPath(String offlineReplicationImportPath) { + this.offlineReplicationImportPath = offlineReplicationImportPath; + return this; + } + + /** + * Get a value indicating the offline IR export path. + * + * @return the offlineReplicationExportPath value + */ + public String offlineReplicationExportPath() { + return this.offlineReplicationExportPath; + } + + /** + * Set a value indicating the offline IR export path. + * + * @param offlineReplicationExportPath the offlineReplicationExportPath value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withOfflineReplicationExportPath(String offlineReplicationExportPath) { + this.offlineReplicationExportPath = offlineReplicationExportPath; + return this; + } + + /** + * Get a value indicating the recovery HTTPS port. + * + * @return the replicationPort value + */ + public Integer replicationPort() { + return this.replicationPort; + } + + /** + * Set a value indicating the recovery HTTPS port. + * + * @param replicationPort the replicationPort value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withReplicationPort(Integer replicationPort) { + this.replicationPort = replicationPort; + return this; + } + + /** + * Get a value indicating the authentication type. + * + * @return the allowedAuthenticationType value + */ + public Integer allowedAuthenticationType() { + return this.allowedAuthenticationType; + } + + /** + * Set a value indicating the authentication type. + * + * @param allowedAuthenticationType the allowedAuthenticationType value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withAllowedAuthenticationType(Integer allowedAuthenticationType) { + this.allowedAuthenticationType = allowedAuthenticationType; + return this; + } + + /** + * Get a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @return the replicaDeletionOption value + */ + public String replicaDeletionOption() { + return this.replicaDeletionOption; + } + + /** + * Set a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @param replicaDeletionOption the replicaDeletionOption value to set + * @return the HyperVReplicaBasePolicyDetails object itself. + */ + public HyperVReplicaBasePolicyDetails withReplicaDeletionOption(String replicaDeletionOption) { + this.replicaDeletionOption = replicaDeletionOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseReplicationDetails.java new file mode 100644 index 0000000000000..b80d066a6719d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBaseReplicationDetails.java @@ -0,0 +1,205 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper V replica provider specific settings base class. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaBaseReplicationDetails") +public class HyperVReplicaBaseReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The Last replication time. + */ + @JsonProperty(value = "lastReplicatedTime") + private DateTime lastReplicatedTime; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * Initial replication details. + */ + @JsonProperty(value = "initialReplicationDetails") + private InitialReplicationDetails initialReplicationDetails; + + /** + * VM disk details. + */ + @JsonProperty(value = "vMDiskDetails") + private List vMDiskDetails; + + /** + * Get the Last replication time. + * + * @return the lastReplicatedTime value + */ + public DateTime lastReplicatedTime() { + return this.lastReplicatedTime; + } + + /** + * Set the Last replication time. + * + * @param lastReplicatedTime the lastReplicatedTime value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withLastReplicatedTime(DateTime lastReplicatedTime) { + this.lastReplicatedTime = lastReplicatedTime; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get initial replication details. + * + * @return the initialReplicationDetails value + */ + public InitialReplicationDetails initialReplicationDetails() { + return this.initialReplicationDetails; + } + + /** + * Set initial replication details. + * + * @param initialReplicationDetails the initialReplicationDetails value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withInitialReplicationDetails(InitialReplicationDetails initialReplicationDetails) { + this.initialReplicationDetails = initialReplicationDetails; + return this; + } + + /** + * Get vM disk details. + * + * @return the vMDiskDetails value + */ + public List vMDiskDetails() { + return this.vMDiskDetails; + } + + /** + * Set vM disk details. + * + * @param vMDiskDetails the vMDiskDetails value to set + * @return the HyperVReplicaBaseReplicationDetails object itself. + */ + public HyperVReplicaBaseReplicationDetails withVMDiskDetails(List vMDiskDetails) { + this.vMDiskDetails = vMDiskDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyDetails.java new file mode 100644 index 0000000000000..15b8b1fdfd6a3 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyDetails.java @@ -0,0 +1,308 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper-V Replica Blue specific protection profile details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012R2") +public class HyperVReplicaBluePolicyDetails extends PolicyProviderSpecificDetails { + /** + * A value indicating the replication interval. + */ + @JsonProperty(value = "replicationFrequencyInSeconds") + private Integer replicationFrequencyInSeconds; + + /** + * A value indicating the number of recovery points. + */ + @JsonProperty(value = "recoveryPoints") + private Integer recoveryPoints; + + /** + * A value indicating the application consistent frequency. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * A value indicating whether compression has to be enabled. + */ + @JsonProperty(value = "compression") + private String compression; + + /** + * A value indicating whether IR is online. + */ + @JsonProperty(value = "initialReplicationMethod") + private String initialReplicationMethod; + + /** + * A value indicating the online IR start time. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating the offline IR import path. + */ + @JsonProperty(value = "offlineReplicationImportPath") + private String offlineReplicationImportPath; + + /** + * A value indicating the offline IR export path. + */ + @JsonProperty(value = "offlineReplicationExportPath") + private String offlineReplicationExportPath; + + /** + * A value indicating the recovery HTTPS port. + */ + @JsonProperty(value = "replicationPort") + private Integer replicationPort; + + /** + * A value indicating the authentication type. + */ + @JsonProperty(value = "allowedAuthenticationType") + private Integer allowedAuthenticationType; + + /** + * A value indicating whether the VM has to be auto deleted. Supported + * Values: String.Empty, None, OnRecoveryCloud. + */ + @JsonProperty(value = "replicaDeletionOption") + private String replicaDeletionOption; + + /** + * Get a value indicating the replication interval. + * + * @return the replicationFrequencyInSeconds value + */ + public Integer replicationFrequencyInSeconds() { + return this.replicationFrequencyInSeconds; + } + + /** + * Set a value indicating the replication interval. + * + * @param replicationFrequencyInSeconds the replicationFrequencyInSeconds value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withReplicationFrequencyInSeconds(Integer replicationFrequencyInSeconds) { + this.replicationFrequencyInSeconds = replicationFrequencyInSeconds; + return this; + } + + /** + * Get a value indicating the number of recovery points. + * + * @return the recoveryPoints value + */ + public Integer recoveryPoints() { + return this.recoveryPoints; + } + + /** + * Set a value indicating the number of recovery points. + * + * @param recoveryPoints the recoveryPoints value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withRecoveryPoints(Integer recoveryPoints) { + this.recoveryPoints = recoveryPoints; + return this; + } + + /** + * Get a value indicating the application consistent frequency. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set a value indicating the application consistent frequency. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get a value indicating whether compression has to be enabled. + * + * @return the compression value + */ + public String compression() { + return this.compression; + } + + /** + * Set a value indicating whether compression has to be enabled. + * + * @param compression the compression value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withCompression(String compression) { + this.compression = compression; + return this; + } + + /** + * Get a value indicating whether IR is online. + * + * @return the initialReplicationMethod value + */ + public String initialReplicationMethod() { + return this.initialReplicationMethod; + } + + /** + * Set a value indicating whether IR is online. + * + * @param initialReplicationMethod the initialReplicationMethod value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withInitialReplicationMethod(String initialReplicationMethod) { + this.initialReplicationMethod = initialReplicationMethod; + return this; + } + + /** + * Get a value indicating the online IR start time. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set a value indicating the online IR start time. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating the offline IR import path. + * + * @return the offlineReplicationImportPath value + */ + public String offlineReplicationImportPath() { + return this.offlineReplicationImportPath; + } + + /** + * Set a value indicating the offline IR import path. + * + * @param offlineReplicationImportPath the offlineReplicationImportPath value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withOfflineReplicationImportPath(String offlineReplicationImportPath) { + this.offlineReplicationImportPath = offlineReplicationImportPath; + return this; + } + + /** + * Get a value indicating the offline IR export path. + * + * @return the offlineReplicationExportPath value + */ + public String offlineReplicationExportPath() { + return this.offlineReplicationExportPath; + } + + /** + * Set a value indicating the offline IR export path. + * + * @param offlineReplicationExportPath the offlineReplicationExportPath value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withOfflineReplicationExportPath(String offlineReplicationExportPath) { + this.offlineReplicationExportPath = offlineReplicationExportPath; + return this; + } + + /** + * Get a value indicating the recovery HTTPS port. + * + * @return the replicationPort value + */ + public Integer replicationPort() { + return this.replicationPort; + } + + /** + * Set a value indicating the recovery HTTPS port. + * + * @param replicationPort the replicationPort value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withReplicationPort(Integer replicationPort) { + this.replicationPort = replicationPort; + return this; + } + + /** + * Get a value indicating the authentication type. + * + * @return the allowedAuthenticationType value + */ + public Integer allowedAuthenticationType() { + return this.allowedAuthenticationType; + } + + /** + * Set a value indicating the authentication type. + * + * @param allowedAuthenticationType the allowedAuthenticationType value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withAllowedAuthenticationType(Integer allowedAuthenticationType) { + this.allowedAuthenticationType = allowedAuthenticationType; + return this; + } + + /** + * Get a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @return the replicaDeletionOption value + */ + public String replicaDeletionOption() { + return this.replicaDeletionOption; + } + + /** + * Set a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @param replicaDeletionOption the replicaDeletionOption value to set + * @return the HyperVReplicaBluePolicyDetails object itself. + */ + public HyperVReplicaBluePolicyDetails withReplicaDeletionOption(String replicaDeletionOption) { + this.replicaDeletionOption = replicaDeletionOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyInput.java new file mode 100644 index 0000000000000..f491978500bc7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBluePolicyInput.java @@ -0,0 +1,307 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HyperV Replica Blue policy input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012R2") +public class HyperVReplicaBluePolicyInput extends PolicyProviderSpecificInput { + /** + * A value indicating the replication interval. + */ + @JsonProperty(value = "replicationFrequencyInSeconds") + private Integer replicationFrequencyInSeconds; + + /** + * A value indicating the number of recovery points. + */ + @JsonProperty(value = "recoveryPoints") + private Integer recoveryPoints; + + /** + * A value indicating the application consistent frequency. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * A value indicating whether compression has to be enabled. + */ + @JsonProperty(value = "compression") + private String compression; + + /** + * A value indicating whether IR is online. + */ + @JsonProperty(value = "initialReplicationMethod") + private String initialReplicationMethod; + + /** + * A value indicating the online IR start time. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating the offline IR import path. + */ + @JsonProperty(value = "offlineReplicationImportPath") + private String offlineReplicationImportPath; + + /** + * A value indicating the offline IR export path. + */ + @JsonProperty(value = "offlineReplicationExportPath") + private String offlineReplicationExportPath; + + /** + * A value indicating the recovery HTTPS port. + */ + @JsonProperty(value = "replicationPort") + private Integer replicationPort; + + /** + * A value indicating the authentication type. + */ + @JsonProperty(value = "allowedAuthenticationType") + private Integer allowedAuthenticationType; + + /** + * A value indicating whether the VM has to be auto deleted. + */ + @JsonProperty(value = "replicaDeletion") + private String replicaDeletion; + + /** + * Get a value indicating the replication interval. + * + * @return the replicationFrequencyInSeconds value + */ + public Integer replicationFrequencyInSeconds() { + return this.replicationFrequencyInSeconds; + } + + /** + * Set a value indicating the replication interval. + * + * @param replicationFrequencyInSeconds the replicationFrequencyInSeconds value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withReplicationFrequencyInSeconds(Integer replicationFrequencyInSeconds) { + this.replicationFrequencyInSeconds = replicationFrequencyInSeconds; + return this; + } + + /** + * Get a value indicating the number of recovery points. + * + * @return the recoveryPoints value + */ + public Integer recoveryPoints() { + return this.recoveryPoints; + } + + /** + * Set a value indicating the number of recovery points. + * + * @param recoveryPoints the recoveryPoints value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withRecoveryPoints(Integer recoveryPoints) { + this.recoveryPoints = recoveryPoints; + return this; + } + + /** + * Get a value indicating the application consistent frequency. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set a value indicating the application consistent frequency. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get a value indicating whether compression has to be enabled. + * + * @return the compression value + */ + public String compression() { + return this.compression; + } + + /** + * Set a value indicating whether compression has to be enabled. + * + * @param compression the compression value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withCompression(String compression) { + this.compression = compression; + return this; + } + + /** + * Get a value indicating whether IR is online. + * + * @return the initialReplicationMethod value + */ + public String initialReplicationMethod() { + return this.initialReplicationMethod; + } + + /** + * Set a value indicating whether IR is online. + * + * @param initialReplicationMethod the initialReplicationMethod value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withInitialReplicationMethod(String initialReplicationMethod) { + this.initialReplicationMethod = initialReplicationMethod; + return this; + } + + /** + * Get a value indicating the online IR start time. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set a value indicating the online IR start time. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating the offline IR import path. + * + * @return the offlineReplicationImportPath value + */ + public String offlineReplicationImportPath() { + return this.offlineReplicationImportPath; + } + + /** + * Set a value indicating the offline IR import path. + * + * @param offlineReplicationImportPath the offlineReplicationImportPath value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withOfflineReplicationImportPath(String offlineReplicationImportPath) { + this.offlineReplicationImportPath = offlineReplicationImportPath; + return this; + } + + /** + * Get a value indicating the offline IR export path. + * + * @return the offlineReplicationExportPath value + */ + public String offlineReplicationExportPath() { + return this.offlineReplicationExportPath; + } + + /** + * Set a value indicating the offline IR export path. + * + * @param offlineReplicationExportPath the offlineReplicationExportPath value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withOfflineReplicationExportPath(String offlineReplicationExportPath) { + this.offlineReplicationExportPath = offlineReplicationExportPath; + return this; + } + + /** + * Get a value indicating the recovery HTTPS port. + * + * @return the replicationPort value + */ + public Integer replicationPort() { + return this.replicationPort; + } + + /** + * Set a value indicating the recovery HTTPS port. + * + * @param replicationPort the replicationPort value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withReplicationPort(Integer replicationPort) { + this.replicationPort = replicationPort; + return this; + } + + /** + * Get a value indicating the authentication type. + * + * @return the allowedAuthenticationType value + */ + public Integer allowedAuthenticationType() { + return this.allowedAuthenticationType; + } + + /** + * Set a value indicating the authentication type. + * + * @param allowedAuthenticationType the allowedAuthenticationType value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withAllowedAuthenticationType(Integer allowedAuthenticationType) { + this.allowedAuthenticationType = allowedAuthenticationType; + return this; + } + + /** + * Get a value indicating whether the VM has to be auto deleted. + * + * @return the replicaDeletion value + */ + public String replicaDeletion() { + return this.replicaDeletion; + } + + /** + * Set a value indicating whether the VM has to be auto deleted. + * + * @param replicaDeletion the replicaDeletion value to set + * @return the HyperVReplicaBluePolicyInput object itself. + */ + public HyperVReplicaBluePolicyInput withReplicaDeletion(String replicaDeletion) { + this.replicaDeletion = replicaDeletion; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBlueReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBlueReplicationDetails.java new file mode 100644 index 0000000000000..5fffe1e8f72f2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaBlueReplicationDetails.java @@ -0,0 +1,205 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HyperV replica 2012 R2 (Blue) replication details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012R2") +public class HyperVReplicaBlueReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The Last replication time. + */ + @JsonProperty(value = "lastReplicatedTime") + private DateTime lastReplicatedTime; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * Initial replication details. + */ + @JsonProperty(value = "initialReplicationDetails") + private InitialReplicationDetails initialReplicationDetails; + + /** + * VM disk details. + */ + @JsonProperty(value = "vMDiskDetails") + private List vMDiskDetails; + + /** + * Get the Last replication time. + * + * @return the lastReplicatedTime value + */ + public DateTime lastReplicatedTime() { + return this.lastReplicatedTime; + } + + /** + * Set the Last replication time. + * + * @param lastReplicatedTime the lastReplicatedTime value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withLastReplicatedTime(DateTime lastReplicatedTime) { + this.lastReplicatedTime = lastReplicatedTime; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get initial replication details. + * + * @return the initialReplicationDetails value + */ + public InitialReplicationDetails initialReplicationDetails() { + return this.initialReplicationDetails; + } + + /** + * Set initial replication details. + * + * @param initialReplicationDetails the initialReplicationDetails value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withInitialReplicationDetails(InitialReplicationDetails initialReplicationDetails) { + this.initialReplicationDetails = initialReplicationDetails; + return this; + } + + /** + * Get vM disk details. + * + * @return the vMDiskDetails value + */ + public List vMDiskDetails() { + return this.vMDiskDetails; + } + + /** + * Set vM disk details. + * + * @param vMDiskDetails the vMDiskDetails value to set + * @return the HyperVReplicaBlueReplicationDetails object itself. + */ + public HyperVReplicaBlueReplicationDetails withVMDiskDetails(List vMDiskDetails) { + this.vMDiskDetails = vMDiskDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyDetails.java new file mode 100644 index 0000000000000..d9d1ac89b63d1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyDetails.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper-V Replica Blue specific protection profile details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012") +public class HyperVReplicaPolicyDetails extends PolicyProviderSpecificDetails { + /** + * A value indicating the number of recovery points. + */ + @JsonProperty(value = "recoveryPoints") + private Integer recoveryPoints; + + /** + * A value indicating the application consistent frequency. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * A value indicating whether compression has to be enabled. + */ + @JsonProperty(value = "compression") + private String compression; + + /** + * A value indicating whether IR is online. + */ + @JsonProperty(value = "initialReplicationMethod") + private String initialReplicationMethod; + + /** + * A value indicating the online IR start time. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating the offline IR import path. + */ + @JsonProperty(value = "offlineReplicationImportPath") + private String offlineReplicationImportPath; + + /** + * A value indicating the offline IR export path. + */ + @JsonProperty(value = "offlineReplicationExportPath") + private String offlineReplicationExportPath; + + /** + * A value indicating the recovery HTTPS port. + */ + @JsonProperty(value = "replicationPort") + private Integer replicationPort; + + /** + * A value indicating the authentication type. + */ + @JsonProperty(value = "allowedAuthenticationType") + private Integer allowedAuthenticationType; + + /** + * A value indicating whether the VM has to be auto deleted. Supported + * Values: String.Empty, None, OnRecoveryCloud. + */ + @JsonProperty(value = "replicaDeletionOption") + private String replicaDeletionOption; + + /** + * Get a value indicating the number of recovery points. + * + * @return the recoveryPoints value + */ + public Integer recoveryPoints() { + return this.recoveryPoints; + } + + /** + * Set a value indicating the number of recovery points. + * + * @param recoveryPoints the recoveryPoints value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withRecoveryPoints(Integer recoveryPoints) { + this.recoveryPoints = recoveryPoints; + return this; + } + + /** + * Get a value indicating the application consistent frequency. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set a value indicating the application consistent frequency. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get a value indicating whether compression has to be enabled. + * + * @return the compression value + */ + public String compression() { + return this.compression; + } + + /** + * Set a value indicating whether compression has to be enabled. + * + * @param compression the compression value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withCompression(String compression) { + this.compression = compression; + return this; + } + + /** + * Get a value indicating whether IR is online. + * + * @return the initialReplicationMethod value + */ + public String initialReplicationMethod() { + return this.initialReplicationMethod; + } + + /** + * Set a value indicating whether IR is online. + * + * @param initialReplicationMethod the initialReplicationMethod value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withInitialReplicationMethod(String initialReplicationMethod) { + this.initialReplicationMethod = initialReplicationMethod; + return this; + } + + /** + * Get a value indicating the online IR start time. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set a value indicating the online IR start time. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating the offline IR import path. + * + * @return the offlineReplicationImportPath value + */ + public String offlineReplicationImportPath() { + return this.offlineReplicationImportPath; + } + + /** + * Set a value indicating the offline IR import path. + * + * @param offlineReplicationImportPath the offlineReplicationImportPath value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withOfflineReplicationImportPath(String offlineReplicationImportPath) { + this.offlineReplicationImportPath = offlineReplicationImportPath; + return this; + } + + /** + * Get a value indicating the offline IR export path. + * + * @return the offlineReplicationExportPath value + */ + public String offlineReplicationExportPath() { + return this.offlineReplicationExportPath; + } + + /** + * Set a value indicating the offline IR export path. + * + * @param offlineReplicationExportPath the offlineReplicationExportPath value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withOfflineReplicationExportPath(String offlineReplicationExportPath) { + this.offlineReplicationExportPath = offlineReplicationExportPath; + return this; + } + + /** + * Get a value indicating the recovery HTTPS port. + * + * @return the replicationPort value + */ + public Integer replicationPort() { + return this.replicationPort; + } + + /** + * Set a value indicating the recovery HTTPS port. + * + * @param replicationPort the replicationPort value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withReplicationPort(Integer replicationPort) { + this.replicationPort = replicationPort; + return this; + } + + /** + * Get a value indicating the authentication type. + * + * @return the allowedAuthenticationType value + */ + public Integer allowedAuthenticationType() { + return this.allowedAuthenticationType; + } + + /** + * Set a value indicating the authentication type. + * + * @param allowedAuthenticationType the allowedAuthenticationType value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withAllowedAuthenticationType(Integer allowedAuthenticationType) { + this.allowedAuthenticationType = allowedAuthenticationType; + return this; + } + + /** + * Get a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @return the replicaDeletionOption value + */ + public String replicaDeletionOption() { + return this.replicaDeletionOption; + } + + /** + * Set a value indicating whether the VM has to be auto deleted. Supported Values: String.Empty, None, OnRecoveryCloud. + * + * @param replicaDeletionOption the replicaDeletionOption value to set + * @return the HyperVReplicaPolicyDetails object itself. + */ + public HyperVReplicaPolicyDetails withReplicaDeletionOption(String replicaDeletionOption) { + this.replicaDeletionOption = replicaDeletionOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyInput.java new file mode 100644 index 0000000000000..ac7392e97786c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaPolicyInput.java @@ -0,0 +1,281 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Hyper-V Replica specific policy Input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012") +public class HyperVReplicaPolicyInput extends PolicyProviderSpecificInput { + /** + * A value indicating the number of recovery points. + */ + @JsonProperty(value = "recoveryPoints") + private Integer recoveryPoints; + + /** + * A value indicating the application consistent frequency. + */ + @JsonProperty(value = "applicationConsistentSnapshotFrequencyInHours") + private Integer applicationConsistentSnapshotFrequencyInHours; + + /** + * A value indicating whether compression has to be enabled. + */ + @JsonProperty(value = "compression") + private String compression; + + /** + * A value indicating whether IR is online. + */ + @JsonProperty(value = "initialReplicationMethod") + private String initialReplicationMethod; + + /** + * A value indicating the online IR start time. + */ + @JsonProperty(value = "onlineReplicationStartTime") + private String onlineReplicationStartTime; + + /** + * A value indicating the offline IR import path. + */ + @JsonProperty(value = "offlineReplicationImportPath") + private String offlineReplicationImportPath; + + /** + * A value indicating the offline IR export path. + */ + @JsonProperty(value = "offlineReplicationExportPath") + private String offlineReplicationExportPath; + + /** + * A value indicating the recovery HTTPS port. + */ + @JsonProperty(value = "replicationPort") + private Integer replicationPort; + + /** + * A value indicating the authentication type. + */ + @JsonProperty(value = "allowedAuthenticationType") + private Integer allowedAuthenticationType; + + /** + * A value indicating whether the VM has to be auto deleted. + */ + @JsonProperty(value = "replicaDeletion") + private String replicaDeletion; + + /** + * Get a value indicating the number of recovery points. + * + * @return the recoveryPoints value + */ + public Integer recoveryPoints() { + return this.recoveryPoints; + } + + /** + * Set a value indicating the number of recovery points. + * + * @param recoveryPoints the recoveryPoints value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withRecoveryPoints(Integer recoveryPoints) { + this.recoveryPoints = recoveryPoints; + return this; + } + + /** + * Get a value indicating the application consistent frequency. + * + * @return the applicationConsistentSnapshotFrequencyInHours value + */ + public Integer applicationConsistentSnapshotFrequencyInHours() { + return this.applicationConsistentSnapshotFrequencyInHours; + } + + /** + * Set a value indicating the application consistent frequency. + * + * @param applicationConsistentSnapshotFrequencyInHours the applicationConsistentSnapshotFrequencyInHours value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withApplicationConsistentSnapshotFrequencyInHours(Integer applicationConsistentSnapshotFrequencyInHours) { + this.applicationConsistentSnapshotFrequencyInHours = applicationConsistentSnapshotFrequencyInHours; + return this; + } + + /** + * Get a value indicating whether compression has to be enabled. + * + * @return the compression value + */ + public String compression() { + return this.compression; + } + + /** + * Set a value indicating whether compression has to be enabled. + * + * @param compression the compression value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withCompression(String compression) { + this.compression = compression; + return this; + } + + /** + * Get a value indicating whether IR is online. + * + * @return the initialReplicationMethod value + */ + public String initialReplicationMethod() { + return this.initialReplicationMethod; + } + + /** + * Set a value indicating whether IR is online. + * + * @param initialReplicationMethod the initialReplicationMethod value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withInitialReplicationMethod(String initialReplicationMethod) { + this.initialReplicationMethod = initialReplicationMethod; + return this; + } + + /** + * Get a value indicating the online IR start time. + * + * @return the onlineReplicationStartTime value + */ + public String onlineReplicationStartTime() { + return this.onlineReplicationStartTime; + } + + /** + * Set a value indicating the online IR start time. + * + * @param onlineReplicationStartTime the onlineReplicationStartTime value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withOnlineReplicationStartTime(String onlineReplicationStartTime) { + this.onlineReplicationStartTime = onlineReplicationStartTime; + return this; + } + + /** + * Get a value indicating the offline IR import path. + * + * @return the offlineReplicationImportPath value + */ + public String offlineReplicationImportPath() { + return this.offlineReplicationImportPath; + } + + /** + * Set a value indicating the offline IR import path. + * + * @param offlineReplicationImportPath the offlineReplicationImportPath value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withOfflineReplicationImportPath(String offlineReplicationImportPath) { + this.offlineReplicationImportPath = offlineReplicationImportPath; + return this; + } + + /** + * Get a value indicating the offline IR export path. + * + * @return the offlineReplicationExportPath value + */ + public String offlineReplicationExportPath() { + return this.offlineReplicationExportPath; + } + + /** + * Set a value indicating the offline IR export path. + * + * @param offlineReplicationExportPath the offlineReplicationExportPath value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withOfflineReplicationExportPath(String offlineReplicationExportPath) { + this.offlineReplicationExportPath = offlineReplicationExportPath; + return this; + } + + /** + * Get a value indicating the recovery HTTPS port. + * + * @return the replicationPort value + */ + public Integer replicationPort() { + return this.replicationPort; + } + + /** + * Set a value indicating the recovery HTTPS port. + * + * @param replicationPort the replicationPort value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withReplicationPort(Integer replicationPort) { + this.replicationPort = replicationPort; + return this; + } + + /** + * Get a value indicating the authentication type. + * + * @return the allowedAuthenticationType value + */ + public Integer allowedAuthenticationType() { + return this.allowedAuthenticationType; + } + + /** + * Set a value indicating the authentication type. + * + * @param allowedAuthenticationType the allowedAuthenticationType value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withAllowedAuthenticationType(Integer allowedAuthenticationType) { + this.allowedAuthenticationType = allowedAuthenticationType; + return this; + } + + /** + * Get a value indicating whether the VM has to be auto deleted. + * + * @return the replicaDeletion value + */ + public String replicaDeletion() { + return this.replicaDeletion; + } + + /** + * Set a value indicating whether the VM has to be auto deleted. + * + * @param replicaDeletion the replicaDeletion value to set + * @return the HyperVReplicaPolicyInput object itself. + */ + public HyperVReplicaPolicyInput withReplicaDeletion(String replicaDeletion) { + this.replicaDeletion = replicaDeletion; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaReplicationDetails.java new file mode 100644 index 0000000000000..895477982ce20 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVReplicaReplicationDetails.java @@ -0,0 +1,205 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HyperV replica 2012 replication details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplica2012") +public class HyperVReplicaReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The Last replication time. + */ + @JsonProperty(value = "lastReplicatedTime") + private DateTime lastReplicatedTime; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * Initial replication details. + */ + @JsonProperty(value = "initialReplicationDetails") + private InitialReplicationDetails initialReplicationDetails; + + /** + * VM disk details. + */ + @JsonProperty(value = "vMDiskDetails") + private List vMDiskDetails; + + /** + * Get the Last replication time. + * + * @return the lastReplicatedTime value + */ + public DateTime lastReplicatedTime() { + return this.lastReplicatedTime; + } + + /** + * Set the Last replication time. + * + * @param lastReplicatedTime the lastReplicatedTime value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withLastReplicatedTime(DateTime lastReplicatedTime) { + this.lastReplicatedTime = lastReplicatedTime; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get initial replication details. + * + * @return the initialReplicationDetails value + */ + public InitialReplicationDetails initialReplicationDetails() { + return this.initialReplicationDetails; + } + + /** + * Set initial replication details. + * + * @param initialReplicationDetails the initialReplicationDetails value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withInitialReplicationDetails(InitialReplicationDetails initialReplicationDetails) { + this.initialReplicationDetails = initialReplicationDetails; + return this; + } + + /** + * Get vM disk details. + * + * @return the vMDiskDetails value + */ + public List vMDiskDetails() { + return this.vMDiskDetails; + } + + /** + * Set vM disk details. + * + * @param vMDiskDetails the vMDiskDetails value to set + * @return the HyperVReplicaReplicationDetails object itself. + */ + public HyperVReplicaReplicationDetails withVMDiskDetails(List vMDiskDetails) { + this.vMDiskDetails = vMDiskDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVSiteDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVSiteDetails.java new file mode 100644 index 0000000000000..6ddb74e2bea7d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVSiteDetails.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * HyperVSite fabric specific details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVSite") +public class HyperVSiteDetails extends FabricSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVVirtualMachineDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVVirtualMachineDetails.java new file mode 100644 index 0000000000000..cf850f1799c62 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/HyperVVirtualMachineDetails.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Single Host fabric provider specific VM settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVVirtualMachine") +public class HyperVVirtualMachineDetails extends ConfigurationSettings { + /** + * The source id of the object. + */ + @JsonProperty(value = "sourceItemId") + private String sourceItemId; + + /** + * The id of the object in fabric. + */ + @JsonProperty(value = "generation") + private String generation; + + /** + * The Last replication time. + */ + @JsonProperty(value = "osDetails") + private OSDetails osDetails; + + /** + * The Last successful failover time. + */ + @JsonProperty(value = "diskDetails") + private List diskDetails; + + /** + * A value indicating whether the VM has a physical disk attached. String + * value of {SrsDataContract.PresenceStatus} enum. Possible values include: + * 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasPhysicalDisk") + private PresenceStatus hasPhysicalDisk; + + /** + * A value indicating whether the VM has a fibre channel adapter attached. + * String value of {SrsDataContract.PresenceStatus} enum. Possible values + * include: 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasFibreChannelAdapter") + private PresenceStatus hasFibreChannelAdapter; + + /** + * A value indicating whether the VM has a shared VHD attached. String + * value of {SrsDataContract.PresenceStatus} enum. Possible values include: + * 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasSharedVhd") + private PresenceStatus hasSharedVhd; + + /** + * Get the source id of the object. + * + * @return the sourceItemId value + */ + public String sourceItemId() { + return this.sourceItemId; + } + + /** + * Set the source id of the object. + * + * @param sourceItemId the sourceItemId value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withSourceItemId(String sourceItemId) { + this.sourceItemId = sourceItemId; + return this; + } + + /** + * Get the id of the object in fabric. + * + * @return the generation value + */ + public String generation() { + return this.generation; + } + + /** + * Set the id of the object in fabric. + * + * @param generation the generation value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withGeneration(String generation) { + this.generation = generation; + return this; + } + + /** + * Get the Last replication time. + * + * @return the osDetails value + */ + public OSDetails osDetails() { + return this.osDetails; + } + + /** + * Set the Last replication time. + * + * @param osDetails the osDetails value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withOsDetails(OSDetails osDetails) { + this.osDetails = osDetails; + return this; + } + + /** + * Get the Last successful failover time. + * + * @return the diskDetails value + */ + public List diskDetails() { + return this.diskDetails; + } + + /** + * Set the Last successful failover time. + * + * @param diskDetails the diskDetails value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withDiskDetails(List diskDetails) { + this.diskDetails = diskDetails; + return this; + } + + /** + * Get a value indicating whether the VM has a physical disk attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasPhysicalDisk value + */ + public PresenceStatus hasPhysicalDisk() { + return this.hasPhysicalDisk; + } + + /** + * Set a value indicating whether the VM has a physical disk attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasPhysicalDisk the hasPhysicalDisk value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withHasPhysicalDisk(PresenceStatus hasPhysicalDisk) { + this.hasPhysicalDisk = hasPhysicalDisk; + return this; + } + + /** + * Get a value indicating whether the VM has a fibre channel adapter attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasFibreChannelAdapter value + */ + public PresenceStatus hasFibreChannelAdapter() { + return this.hasFibreChannelAdapter; + } + + /** + * Set a value indicating whether the VM has a fibre channel adapter attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasFibreChannelAdapter the hasFibreChannelAdapter value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withHasFibreChannelAdapter(PresenceStatus hasFibreChannelAdapter) { + this.hasFibreChannelAdapter = hasFibreChannelAdapter; + return this; + } + + /** + * Get a value indicating whether the VM has a shared VHD attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasSharedVhd value + */ + public PresenceStatus hasSharedVhd() { + return this.hasSharedVhd; + } + + /** + * Set a value indicating whether the VM has a shared VHD attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasSharedVhd the hasSharedVhd value to set + * @return the HyperVVirtualMachineDetails object itself. + */ + public HyperVVirtualMachineDetails withHasSharedVhd(PresenceStatus hasSharedVhd) { + this.hasSharedVhd = hasSharedVhd; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderDetails.java new file mode 100644 index 0000000000000..b93853bb87f3e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderDetails.java @@ -0,0 +1,155 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Identity provider details. + */ +public class IdentityProviderDetails { + /** + * The tenant Id for the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "tenantId") + private String tenantId; + + /** + * The application/client Id for the service principal with which the + * on-premise management/data plane components would communicate with our + * Azure services. + */ + @JsonProperty(value = "applicationId") + private String applicationId; + + /** + * The object Id of the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "objectId") + private String objectId; + + /** + * The intended Audience of the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "audience") + private String audience; + + /** + * The base authority for Azure Active Directory authentication. + */ + @JsonProperty(value = "aadAuthority") + private String aadAuthority; + + /** + * Get the tenant Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the tenantId value + */ + public String tenantId() { + return this.tenantId; + } + + /** + * Set the tenant Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param tenantId the tenantId value to set + * @return the IdentityProviderDetails object itself. + */ + public IdentityProviderDetails withTenantId(String tenantId) { + this.tenantId = tenantId; + return this; + } + + /** + * Get the application/client Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the applicationId value + */ + public String applicationId() { + return this.applicationId; + } + + /** + * Set the application/client Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param applicationId the applicationId value to set + * @return the IdentityProviderDetails object itself. + */ + public IdentityProviderDetails withApplicationId(String applicationId) { + this.applicationId = applicationId; + return this; + } + + /** + * Get the object Id of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the objectId value + */ + public String objectId() { + return this.objectId; + } + + /** + * Set the object Id of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param objectId the objectId value to set + * @return the IdentityProviderDetails object itself. + */ + public IdentityProviderDetails withObjectId(String objectId) { + this.objectId = objectId; + return this; + } + + /** + * Get the intended Audience of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the audience value + */ + public String audience() { + return this.audience; + } + + /** + * Set the intended Audience of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param audience the audience value to set + * @return the IdentityProviderDetails object itself. + */ + public IdentityProviderDetails withAudience(String audience) { + this.audience = audience; + return this; + } + + /** + * Get the base authority for Azure Active Directory authentication. + * + * @return the aadAuthority value + */ + public String aadAuthority() { + return this.aadAuthority; + } + + /** + * Set the base authority for Azure Active Directory authentication. + * + * @param aadAuthority the aadAuthority value to set + * @return the IdentityProviderDetails object itself. + */ + public IdentityProviderDetails withAadAuthority(String aadAuthority) { + this.aadAuthority = aadAuthority; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderInput.java new file mode 100644 index 0000000000000..25830bc63fe20 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/IdentityProviderInput.java @@ -0,0 +1,155 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Identity provider input. + */ +public class IdentityProviderInput { + /** + * The tenant Id for the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "tenantId", required = true) + private String tenantId; + + /** + * The application/client Id for the service principal with which the + * on-premise management/data plane components would communicate with our + * Azure services. + */ + @JsonProperty(value = "applicationId", required = true) + private String applicationId; + + /** + * The object Id of the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "objectId", required = true) + private String objectId; + + /** + * The intended Audience of the service principal with which the on-premise + * management/data plane components would communicate with our Azure + * services. + */ + @JsonProperty(value = "audience", required = true) + private String audience; + + /** + * The base authority for Azure Active Directory authentication. + */ + @JsonProperty(value = "aadAuthority", required = true) + private String aadAuthority; + + /** + * Get the tenant Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the tenantId value + */ + public String tenantId() { + return this.tenantId; + } + + /** + * Set the tenant Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param tenantId the tenantId value to set + * @return the IdentityProviderInput object itself. + */ + public IdentityProviderInput withTenantId(String tenantId) { + this.tenantId = tenantId; + return this; + } + + /** + * Get the application/client Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the applicationId value + */ + public String applicationId() { + return this.applicationId; + } + + /** + * Set the application/client Id for the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param applicationId the applicationId value to set + * @return the IdentityProviderInput object itself. + */ + public IdentityProviderInput withApplicationId(String applicationId) { + this.applicationId = applicationId; + return this; + } + + /** + * Get the object Id of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the objectId value + */ + public String objectId() { + return this.objectId; + } + + /** + * Set the object Id of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param objectId the objectId value to set + * @return the IdentityProviderInput object itself. + */ + public IdentityProviderInput withObjectId(String objectId) { + this.objectId = objectId; + return this; + } + + /** + * Get the intended Audience of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @return the audience value + */ + public String audience() { + return this.audience; + } + + /** + * Set the intended Audience of the service principal with which the on-premise management/data plane components would communicate with our Azure services. + * + * @param audience the audience value to set + * @return the IdentityProviderInput object itself. + */ + public IdentityProviderInput withAudience(String audience) { + this.audience = audience; + return this; + } + + /** + * Get the base authority for Azure Active Directory authentication. + * + * @return the aadAuthority value + */ + public String aadAuthority() { + return this.aadAuthority; + } + + /** + * Set the base authority for Azure Active Directory authentication. + * + * @param aadAuthority the aadAuthority value to set + * @return the IdentityProviderInput object itself. + */ + public IdentityProviderInput withAadAuthority(String aadAuthority) { + this.aadAuthority = aadAuthority; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentDetails.java new file mode 100644 index 0000000000000..8955d2714448f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentDetails.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The details of the InMage agent. + */ +public class InMageAgentDetails { + /** + * The agent version. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * A value indicating whether installed agent needs to be updated. + */ + @JsonProperty(value = "agentUpdateStatus") + private String agentUpdateStatus; + + /** + * A value indicating whether reboot is required after update is applied. + */ + @JsonProperty(value = "postUpdateRebootStatus") + private String postUpdateRebootStatus; + + /** + * Agent expiry date. + */ + @JsonProperty(value = "agentExpiryDate") + private DateTime agentExpiryDate; + + /** + * Get the agent version. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the agent version. + * + * @param agentVersion the agentVersion value to set + * @return the InMageAgentDetails object itself. + */ + public InMageAgentDetails withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get a value indicating whether installed agent needs to be updated. + * + * @return the agentUpdateStatus value + */ + public String agentUpdateStatus() { + return this.agentUpdateStatus; + } + + /** + * Set a value indicating whether installed agent needs to be updated. + * + * @param agentUpdateStatus the agentUpdateStatus value to set + * @return the InMageAgentDetails object itself. + */ + public InMageAgentDetails withAgentUpdateStatus(String agentUpdateStatus) { + this.agentUpdateStatus = agentUpdateStatus; + return this; + } + + /** + * Get a value indicating whether reboot is required after update is applied. + * + * @return the postUpdateRebootStatus value + */ + public String postUpdateRebootStatus() { + return this.postUpdateRebootStatus; + } + + /** + * Set a value indicating whether reboot is required after update is applied. + * + * @param postUpdateRebootStatus the postUpdateRebootStatus value to set + * @return the InMageAgentDetails object itself. + */ + public InMageAgentDetails withPostUpdateRebootStatus(String postUpdateRebootStatus) { + this.postUpdateRebootStatus = postUpdateRebootStatus; + return this; + } + + /** + * Get agent expiry date. + * + * @return the agentExpiryDate value + */ + public DateTime agentExpiryDate() { + return this.agentExpiryDate; + } + + /** + * Set agent expiry date. + * + * @param agentExpiryDate the agentExpiryDate value to set + * @return the InMageAgentDetails object itself. + */ + public InMageAgentDetails withAgentExpiryDate(DateTime agentExpiryDate) { + this.agentExpiryDate = agentExpiryDate; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentVersionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentVersionDetails.java new file mode 100644 index 0000000000000..3b9646c893395 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAgentVersionDetails.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * InMage agent version details. + */ +public class InMageAgentVersionDetails { + /** + * A value indicating whether reboot is required after update is applied. + */ + @JsonProperty(value = "postUpdateRebootStatus") + private String postUpdateRebootStatus; + + /** + * The agent version. + */ + @JsonProperty(value = "version") + private String version; + + /** + * Version expiry date. + */ + @JsonProperty(value = "expiryDate") + private DateTime expiryDate; + + /** + * A value indicating whether security update required. Possible values + * include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', + * 'SecurityUpdateRequired'. + */ + @JsonProperty(value = "status") + private AgentVersionStatus status; + + /** + * Get a value indicating whether reboot is required after update is applied. + * + * @return the postUpdateRebootStatus value + */ + public String postUpdateRebootStatus() { + return this.postUpdateRebootStatus; + } + + /** + * Set a value indicating whether reboot is required after update is applied. + * + * @param postUpdateRebootStatus the postUpdateRebootStatus value to set + * @return the InMageAgentVersionDetails object itself. + */ + public InMageAgentVersionDetails withPostUpdateRebootStatus(String postUpdateRebootStatus) { + this.postUpdateRebootStatus = postUpdateRebootStatus; + return this; + } + + /** + * Get the agent version. + * + * @return the version value + */ + public String version() { + return this.version; + } + + /** + * Set the agent version. + * + * @param version the version value to set + * @return the InMageAgentVersionDetails object itself. + */ + public InMageAgentVersionDetails withVersion(String version) { + this.version = version; + return this; + } + + /** + * Get version expiry date. + * + * @return the expiryDate value + */ + public DateTime expiryDate() { + return this.expiryDate; + } + + /** + * Set version expiry date. + * + * @param expiryDate the expiryDate value to set + * @return the InMageAgentVersionDetails object itself. + */ + public InMageAgentVersionDetails withExpiryDate(DateTime expiryDate) { + this.expiryDate = expiryDate; + return this; + } + + /** + * Get a value indicating whether security update required. Possible values include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', 'SecurityUpdateRequired'. + * + * @return the status value + */ + public AgentVersionStatus status() { + return this.status; + } + + /** + * Set a value indicating whether security update required. Possible values include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', 'SecurityUpdateRequired'. + * + * @param status the status value to set + * @return the InMageAgentVersionDetails object itself. + */ + public InMageAgentVersionDetails withStatus(AgentVersionStatus status) { + this.status = status; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ApplyRecoveryPointInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ApplyRecoveryPointInput.java new file mode 100644 index 0000000000000..c5b7ef453e448 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ApplyRecoveryPointInput.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * ApplyRecoveryPoint input specific to InMageAzureV2 provider. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2ApplyRecoveryPointInput extends ApplyRecoveryPointProviderSpecificInput { + /** + * The vault location where the recovery Vm resides. + */ + @JsonProperty(value = "vaultLocation") + private String vaultLocation; + + /** + * Get the vault location where the recovery Vm resides. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set the vault location where the recovery Vm resides. + * + * @param vaultLocation the vaultLocation value to set + * @return the InMageAzureV2ApplyRecoveryPointInput object itself. + */ + public InMageAzureV2ApplyRecoveryPointInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EnableProtectionInput.java new file mode 100644 index 0000000000000..5eb990297d276 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EnableProtectionInput.java @@ -0,0 +1,415 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMware Azure specific enable protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2EnableProtectionInput extends EnableProtectionProviderSpecificInput { + /** + * The Master target Id. + */ + @JsonProperty(value = "masterTargetId") + private String masterTargetId; + + /** + * The Process Server Id. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The storage account name. + */ + @JsonProperty(value = "storageAccountId", required = true) + private String storageAccountId; + + /** + * The CS account Id. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * The multi vm group Id. + */ + @JsonProperty(value = "multiVmGroupId") + private String multiVmGroupId; + + /** + * The multi vm group name. + */ + @JsonProperty(value = "multiVmGroupName") + private String multiVmGroupName; + + /** + * The disks to include list. + */ + @JsonProperty(value = "disksToInclude") + private List disksToInclude; + + /** + * The selected target Azure network Id. + */ + @JsonProperty(value = "targetAzureNetworkId") + private String targetAzureNetworkId; + + /** + * The selected target Azure subnet Id. + */ + @JsonProperty(value = "targetAzureSubnetId") + private String targetAzureSubnetId; + + /** + * The selected option to enable RDP\SSH on target vm after failover. + * String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + */ + @JsonProperty(value = "enableRdpOnTargetOption") + private String enableRdpOnTargetOption; + + /** + * The target azure Vm Name. + */ + @JsonProperty(value = "targetAzureVmName") + private String targetAzureVmName; + + /** + * The storage account to be used for logging during replication. + */ + @JsonProperty(value = "logStorageAccountId") + private String logStorageAccountId; + + /** + * The Id of the target resource group (for classic deployment) in which + * the failover VM is to be created. + */ + @JsonProperty(value = "targetAzureV1ResourceGroupId") + private String targetAzureV1ResourceGroupId; + + /** + * The Id of the target resource group (for resource manager deployment) in + * which the failover VM is to be created. + */ + @JsonProperty(value = "targetAzureV2ResourceGroupId") + private String targetAzureV2ResourceGroupId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * Get the Master target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the Master target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the Process Server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the Process Server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the storage account name. + * + * @return the storageAccountId value + */ + public String storageAccountId() { + return this.storageAccountId; + } + + /** + * Set the storage account name. + * + * @param storageAccountId the storageAccountId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withStorageAccountId(String storageAccountId) { + this.storageAccountId = storageAccountId; + return this; + } + + /** + * Get the CS account Id. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS account Id. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + + /** + * Get the multi vm group Id. + * + * @return the multiVmGroupId value + */ + public String multiVmGroupId() { + return this.multiVmGroupId; + } + + /** + * Set the multi vm group Id. + * + * @param multiVmGroupId the multiVmGroupId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withMultiVmGroupId(String multiVmGroupId) { + this.multiVmGroupId = multiVmGroupId; + return this; + } + + /** + * Get the multi vm group name. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get the disks to include list. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the disks to include list. + * + * @param disksToInclude the disksToInclude value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + + /** + * Get the selected target Azure network Id. + * + * @return the targetAzureNetworkId value + */ + public String targetAzureNetworkId() { + return this.targetAzureNetworkId; + } + + /** + * Set the selected target Azure network Id. + * + * @param targetAzureNetworkId the targetAzureNetworkId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withTargetAzureNetworkId(String targetAzureNetworkId) { + this.targetAzureNetworkId = targetAzureNetworkId; + return this; + } + + /** + * Get the selected target Azure subnet Id. + * + * @return the targetAzureSubnetId value + */ + public String targetAzureSubnetId() { + return this.targetAzureSubnetId; + } + + /** + * Set the selected target Azure subnet Id. + * + * @param targetAzureSubnetId the targetAzureSubnetId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withTargetAzureSubnetId(String targetAzureSubnetId) { + this.targetAzureSubnetId = targetAzureSubnetId; + return this; + } + + /** + * Get the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @return the enableRdpOnTargetOption value + */ + public String enableRdpOnTargetOption() { + return this.enableRdpOnTargetOption; + } + + /** + * Set the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @param enableRdpOnTargetOption the enableRdpOnTargetOption value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withEnableRdpOnTargetOption(String enableRdpOnTargetOption) { + this.enableRdpOnTargetOption = enableRdpOnTargetOption; + return this; + } + + /** + * Get the target azure Vm Name. + * + * @return the targetAzureVmName value + */ + public String targetAzureVmName() { + return this.targetAzureVmName; + } + + /** + * Set the target azure Vm Name. + * + * @param targetAzureVmName the targetAzureVmName value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withTargetAzureVmName(String targetAzureVmName) { + this.targetAzureVmName = targetAzureVmName; + return this; + } + + /** + * Get the storage account to be used for logging during replication. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Set the storage account to be used for logging during replication. + * + * @param logStorageAccountId the logStorageAccountId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withLogStorageAccountId(String logStorageAccountId) { + this.logStorageAccountId = logStorageAccountId; + return this; + } + + /** + * Get the Id of the target resource group (for classic deployment) in which the failover VM is to be created. + * + * @return the targetAzureV1ResourceGroupId value + */ + public String targetAzureV1ResourceGroupId() { + return this.targetAzureV1ResourceGroupId; + } + + /** + * Set the Id of the target resource group (for classic deployment) in which the failover VM is to be created. + * + * @param targetAzureV1ResourceGroupId the targetAzureV1ResourceGroupId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withTargetAzureV1ResourceGroupId(String targetAzureV1ResourceGroupId) { + this.targetAzureV1ResourceGroupId = targetAzureV1ResourceGroupId; + return this; + } + + /** + * Get the Id of the target resource group (for resource manager deployment) in which the failover VM is to be created. + * + * @return the targetAzureV2ResourceGroupId value + */ + public String targetAzureV2ResourceGroupId() { + return this.targetAzureV2ResourceGroupId; + } + + /** + * Set the Id of the target resource group (for resource manager deployment) in which the failover VM is to be created. + * + * @param targetAzureV2ResourceGroupId the targetAzureV2ResourceGroupId value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withTargetAzureV2ResourceGroupId(String targetAzureV2ResourceGroupId) { + this.targetAzureV2ResourceGroupId = targetAzureV2ResourceGroupId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the InMageAzureV2EnableProtectionInput object itself. + */ + public InMageAzureV2EnableProtectionInput withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EventDetails.java new file mode 100644 index 0000000000000..917162ce16406 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2EventDetails.java @@ -0,0 +1,204 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a VMwareAzureV2 event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2EventDetails extends EventProviderSpecificDetails { + /** + * InMage Event type. Takes one of the values of + * {InMageDataContract.InMageMonitoringEventType}. + */ + @JsonProperty(value = "eventType") + private String eventType; + + /** + * InMage Event Category. + */ + @JsonProperty(value = "category") + private String category; + + /** + * InMage Event Component. + */ + @JsonProperty(value = "component") + private String component; + + /** + * Corrective Action string for the event. + */ + @JsonProperty(value = "correctiveAction") + private String correctiveAction; + + /** + * InMage Event Details. + */ + @JsonProperty(value = "details") + private String details; + + /** + * InMage Event Summary. + */ + @JsonProperty(value = "summary") + private String summary; + + /** + * VMware Site name. + */ + @JsonProperty(value = "siteName") + private String siteName; + + /** + * Get inMage Event type. Takes one of the values of {InMageDataContract.InMageMonitoringEventType}. + * + * @return the eventType value + */ + public String eventType() { + return this.eventType; + } + + /** + * Set inMage Event type. Takes one of the values of {InMageDataContract.InMageMonitoringEventType}. + * + * @param eventType the eventType value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withEventType(String eventType) { + this.eventType = eventType; + return this; + } + + /** + * Get inMage Event Category. + * + * @return the category value + */ + public String category() { + return this.category; + } + + /** + * Set inMage Event Category. + * + * @param category the category value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withCategory(String category) { + this.category = category; + return this; + } + + /** + * Get inMage Event Component. + * + * @return the component value + */ + public String component() { + return this.component; + } + + /** + * Set inMage Event Component. + * + * @param component the component value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withComponent(String component) { + this.component = component; + return this; + } + + /** + * Get corrective Action string for the event. + * + * @return the correctiveAction value + */ + public String correctiveAction() { + return this.correctiveAction; + } + + /** + * Set corrective Action string for the event. + * + * @param correctiveAction the correctiveAction value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withCorrectiveAction(String correctiveAction) { + this.correctiveAction = correctiveAction; + return this; + } + + /** + * Get inMage Event Details. + * + * @return the details value + */ + public String details() { + return this.details; + } + + /** + * Set inMage Event Details. + * + * @param details the details value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withDetails(String details) { + this.details = details; + return this; + } + + /** + * Get inMage Event Summary. + * + * @return the summary value + */ + public String summary() { + return this.summary; + } + + /** + * Set inMage Event Summary. + * + * @param summary the summary value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withSummary(String summary) { + this.summary = summary; + return this; + } + + /** + * Get vMware Site name. + * + * @return the siteName value + */ + public String siteName() { + return this.siteName; + } + + /** + * Set vMware Site name. + * + * @param siteName the siteName value to set + * @return the InMageAzureV2EventDetails object itself. + */ + public InMageAzureV2EventDetails withSiteName(String siteName) { + this.siteName = siteName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2FailoverProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2FailoverProviderInput.java new file mode 100644 index 0000000000000..ba6a8c21faf41 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2FailoverProviderInput.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMageAzureV2 provider specific input for failover. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2FailoverProviderInput extends ProviderSpecificFailoverInput { + /** + * Location of the vault. + */ + @JsonProperty(value = "vaultLocation") + private String vaultLocation; + + /** + * The recovery point id to be passed to failover to a particular recovery + * point. In case of latest recovery point, null should be passed. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * Get location of the vault. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set location of the vault. + * + * @param vaultLocation the vaultLocation value to set + * @return the InMageAzureV2FailoverProviderInput object itself. + */ + public InMageAzureV2FailoverProviderInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + + /** + * Get the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the InMageAzureV2FailoverProviderInput object itself. + */ + public InMageAzureV2FailoverProviderInput withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyDetails.java new file mode 100644 index 0000000000000..dd3f60750d693 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyDetails.java @@ -0,0 +1,152 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage Azure v2 specific protection profile details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2PolicyDetails extends PolicyProviderSpecificDetails { + /** + * The crash consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * Get the crash consistent snapshot frequency in minutes. + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency in minutes. + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the InMageAzureV2PolicyDetails object itself. + */ + public InMageAzureV2PolicyDetails withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the InMageAzureV2PolicyDetails object itself. + */ + public InMageAzureV2PolicyDetails withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the InMageAzureV2PolicyDetails object itself. + */ + public InMageAzureV2PolicyDetails withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the InMageAzureV2PolicyDetails object itself. + */ + public InMageAzureV2PolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMageAzureV2PolicyDetails object itself. + */ + public InMageAzureV2PolicyDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyInput.java new file mode 100644 index 0000000000000..d5b35873fe365 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2PolicyInput.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMWare Azure specific policy Input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2PolicyInput extends PolicyProviderSpecificInput { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The crash consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * The app consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. Value should + * be 'Enabled' or 'Disabled'. Possible values include: 'Enable', + * 'Disable'. + */ + @JsonProperty(value = "multiVmSyncStatus", required = true) + private SetMultiVmSyncStatus multiVmSyncStatus; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the InMageAzureV2PolicyInput object itself. + */ + public InMageAzureV2PolicyInput withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the InMageAzureV2PolicyInput object itself. + */ + public InMageAzureV2PolicyInput withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the crash consistent snapshot frequency (in minutes). + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency (in minutes). + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the InMageAzureV2PolicyInput object itself. + */ + public InMageAzureV2PolicyInput withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + + /** + * Get the app consistent snapshot frequency (in minutes). + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency (in minutes). + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the InMageAzureV2PolicyInput object itself. + */ + public InMageAzureV2PolicyInput withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @return the multiVmSyncStatus value + */ + public SetMultiVmSyncStatus multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMageAzureV2PolicyInput object itself. + */ + public InMageAzureV2PolicyInput withMultiVmSyncStatus(SetMultiVmSyncStatus multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ProtectedDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ProtectedDiskDetails.java new file mode 100644 index 0000000000000..a82740b62ac33 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ProtectedDiskDetails.java @@ -0,0 +1,408 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * InMageAzureV2 protected disk details. + */ +public class InMageAzureV2ProtectedDiskDetails { + /** + * The disk id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName") + private String diskName; + + /** + * The protection stage. + */ + @JsonProperty(value = "protectionStage") + private String protectionStage; + + /** + * The health error code for the disk. + */ + @JsonProperty(value = "healthErrorCode") + private String healthErrorCode; + + /** + * The RPO in seconds. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * A value indicating whether resync is required for this disk. + */ + @JsonProperty(value = "resyncRequired") + private String resyncRequired; + + /** + * The resync progress percentage. + */ + @JsonProperty(value = "resyncProgressPercentage") + private Integer resyncProgressPercentage; + + /** + * The resync duration in seconds. + */ + @JsonProperty(value = "resyncDurationInSeconds") + private Long resyncDurationInSeconds; + + /** + * The disk capacity in bytes. + */ + @JsonProperty(value = "diskCapacityInBytes") + private Long diskCapacityInBytes; + + /** + * The disk file system capacity in bytes. + */ + @JsonProperty(value = "fileSystemCapacityInBytes") + private Long fileSystemCapacityInBytes; + + /** + * The source data transit in MB. + */ + @JsonProperty(value = "sourceDataInMegaBytes") + private Double sourceDataInMegaBytes; + + /** + * The PS data transit in MB. + */ + @JsonProperty(value = "psDataInMegaBytes") + private Double psDataInMegaBytes; + + /** + * The target data transit in MB. + */ + @JsonProperty(value = "targetDataInMegaBytes") + private Double targetDataInMegaBytes; + + /** + * A value indicating whether disk is resized. + */ + @JsonProperty(value = "diskResized") + private String diskResized; + + /** + * The last RPO calculated time. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * Get the disk id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk id. + * + * @param diskId the diskId value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Set the disk name. + * + * @param diskName the diskName value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withDiskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Get the protection stage. + * + * @return the protectionStage value + */ + public String protectionStage() { + return this.protectionStage; + } + + /** + * Set the protection stage. + * + * @param protectionStage the protectionStage value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withProtectionStage(String protectionStage) { + this.protectionStage = protectionStage; + return this; + } + + /** + * Get the health error code for the disk. + * + * @return the healthErrorCode value + */ + public String healthErrorCode() { + return this.healthErrorCode; + } + + /** + * Set the health error code for the disk. + * + * @param healthErrorCode the healthErrorCode value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withHealthErrorCode(String healthErrorCode) { + this.healthErrorCode = healthErrorCode; + return this; + } + + /** + * Get the RPO in seconds. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set the RPO in seconds. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get a value indicating whether resync is required for this disk. + * + * @return the resyncRequired value + */ + public String resyncRequired() { + return this.resyncRequired; + } + + /** + * Set a value indicating whether resync is required for this disk. + * + * @param resyncRequired the resyncRequired value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withResyncRequired(String resyncRequired) { + this.resyncRequired = resyncRequired; + return this; + } + + /** + * Get the resync progress percentage. + * + * @return the resyncProgressPercentage value + */ + public Integer resyncProgressPercentage() { + return this.resyncProgressPercentage; + } + + /** + * Set the resync progress percentage. + * + * @param resyncProgressPercentage the resyncProgressPercentage value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withResyncProgressPercentage(Integer resyncProgressPercentage) { + this.resyncProgressPercentage = resyncProgressPercentage; + return this; + } + + /** + * Get the resync duration in seconds. + * + * @return the resyncDurationInSeconds value + */ + public Long resyncDurationInSeconds() { + return this.resyncDurationInSeconds; + } + + /** + * Set the resync duration in seconds. + * + * @param resyncDurationInSeconds the resyncDurationInSeconds value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withResyncDurationInSeconds(Long resyncDurationInSeconds) { + this.resyncDurationInSeconds = resyncDurationInSeconds; + return this; + } + + /** + * Get the disk capacity in bytes. + * + * @return the diskCapacityInBytes value + */ + public Long diskCapacityInBytes() { + return this.diskCapacityInBytes; + } + + /** + * Set the disk capacity in bytes. + * + * @param diskCapacityInBytes the diskCapacityInBytes value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withDiskCapacityInBytes(Long diskCapacityInBytes) { + this.diskCapacityInBytes = diskCapacityInBytes; + return this; + } + + /** + * Get the disk file system capacity in bytes. + * + * @return the fileSystemCapacityInBytes value + */ + public Long fileSystemCapacityInBytes() { + return this.fileSystemCapacityInBytes; + } + + /** + * Set the disk file system capacity in bytes. + * + * @param fileSystemCapacityInBytes the fileSystemCapacityInBytes value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withFileSystemCapacityInBytes(Long fileSystemCapacityInBytes) { + this.fileSystemCapacityInBytes = fileSystemCapacityInBytes; + return this; + } + + /** + * Get the source data transit in MB. + * + * @return the sourceDataInMegaBytes value + */ + public Double sourceDataInMegaBytes() { + return this.sourceDataInMegaBytes; + } + + /** + * Set the source data transit in MB. + * + * @param sourceDataInMegaBytes the sourceDataInMegaBytes value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withSourceDataInMegaBytes(Double sourceDataInMegaBytes) { + this.sourceDataInMegaBytes = sourceDataInMegaBytes; + return this; + } + + /** + * Get the PS data transit in MB. + * + * @return the psDataInMegaBytes value + */ + public Double psDataInMegaBytes() { + return this.psDataInMegaBytes; + } + + /** + * Set the PS data transit in MB. + * + * @param psDataInMegaBytes the psDataInMegaBytes value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withPsDataInMegaBytes(Double psDataInMegaBytes) { + this.psDataInMegaBytes = psDataInMegaBytes; + return this; + } + + /** + * Get the target data transit in MB. + * + * @return the targetDataInMegaBytes value + */ + public Double targetDataInMegaBytes() { + return this.targetDataInMegaBytes; + } + + /** + * Set the target data transit in MB. + * + * @param targetDataInMegaBytes the targetDataInMegaBytes value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withTargetDataInMegaBytes(Double targetDataInMegaBytes) { + this.targetDataInMegaBytes = targetDataInMegaBytes; + return this; + } + + /** + * Get a value indicating whether disk is resized. + * + * @return the diskResized value + */ + public String diskResized() { + return this.diskResized; + } + + /** + * Set a value indicating whether disk is resized. + * + * @param diskResized the diskResized value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withDiskResized(String diskResized) { + this.diskResized = diskResized; + return this; + } + + /** + * Get the last RPO calculated time. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the last RPO calculated time. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the InMageAzureV2ProtectedDiskDetails object itself. + */ + public InMageAzureV2ProtectedDiskDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2RecoveryPointDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2RecoveryPointDetails.java new file mode 100644 index 0000000000000..dce8c9a3bb3dc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2RecoveryPointDetails.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage Azure V2 provider specific recovery point details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2RecoveryPointDetails extends ProviderSpecificRecoveryPointDetails { + /** + * A value indicating whether the recovery point is multi VM consistent. + */ + @JsonProperty(value = "isMultiVmSyncPoint") + private String isMultiVmSyncPoint; + + /** + * Get a value indicating whether the recovery point is multi VM consistent. + * + * @return the isMultiVmSyncPoint value + */ + public String isMultiVmSyncPoint() { + return this.isMultiVmSyncPoint; + } + + /** + * Set a value indicating whether the recovery point is multi VM consistent. + * + * @param isMultiVmSyncPoint the isMultiVmSyncPoint value to set + * @return the InMageAzureV2RecoveryPointDetails object itself. + */ + public InMageAzureV2RecoveryPointDetails withIsMultiVmSyncPoint(String isMultiVmSyncPoint) { + this.isMultiVmSyncPoint = isMultiVmSyncPoint; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReplicationDetails.java new file mode 100644 index 0000000000000..f9ba467dd9428 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReplicationDetails.java @@ -0,0 +1,1307 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMageAzureV2 provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2ReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The infrastructure VM Id. + */ + @JsonProperty(value = "infrastructureVmId") + private String infrastructureVmId; + + /** + * The vCenter infrastructure Id. + */ + @JsonProperty(value = "vCenterInfrastructureId") + private String vCenterInfrastructureId; + + /** + * The protection stage. + */ + @JsonProperty(value = "protectionStage") + private String protectionStage; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * The resync progress percentage. + */ + @JsonProperty(value = "resyncProgressPercentage") + private Integer resyncProgressPercentage; + + /** + * The RPO in seconds. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * The compressed data change rate in MB. + */ + @JsonProperty(value = "compressedDataRateInMB") + private Double compressedDataRateInMB; + + /** + * The uncompressed data change rate in MB. + */ + @JsonProperty(value = "uncompressedDataRateInMB") + private Double uncompressedDataRateInMB; + + /** + * The source IP address. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The agent version. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * Agent expiry date. + */ + @JsonProperty(value = "agentExpiryDate") + private DateTime agentExpiryDate; + + /** + * A value indicating whether installed agent needs to be updated. + */ + @JsonProperty(value = "isAgentUpdateRequired") + private String isAgentUpdateRequired; + + /** + * A value indicating whether the source server requires a restart after + * update. + */ + @JsonProperty(value = "isRebootAfterUpdateRequired") + private String isRebootAfterUpdateRequired; + + /** + * The last heartbeat received from the source server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * The process server Id. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The multi vm group Id. + */ + @JsonProperty(value = "multiVmGroupId") + private String multiVmGroupId; + + /** + * The multi vm group name. + */ + @JsonProperty(value = "multiVmGroupName") + private String multiVmGroupName; + + /** + * A value indicating whether multi vm sync is enabled or disabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * The list of protected disks. + */ + @JsonProperty(value = "protectedDisks") + private List protectedDisks; + + /** + * A value indicating whether any disk is resized for this VM. + */ + @JsonProperty(value = "diskResized") + private String diskResized; + + /** + * The master target Id. + */ + @JsonProperty(value = "masterTargetId") + private String masterTargetId; + + /** + * The CPU count of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmCpuCount") + private Integer sourceVmCpuCount; + + /** + * The RAM size of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmRamSizeInMB") + private Integer sourceVmRamSizeInMB; + + /** + * The type of the OS on the VM. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The OS disk VHD name. + */ + @JsonProperty(value = "vhdName") + private String vhdName; + + /** + * The id of the disk containing the OS. + */ + @JsonProperty(value = "osDiskId") + private String osDiskId; + + /** + * Azure VM Disk details. + */ + @JsonProperty(value = "azureVMDiskDetails") + private List azureVMDiskDetails; + + /** + * Recovery Azure given name. + */ + @JsonProperty(value = "recoveryAzureVMName") + private String recoveryAzureVMName; + + /** + * The Recovery Azure VM size. + */ + @JsonProperty(value = "recoveryAzureVMSize") + private String recoveryAzureVMSize; + + /** + * The recovery Azure storage account. + */ + @JsonProperty(value = "recoveryAzureStorageAccount") + private String recoveryAzureStorageAccount; + + /** + * The ARM id of the log storage account used for replication. This will be + * set to null if no log storage account was provided during enable + * protection. + */ + @JsonProperty(value = "recoveryAzureLogStorageAccountId") + private String recoveryAzureLogStorageAccountId; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The selected recovery azure network Id. + */ + @JsonProperty(value = "selectedRecoveryAzureNetworkId") + private String selectedRecoveryAzureNetworkId; + + /** + * The selected source nic Id which will be used as the primary nic during + * failover. + */ + @JsonProperty(value = "selectedSourceNicId") + private String selectedSourceNicId; + + /** + * A value indicating the discovery type of the machine. Value can be + * vCenter or physical. + */ + @JsonProperty(value = "discoveryType") + private String discoveryType; + + /** + * The selected option to enable RDP\SSH on target vm after failover. + * String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + */ + @JsonProperty(value = "enableRdpOnTargetOption") + private String enableRdpOnTargetOption; + + /** + * The data stores of the on-premise machine. Value can be list of strings + * that contain data store names. + */ + @JsonProperty(value = "datastores") + private List datastores; + + /** + * The ARM Id of the target Azure VM. This value will be null until the VM + * is failed over. Only after failure it will be populated with the ARM Id + * of the Azure VM. + */ + @JsonProperty(value = "targetVmId") + private String targetVmId; + + /** + * The target resource group Id. + */ + @JsonProperty(value = "recoveryAzureResourceGroupId") + private String recoveryAzureResourceGroupId; + + /** + * The recovery availability set Id. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * License Type of the VM to be used. + */ + @JsonProperty(value = "licenseType") + private String licenseType; + + /** + * The validation errors of the on-premise machine Value can be list of + * validation errors. + */ + @JsonProperty(value = "validationErrors") + private List validationErrors; + + /** + * The last RPO calculated time. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * The last update time received from on-prem components. + */ + @JsonProperty(value = "lastUpdateReceivedTime") + private DateTime lastUpdateReceivedTime; + + /** + * The replica id of the protected item. + */ + @JsonProperty(value = "replicaId") + private String replicaId; + + /** + * The OS Version of the protected item. + */ + @JsonProperty(value = "osVersion") + private String osVersion; + + /** + * Get the infrastructure VM Id. + * + * @return the infrastructureVmId value + */ + public String infrastructureVmId() { + return this.infrastructureVmId; + } + + /** + * Set the infrastructure VM Id. + * + * @param infrastructureVmId the infrastructureVmId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withInfrastructureVmId(String infrastructureVmId) { + this.infrastructureVmId = infrastructureVmId; + return this; + } + + /** + * Get the vCenter infrastructure Id. + * + * @return the vCenterInfrastructureId value + */ + public String vCenterInfrastructureId() { + return this.vCenterInfrastructureId; + } + + /** + * Set the vCenter infrastructure Id. + * + * @param vCenterInfrastructureId the vCenterInfrastructureId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVCenterInfrastructureId(String vCenterInfrastructureId) { + this.vCenterInfrastructureId = vCenterInfrastructureId; + return this; + } + + /** + * Get the protection stage. + * + * @return the protectionStage value + */ + public String protectionStage() { + return this.protectionStage; + } + + /** + * Set the protection stage. + * + * @param protectionStage the protectionStage value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withProtectionStage(String protectionStage) { + this.protectionStage = protectionStage; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get the resync progress percentage. + * + * @return the resyncProgressPercentage value + */ + public Integer resyncProgressPercentage() { + return this.resyncProgressPercentage; + } + + /** + * Set the resync progress percentage. + * + * @param resyncProgressPercentage the resyncProgressPercentage value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withResyncProgressPercentage(Integer resyncProgressPercentage) { + this.resyncProgressPercentage = resyncProgressPercentage; + return this; + } + + /** + * Get the RPO in seconds. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set the RPO in seconds. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get the compressed data change rate in MB. + * + * @return the compressedDataRateInMB value + */ + public Double compressedDataRateInMB() { + return this.compressedDataRateInMB; + } + + /** + * Set the compressed data change rate in MB. + * + * @param compressedDataRateInMB the compressedDataRateInMB value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withCompressedDataRateInMB(Double compressedDataRateInMB) { + this.compressedDataRateInMB = compressedDataRateInMB; + return this; + } + + /** + * Get the uncompressed data change rate in MB. + * + * @return the uncompressedDataRateInMB value + */ + public Double uncompressedDataRateInMB() { + return this.uncompressedDataRateInMB; + } + + /** + * Set the uncompressed data change rate in MB. + * + * @param uncompressedDataRateInMB the uncompressedDataRateInMB value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withUncompressedDataRateInMB(Double uncompressedDataRateInMB) { + this.uncompressedDataRateInMB = uncompressedDataRateInMB; + return this; + } + + /** + * Get the source IP address. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the source IP address. + * + * @param ipAddress the ipAddress value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the agent version. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the agent version. + * + * @param agentVersion the agentVersion value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get agent expiry date. + * + * @return the agentExpiryDate value + */ + public DateTime agentExpiryDate() { + return this.agentExpiryDate; + } + + /** + * Set agent expiry date. + * + * @param agentExpiryDate the agentExpiryDate value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withAgentExpiryDate(DateTime agentExpiryDate) { + this.agentExpiryDate = agentExpiryDate; + return this; + } + + /** + * Get a value indicating whether installed agent needs to be updated. + * + * @return the isAgentUpdateRequired value + */ + public String isAgentUpdateRequired() { + return this.isAgentUpdateRequired; + } + + /** + * Set a value indicating whether installed agent needs to be updated. + * + * @param isAgentUpdateRequired the isAgentUpdateRequired value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withIsAgentUpdateRequired(String isAgentUpdateRequired) { + this.isAgentUpdateRequired = isAgentUpdateRequired; + return this; + } + + /** + * Get a value indicating whether the source server requires a restart after update. + * + * @return the isRebootAfterUpdateRequired value + */ + public String isRebootAfterUpdateRequired() { + return this.isRebootAfterUpdateRequired; + } + + /** + * Set a value indicating whether the source server requires a restart after update. + * + * @param isRebootAfterUpdateRequired the isRebootAfterUpdateRequired value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withIsRebootAfterUpdateRequired(String isRebootAfterUpdateRequired) { + this.isRebootAfterUpdateRequired = isRebootAfterUpdateRequired; + return this; + } + + /** + * Get the last heartbeat received from the source server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from the source server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get the process server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the process server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the multi vm group Id. + * + * @return the multiVmGroupId value + */ + public String multiVmGroupId() { + return this.multiVmGroupId; + } + + /** + * Set the multi vm group Id. + * + * @param multiVmGroupId the multiVmGroupId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withMultiVmGroupId(String multiVmGroupId) { + this.multiVmGroupId = multiVmGroupId; + return this; + } + + /** + * Get the multi vm group name. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get a value indicating whether multi vm sync is enabled or disabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi vm sync is enabled or disabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + + /** + * Get the list of protected disks. + * + * @return the protectedDisks value + */ + public List protectedDisks() { + return this.protectedDisks; + } + + /** + * Set the list of protected disks. + * + * @param protectedDisks the protectedDisks value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withProtectedDisks(List protectedDisks) { + this.protectedDisks = protectedDisks; + return this; + } + + /** + * Get a value indicating whether any disk is resized for this VM. + * + * @return the diskResized value + */ + public String diskResized() { + return this.diskResized; + } + + /** + * Set a value indicating whether any disk is resized for this VM. + * + * @param diskResized the diskResized value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withDiskResized(String diskResized) { + this.diskResized = diskResized; + return this; + } + + /** + * Get the master target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the master target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the CPU count of the VM on the primary side. + * + * @return the sourceVmCpuCount value + */ + public Integer sourceVmCpuCount() { + return this.sourceVmCpuCount; + } + + /** + * Set the CPU count of the VM on the primary side. + * + * @param sourceVmCpuCount the sourceVmCpuCount value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withSourceVmCpuCount(Integer sourceVmCpuCount) { + this.sourceVmCpuCount = sourceVmCpuCount; + return this; + } + + /** + * Get the RAM size of the VM on the primary side. + * + * @return the sourceVmRamSizeInMB value + */ + public Integer sourceVmRamSizeInMB() { + return this.sourceVmRamSizeInMB; + } + + /** + * Set the RAM size of the VM on the primary side. + * + * @param sourceVmRamSizeInMB the sourceVmRamSizeInMB value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withSourceVmRamSizeInMB(Integer sourceVmRamSizeInMB) { + this.sourceVmRamSizeInMB = sourceVmRamSizeInMB; + return this; + } + + /** + * Get the type of the OS on the VM. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the type of the OS on the VM. + * + * @param osType the osType value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the OS disk VHD name. + * + * @return the vhdName value + */ + public String vhdName() { + return this.vhdName; + } + + /** + * Set the OS disk VHD name. + * + * @param vhdName the vhdName value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVhdName(String vhdName) { + this.vhdName = vhdName; + return this; + } + + /** + * Get the id of the disk containing the OS. + * + * @return the osDiskId value + */ + public String osDiskId() { + return this.osDiskId; + } + + /** + * Set the id of the disk containing the OS. + * + * @param osDiskId the osDiskId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withOsDiskId(String osDiskId) { + this.osDiskId = osDiskId; + return this; + } + + /** + * Get azure VM Disk details. + * + * @return the azureVMDiskDetails value + */ + public List azureVMDiskDetails() { + return this.azureVMDiskDetails; + } + + /** + * Set azure VM Disk details. + * + * @param azureVMDiskDetails the azureVMDiskDetails value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withAzureVMDiskDetails(List azureVMDiskDetails) { + this.azureVMDiskDetails = azureVMDiskDetails; + return this; + } + + /** + * Get recovery Azure given name. + * + * @return the recoveryAzureVMName value + */ + public String recoveryAzureVMName() { + return this.recoveryAzureVMName; + } + + /** + * Set recovery Azure given name. + * + * @param recoveryAzureVMName the recoveryAzureVMName value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAzureVMName(String recoveryAzureVMName) { + this.recoveryAzureVMName = recoveryAzureVMName; + return this; + } + + /** + * Get the Recovery Azure VM size. + * + * @return the recoveryAzureVMSize value + */ + public String recoveryAzureVMSize() { + return this.recoveryAzureVMSize; + } + + /** + * Set the Recovery Azure VM size. + * + * @param recoveryAzureVMSize the recoveryAzureVMSize value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAzureVMSize(String recoveryAzureVMSize) { + this.recoveryAzureVMSize = recoveryAzureVMSize; + return this; + } + + /** + * Get the recovery Azure storage account. + * + * @return the recoveryAzureStorageAccount value + */ + public String recoveryAzureStorageAccount() { + return this.recoveryAzureStorageAccount; + } + + /** + * Set the recovery Azure storage account. + * + * @param recoveryAzureStorageAccount the recoveryAzureStorageAccount value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAzureStorageAccount(String recoveryAzureStorageAccount) { + this.recoveryAzureStorageAccount = recoveryAzureStorageAccount; + return this; + } + + /** + * Get the ARM id of the log storage account used for replication. This will be set to null if no log storage account was provided during enable protection. + * + * @return the recoveryAzureLogStorageAccountId value + */ + public String recoveryAzureLogStorageAccountId() { + return this.recoveryAzureLogStorageAccountId; + } + + /** + * Set the ARM id of the log storage account used for replication. This will be set to null if no log storage account was provided during enable protection. + * + * @param recoveryAzureLogStorageAccountId the recoveryAzureLogStorageAccountId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAzureLogStorageAccountId(String recoveryAzureLogStorageAccountId) { + this.recoveryAzureLogStorageAccountId = recoveryAzureLogStorageAccountId; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the selected recovery azure network Id. + * + * @return the selectedRecoveryAzureNetworkId value + */ + public String selectedRecoveryAzureNetworkId() { + return this.selectedRecoveryAzureNetworkId; + } + + /** + * Set the selected recovery azure network Id. + * + * @param selectedRecoveryAzureNetworkId the selectedRecoveryAzureNetworkId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withSelectedRecoveryAzureNetworkId(String selectedRecoveryAzureNetworkId) { + this.selectedRecoveryAzureNetworkId = selectedRecoveryAzureNetworkId; + return this; + } + + /** + * Get the selected source nic Id which will be used as the primary nic during failover. + * + * @return the selectedSourceNicId value + */ + public String selectedSourceNicId() { + return this.selectedSourceNicId; + } + + /** + * Set the selected source nic Id which will be used as the primary nic during failover. + * + * @param selectedSourceNicId the selectedSourceNicId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withSelectedSourceNicId(String selectedSourceNicId) { + this.selectedSourceNicId = selectedSourceNicId; + return this; + } + + /** + * Get a value indicating the discovery type of the machine. Value can be vCenter or physical. + * + * @return the discoveryType value + */ + public String discoveryType() { + return this.discoveryType; + } + + /** + * Set a value indicating the discovery type of the machine. Value can be vCenter or physical. + * + * @param discoveryType the discoveryType value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withDiscoveryType(String discoveryType) { + this.discoveryType = discoveryType; + return this; + } + + /** + * Get the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @return the enableRdpOnTargetOption value + */ + public String enableRdpOnTargetOption() { + return this.enableRdpOnTargetOption; + } + + /** + * Set the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @param enableRdpOnTargetOption the enableRdpOnTargetOption value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withEnableRdpOnTargetOption(String enableRdpOnTargetOption) { + this.enableRdpOnTargetOption = enableRdpOnTargetOption; + return this; + } + + /** + * Get the data stores of the on-premise machine. Value can be list of strings that contain data store names. + * + * @return the datastores value + */ + public List datastores() { + return this.datastores; + } + + /** + * Set the data stores of the on-premise machine. Value can be list of strings that contain data store names. + * + * @param datastores the datastores value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withDatastores(List datastores) { + this.datastores = datastores; + return this; + } + + /** + * Get the ARM Id of the target Azure VM. This value will be null until the VM is failed over. Only after failure it will be populated with the ARM Id of the Azure VM. + * + * @return the targetVmId value + */ + public String targetVmId() { + return this.targetVmId; + } + + /** + * Set the ARM Id of the target Azure VM. This value will be null until the VM is failed over. Only after failure it will be populated with the ARM Id of the Azure VM. + * + * @param targetVmId the targetVmId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withTargetVmId(String targetVmId) { + this.targetVmId = targetVmId; + return this; + } + + /** + * Get the target resource group Id. + * + * @return the recoveryAzureResourceGroupId value + */ + public String recoveryAzureResourceGroupId() { + return this.recoveryAzureResourceGroupId; + } + + /** + * Set the target resource group Id. + * + * @param recoveryAzureResourceGroupId the recoveryAzureResourceGroupId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAzureResourceGroupId(String recoveryAzureResourceGroupId) { + this.recoveryAzureResourceGroupId = recoveryAzureResourceGroupId; + return this; + } + + /** + * Get the recovery availability set Id. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the recovery availability set Id. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + + /** + * Get license Type of the VM to be used. + * + * @return the licenseType value + */ + public String licenseType() { + return this.licenseType; + } + + /** + * Set license Type of the VM to be used. + * + * @param licenseType the licenseType value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withLicenseType(String licenseType) { + this.licenseType = licenseType; + return this; + } + + /** + * Get the validation errors of the on-premise machine Value can be list of validation errors. + * + * @return the validationErrors value + */ + public List validationErrors() { + return this.validationErrors; + } + + /** + * Set the validation errors of the on-premise machine Value can be list of validation errors. + * + * @param validationErrors the validationErrors value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withValidationErrors(List validationErrors) { + this.validationErrors = validationErrors; + return this; + } + + /** + * Get the last RPO calculated time. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the last RPO calculated time. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + + /** + * Get the last update time received from on-prem components. + * + * @return the lastUpdateReceivedTime value + */ + public DateTime lastUpdateReceivedTime() { + return this.lastUpdateReceivedTime; + } + + /** + * Set the last update time received from on-prem components. + * + * @param lastUpdateReceivedTime the lastUpdateReceivedTime value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withLastUpdateReceivedTime(DateTime lastUpdateReceivedTime) { + this.lastUpdateReceivedTime = lastUpdateReceivedTime; + return this; + } + + /** + * Get the replica id of the protected item. + * + * @return the replicaId value + */ + public String replicaId() { + return this.replicaId; + } + + /** + * Set the replica id of the protected item. + * + * @param replicaId the replicaId value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withReplicaId(String replicaId) { + this.replicaId = replicaId; + return this; + } + + /** + * Get the OS Version of the protected item. + * + * @return the osVersion value + */ + public String osVersion() { + return this.osVersion; + } + + /** + * Set the OS Version of the protected item. + * + * @param osVersion the osVersion value to set + * @return the InMageAzureV2ReplicationDetails object itself. + */ + public InMageAzureV2ReplicationDetails withOsVersion(String osVersion) { + this.osVersion = osVersion; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReprotectInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReprotectInput.java new file mode 100644 index 0000000000000..d42db36682298 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2ReprotectInput.java @@ -0,0 +1,204 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMageAzureV2 specific provider input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2ReprotectInput extends ReverseReplicationProviderSpecificInput { + /** + * The Master target Id. + */ + @JsonProperty(value = "masterTargetId") + private String masterTargetId; + + /** + * The Process Server Id. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The storage account id. + */ + @JsonProperty(value = "storageAccountId") + private String storageAccountId; + + /** + * The CS account Id. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * The Policy Id. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * The storage account to be used for logging during replication. + */ + @JsonProperty(value = "logStorageAccountId") + private String logStorageAccountId; + + /** + * The disks to include list. + */ + @JsonProperty(value = "disksToInclude") + private List disksToInclude; + + /** + * Get the Master target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the Master target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the Process Server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the Process Server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the storage account id. + * + * @return the storageAccountId value + */ + public String storageAccountId() { + return this.storageAccountId; + } + + /** + * Set the storage account id. + * + * @param storageAccountId the storageAccountId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withStorageAccountId(String storageAccountId) { + this.storageAccountId = storageAccountId; + return this; + } + + /** + * Get the CS account Id. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS account Id. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + + /** + * Get the Policy Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the Policy Id. + * + * @param policyId the policyId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get the storage account to be used for logging during replication. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Set the storage account to be used for logging during replication. + * + * @param logStorageAccountId the logStorageAccountId value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withLogStorageAccountId(String logStorageAccountId) { + this.logStorageAccountId = logStorageAccountId; + return this; + } + + /** + * Get the disks to include list. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the disks to include list. + * + * @param disksToInclude the disksToInclude value to set + * @return the InMageAzureV2ReprotectInput object itself. + */ + public InMageAzureV2ReprotectInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2UpdateReplicationProtectedItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2UpdateReplicationProtectedItemInput.java new file mode 100644 index 0000000000000..0b84bb25690ef --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageAzureV2UpdateReplicationProtectedItemInput.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage Azure V2 input to update replication protected item. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class InMageAzureV2UpdateReplicationProtectedItemInput extends UpdateReplicationProtectedItemProviderInput { + /** + * The recovery Azure resource group Id for classic deployment. + */ + @JsonProperty(value = "recoveryAzureV1ResourceGroupId") + private String recoveryAzureV1ResourceGroupId; + + /** + * The recovery Azure resource group Id for resource manager deployment. + */ + @JsonProperty(value = "recoveryAzureV2ResourceGroupId") + private String recoveryAzureV2ResourceGroupId; + + /** + * A value indicating whether managed disks should be used during failover. + */ + @JsonProperty(value = "useManagedDisks") + private String useManagedDisks; + + /** + * Get the recovery Azure resource group Id for classic deployment. + * + * @return the recoveryAzureV1ResourceGroupId value + */ + public String recoveryAzureV1ResourceGroupId() { + return this.recoveryAzureV1ResourceGroupId; + } + + /** + * Set the recovery Azure resource group Id for classic deployment. + * + * @param recoveryAzureV1ResourceGroupId the recoveryAzureV1ResourceGroupId value to set + * @return the InMageAzureV2UpdateReplicationProtectedItemInput object itself. + */ + public InMageAzureV2UpdateReplicationProtectedItemInput withRecoveryAzureV1ResourceGroupId(String recoveryAzureV1ResourceGroupId) { + this.recoveryAzureV1ResourceGroupId = recoveryAzureV1ResourceGroupId; + return this; + } + + /** + * Get the recovery Azure resource group Id for resource manager deployment. + * + * @return the recoveryAzureV2ResourceGroupId value + */ + public String recoveryAzureV2ResourceGroupId() { + return this.recoveryAzureV2ResourceGroupId; + } + + /** + * Set the recovery Azure resource group Id for resource manager deployment. + * + * @param recoveryAzureV2ResourceGroupId the recoveryAzureV2ResourceGroupId value to set + * @return the InMageAzureV2UpdateReplicationProtectedItemInput object itself. + */ + public InMageAzureV2UpdateReplicationProtectedItemInput withRecoveryAzureV2ResourceGroupId(String recoveryAzureV2ResourceGroupId) { + this.recoveryAzureV2ResourceGroupId = recoveryAzureV2ResourceGroupId; + return this; + } + + /** + * Get a value indicating whether managed disks should be used during failover. + * + * @return the useManagedDisks value + */ + public String useManagedDisks() { + return this.useManagedDisks; + } + + /** + * Set a value indicating whether managed disks should be used during failover. + * + * @param useManagedDisks the useManagedDisks value to set + * @return the InMageAzureV2UpdateReplicationProtectedItemInput object itself. + */ + public InMageAzureV2UpdateReplicationProtectedItemInput withUseManagedDisks(String useManagedDisks) { + this.useManagedDisks = useManagedDisks; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageBasePolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageBasePolicyDetails.java new file mode 100644 index 0000000000000..67d655ec8ad3d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageBasePolicyDetails.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Base class for the policies of providers using InMage replication. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageBasePolicyDetails") +public class InMageBasePolicyDetails extends PolicyProviderSpecificDetails { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the InMageBasePolicyDetails object itself. + */ + public InMageBasePolicyDetails withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the InMageBasePolicyDetails object itself. + */ + public InMageBasePolicyDetails withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the InMageBasePolicyDetails object itself. + */ + public InMageBasePolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMageBasePolicyDetails object itself. + */ + public InMageBasePolicyDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDisableProtectionProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDisableProtectionProviderSpecificInput.java new file mode 100644 index 0000000000000..413e3798b63cc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDisableProtectionProviderSpecificInput.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage disable protection provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMageDisableProtectionProviderSpecificInput extends DisableProtectionProviderSpecificInput { + /** + * A value indicating whether the replica VM should be destroyed or + * retained. Values from Delete and Retain. + */ + @JsonProperty(value = "replicaVmDeletionStatus") + private String replicaVmDeletionStatus; + + /** + * Get a value indicating whether the replica VM should be destroyed or retained. Values from Delete and Retain. + * + * @return the replicaVmDeletionStatus value + */ + public String replicaVmDeletionStatus() { + return this.replicaVmDeletionStatus; + } + + /** + * Set a value indicating whether the replica VM should be destroyed or retained. Values from Delete and Retain. + * + * @param replicaVmDeletionStatus the replicaVmDeletionStatus value to set + * @return the InMageDisableProtectionProviderSpecificInput object itself. + */ + public InMageDisableProtectionProviderSpecificInput withReplicaVmDeletionStatus(String replicaVmDeletionStatus) { + this.replicaVmDeletionStatus = replicaVmDeletionStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskDetails.java new file mode 100644 index 0000000000000..059f1693733e1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskDetails.java @@ -0,0 +1,174 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * VMware/Physical specific Disk Details. + */ +public class InMageDiskDetails { + /** + * The disk Id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName") + private String diskName; + + /** + * The disk size in MB. + */ + @JsonProperty(value = "diskSizeInMB") + private String diskSizeInMB; + + /** + * Whether disk is system disk or data disk. + */ + @JsonProperty(value = "diskType") + private String diskType; + + /** + * Whether disk is dynamic disk or basic disk. + */ + @JsonProperty(value = "diskConfiguration") + private String diskConfiguration; + + /** + * Volumes of the disk. + */ + @JsonProperty(value = "volumeList") + private List volumeList; + + /** + * Get the disk Id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk Id. + * + * @param diskId the diskId value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Set the disk name. + * + * @param diskName the diskName value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withDiskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Get the disk size in MB. + * + * @return the diskSizeInMB value + */ + public String diskSizeInMB() { + return this.diskSizeInMB; + } + + /** + * Set the disk size in MB. + * + * @param diskSizeInMB the diskSizeInMB value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withDiskSizeInMB(String diskSizeInMB) { + this.diskSizeInMB = diskSizeInMB; + return this; + } + + /** + * Get whether disk is system disk or data disk. + * + * @return the diskType value + */ + public String diskType() { + return this.diskType; + } + + /** + * Set whether disk is system disk or data disk. + * + * @param diskType the diskType value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withDiskType(String diskType) { + this.diskType = diskType; + return this; + } + + /** + * Get whether disk is dynamic disk or basic disk. + * + * @return the diskConfiguration value + */ + public String diskConfiguration() { + return this.diskConfiguration; + } + + /** + * Set whether disk is dynamic disk or basic disk. + * + * @param diskConfiguration the diskConfiguration value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withDiskConfiguration(String diskConfiguration) { + this.diskConfiguration = diskConfiguration; + return this; + } + + /** + * Get volumes of the disk. + * + * @return the volumeList value + */ + public List volumeList() { + return this.volumeList; + } + + /** + * Set volumes of the disk. + * + * @param volumeList the volumeList value to set + * @return the InMageDiskDetails object itself. + */ + public InMageDiskDetails withVolumeList(List volumeList) { + this.volumeList = volumeList; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskExclusionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskExclusionInput.java new file mode 100644 index 0000000000000..de3abbf14afbb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskExclusionInput.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * DiskExclusionInput when doing enable protection of virtual machine in InMage + * provider. + */ +public class InMageDiskExclusionInput { + /** + * The volume label based option for disk exclusion. + */ + @JsonProperty(value = "volumeOptions") + private List volumeOptions; + + /** + * The guest disk signature based option for disk exclusion. + */ + @JsonProperty(value = "diskSignatureOptions") + private List diskSignatureOptions; + + /** + * Get the volume label based option for disk exclusion. + * + * @return the volumeOptions value + */ + public List volumeOptions() { + return this.volumeOptions; + } + + /** + * Set the volume label based option for disk exclusion. + * + * @param volumeOptions the volumeOptions value to set + * @return the InMageDiskExclusionInput object itself. + */ + public InMageDiskExclusionInput withVolumeOptions(List volumeOptions) { + this.volumeOptions = volumeOptions; + return this; + } + + /** + * Get the guest disk signature based option for disk exclusion. + * + * @return the diskSignatureOptions value + */ + public List diskSignatureOptions() { + return this.diskSignatureOptions; + } + + /** + * Set the guest disk signature based option for disk exclusion. + * + * @param diskSignatureOptions the diskSignatureOptions value to set + * @return the InMageDiskExclusionInput object itself. + */ + public InMageDiskExclusionInput withDiskSignatureOptions(List diskSignatureOptions) { + this.diskSignatureOptions = diskSignatureOptions; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskSignatureExclusionOptions.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskSignatureExclusionOptions.java new file mode 100644 index 0000000000000..2b8f43356709f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageDiskSignatureExclusionOptions.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Guest disk signature based disk exclusion option when doing enable + * protection of virtual machine in InMage provider. + */ +public class InMageDiskSignatureExclusionOptions { + /** + * The guest signature of disk to be excluded from replication. + */ + @JsonProperty(value = "diskSignature") + private String diskSignature; + + /** + * Get the guest signature of disk to be excluded from replication. + * + * @return the diskSignature value + */ + public String diskSignature() { + return this.diskSignature; + } + + /** + * Set the guest signature of disk to be excluded from replication. + * + * @param diskSignature the diskSignature value to set + * @return the InMageDiskSignatureExclusionOptions object itself. + */ + public InMageDiskSignatureExclusionOptions withDiskSignature(String diskSignature) { + this.diskSignature = diskSignature; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageEnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageEnableProtectionInput.java new file mode 100644 index 0000000000000..dc1c768fba3e8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageEnableProtectionInput.java @@ -0,0 +1,282 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMware Azure specific enable protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMageEnableProtectionInput extends EnableProtectionProviderSpecificInput { + /** + * The Vm Name. + */ + @JsonProperty(value = "vmFriendlyName") + private String vmFriendlyName; + + /** + * The Master Target Id. + */ + @JsonProperty(value = "masterTargetId", required = true) + private String masterTargetId; + + /** + * The Process Server Id. + */ + @JsonProperty(value = "processServerId", required = true) + private String processServerId; + + /** + * The retention drive to use on the MT. + */ + @JsonProperty(value = "retentionDrive", required = true) + private String retentionDrive; + + /** + * The CS account Id. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * The multi vm group Id. + */ + @JsonProperty(value = "multiVmGroupId", required = true) + private String multiVmGroupId; + + /** + * The multi vm group name. + */ + @JsonProperty(value = "multiVmGroupName", required = true) + private String multiVmGroupName; + + /** + * The target data store name. + */ + @JsonProperty(value = "datastoreName") + private String datastoreName; + + /** + * The enable disk exclusion input. + */ + @JsonProperty(value = "diskExclusionInput") + private InMageDiskExclusionInput diskExclusionInput; + + /** + * The disks to include list. + */ + @JsonProperty(value = "disksToInclude") + private List disksToInclude; + + /** + * Get the Vm Name. + * + * @return the vmFriendlyName value + */ + public String vmFriendlyName() { + return this.vmFriendlyName; + } + + /** + * Set the Vm Name. + * + * @param vmFriendlyName the vmFriendlyName value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withVmFriendlyName(String vmFriendlyName) { + this.vmFriendlyName = vmFriendlyName; + return this; + } + + /** + * Get the Master Target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the Master Target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the Process Server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the Process Server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the retention drive to use on the MT. + * + * @return the retentionDrive value + */ + public String retentionDrive() { + return this.retentionDrive; + } + + /** + * Set the retention drive to use on the MT. + * + * @param retentionDrive the retentionDrive value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withRetentionDrive(String retentionDrive) { + this.retentionDrive = retentionDrive; + return this; + } + + /** + * Get the CS account Id. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS account Id. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + + /** + * Get the multi vm group Id. + * + * @return the multiVmGroupId value + */ + public String multiVmGroupId() { + return this.multiVmGroupId; + } + + /** + * Set the multi vm group Id. + * + * @param multiVmGroupId the multiVmGroupId value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withMultiVmGroupId(String multiVmGroupId) { + this.multiVmGroupId = multiVmGroupId; + return this; + } + + /** + * Get the multi vm group name. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get the target data store name. + * + * @return the datastoreName value + */ + public String datastoreName() { + return this.datastoreName; + } + + /** + * Set the target data store name. + * + * @param datastoreName the datastoreName value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withDatastoreName(String datastoreName) { + this.datastoreName = datastoreName; + return this; + } + + /** + * Get the enable disk exclusion input. + * + * @return the diskExclusionInput value + */ + public InMageDiskExclusionInput diskExclusionInput() { + return this.diskExclusionInput; + } + + /** + * Set the enable disk exclusion input. + * + * @param diskExclusionInput the diskExclusionInput value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withDiskExclusionInput(InMageDiskExclusionInput diskExclusionInput) { + this.diskExclusionInput = diskExclusionInput; + return this; + } + + /** + * Get the disks to include list. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the disks to include list. + * + * @param disksToInclude the disksToInclude value to set + * @return the InMageEnableProtectionInput object itself. + */ + public InMageEnableProtectionInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageFailoverProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageFailoverProviderInput.java new file mode 100644 index 0000000000000..6d0bacb5053a9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageFailoverProviderInput.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Provider specific input for InMage failover. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMageFailoverProviderInput extends ProviderSpecificFailoverInput { + /** + * The recovery point type. Values from LatestTime, LatestTag or Custom. In + * the case of custom, the recovery point provided by RecoveryPointId will + * be used. In the other two cases, recovery point id will be ignored. + * Possible values include: 'LatestTime', 'LatestTag', 'Custom'. + */ + @JsonProperty(value = "recoveryPointType") + private RecoveryPointType recoveryPointType; + + /** + * The recovery point id to be passed to failover to a particular recovery + * point. In case of latest recovery point, null should be passed. + */ + @JsonProperty(value = "recoveryPointId") + private String recoveryPointId; + + /** + * Get the recovery point type. Values from LatestTime, LatestTag or Custom. In the case of custom, the recovery point provided by RecoveryPointId will be used. In the other two cases, recovery point id will be ignored. Possible values include: 'LatestTime', 'LatestTag', 'Custom'. + * + * @return the recoveryPointType value + */ + public RecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type. Values from LatestTime, LatestTag or Custom. In the case of custom, the recovery point provided by RecoveryPointId will be used. In the other two cases, recovery point id will be ignored. Possible values include: 'LatestTime', 'LatestTag', 'Custom'. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the InMageFailoverProviderInput object itself. + */ + public InMageFailoverProviderInput withRecoveryPointType(RecoveryPointType recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + + /** + * Get the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point id to be passed to failover to a particular recovery point. In case of latest recovery point, null should be passed. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the InMageFailoverProviderInput object itself. + */ + public InMageFailoverProviderInput withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyDetails.java new file mode 100644 index 0000000000000..0a949924c4946 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyDetails.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage specific protection profile details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMagePolicyDetails extends PolicyProviderSpecificDetails { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the InMagePolicyDetails object itself. + */ + public InMagePolicyDetails withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the InMagePolicyDetails object itself. + */ + public InMagePolicyDetails withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the InMagePolicyDetails object itself. + */ + public InMagePolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMagePolicyDetails object itself. + */ + public InMagePolicyDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyInput.java new file mode 100644 index 0000000000000..6fbc1834af9cf --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMagePolicyInput.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMWare Azure specific protection profile Input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMagePolicyInput extends PolicyProviderSpecificInput { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. Value should + * be 'Enabled' or 'Disabled'. Possible values include: 'Enable', + * 'Disable'. + */ + @JsonProperty(value = "multiVmSyncStatus", required = true) + private SetMultiVmSyncStatus multiVmSyncStatus; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the InMagePolicyInput object itself. + */ + public InMagePolicyInput withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the InMagePolicyInput object itself. + */ + public InMagePolicyInput withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency (in minutes). + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency (in minutes). + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the InMagePolicyInput object itself. + */ + public InMagePolicyInput withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @return the multiVmSyncStatus value + */ + public SetMultiVmSyncStatus multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. Value should be 'Enabled' or 'Disabled'. Possible values include: 'Enable', 'Disable'. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMagePolicyInput object itself. + */ + public InMagePolicyInput withMultiVmSyncStatus(SetMultiVmSyncStatus multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageProtectedDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageProtectedDiskDetails.java new file mode 100644 index 0000000000000..d78960aa05d17 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageProtectedDiskDetails.java @@ -0,0 +1,408 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * InMage protected disk details. + */ +public class InMageProtectedDiskDetails { + /** + * The disk id. + */ + @JsonProperty(value = "diskId") + private String diskId; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName") + private String diskName; + + /** + * The protection stage. + */ + @JsonProperty(value = "protectionStage") + private String protectionStage; + + /** + * The health error code for the disk. + */ + @JsonProperty(value = "healthErrorCode") + private String healthErrorCode; + + /** + * The RPO in seconds. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * A value indicating whether resync is required for this disk. + */ + @JsonProperty(value = "resyncRequired") + private String resyncRequired; + + /** + * The resync progress percentage. + */ + @JsonProperty(value = "resyncProgressPercentage") + private Integer resyncProgressPercentage; + + /** + * The resync duration in seconds. + */ + @JsonProperty(value = "resyncDurationInSeconds") + private Long resyncDurationInSeconds; + + /** + * The disk capacity in bytes. + */ + @JsonProperty(value = "diskCapacityInBytes") + private Long diskCapacityInBytes; + + /** + * The file system capacity in bytes. + */ + @JsonProperty(value = "fileSystemCapacityInBytes") + private Long fileSystemCapacityInBytes; + + /** + * The source data transit in MB. + */ + @JsonProperty(value = "sourceDataInMB") + private Double sourceDataInMB; + + /** + * The PS data transit in MB. + */ + @JsonProperty(value = "psDataInMB") + private Double psDataInMB; + + /** + * The target data transit in MB. + */ + @JsonProperty(value = "targetDataInMB") + private Double targetDataInMB; + + /** + * A value indicating whether disk is resized. + */ + @JsonProperty(value = "diskResized") + private String diskResized; + + /** + * The last RPO calculated time. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * Get the disk id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk id. + * + * @param diskId the diskId value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Set the disk name. + * + * @param diskName the diskName value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withDiskName(String diskName) { + this.diskName = diskName; + return this; + } + + /** + * Get the protection stage. + * + * @return the protectionStage value + */ + public String protectionStage() { + return this.protectionStage; + } + + /** + * Set the protection stage. + * + * @param protectionStage the protectionStage value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withProtectionStage(String protectionStage) { + this.protectionStage = protectionStage; + return this; + } + + /** + * Get the health error code for the disk. + * + * @return the healthErrorCode value + */ + public String healthErrorCode() { + return this.healthErrorCode; + } + + /** + * Set the health error code for the disk. + * + * @param healthErrorCode the healthErrorCode value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withHealthErrorCode(String healthErrorCode) { + this.healthErrorCode = healthErrorCode; + return this; + } + + /** + * Get the RPO in seconds. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set the RPO in seconds. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get a value indicating whether resync is required for this disk. + * + * @return the resyncRequired value + */ + public String resyncRequired() { + return this.resyncRequired; + } + + /** + * Set a value indicating whether resync is required for this disk. + * + * @param resyncRequired the resyncRequired value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withResyncRequired(String resyncRequired) { + this.resyncRequired = resyncRequired; + return this; + } + + /** + * Get the resync progress percentage. + * + * @return the resyncProgressPercentage value + */ + public Integer resyncProgressPercentage() { + return this.resyncProgressPercentage; + } + + /** + * Set the resync progress percentage. + * + * @param resyncProgressPercentage the resyncProgressPercentage value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withResyncProgressPercentage(Integer resyncProgressPercentage) { + this.resyncProgressPercentage = resyncProgressPercentage; + return this; + } + + /** + * Get the resync duration in seconds. + * + * @return the resyncDurationInSeconds value + */ + public Long resyncDurationInSeconds() { + return this.resyncDurationInSeconds; + } + + /** + * Set the resync duration in seconds. + * + * @param resyncDurationInSeconds the resyncDurationInSeconds value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withResyncDurationInSeconds(Long resyncDurationInSeconds) { + this.resyncDurationInSeconds = resyncDurationInSeconds; + return this; + } + + /** + * Get the disk capacity in bytes. + * + * @return the diskCapacityInBytes value + */ + public Long diskCapacityInBytes() { + return this.diskCapacityInBytes; + } + + /** + * Set the disk capacity in bytes. + * + * @param diskCapacityInBytes the diskCapacityInBytes value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withDiskCapacityInBytes(Long diskCapacityInBytes) { + this.diskCapacityInBytes = diskCapacityInBytes; + return this; + } + + /** + * Get the file system capacity in bytes. + * + * @return the fileSystemCapacityInBytes value + */ + public Long fileSystemCapacityInBytes() { + return this.fileSystemCapacityInBytes; + } + + /** + * Set the file system capacity in bytes. + * + * @param fileSystemCapacityInBytes the fileSystemCapacityInBytes value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withFileSystemCapacityInBytes(Long fileSystemCapacityInBytes) { + this.fileSystemCapacityInBytes = fileSystemCapacityInBytes; + return this; + } + + /** + * Get the source data transit in MB. + * + * @return the sourceDataInMB value + */ + public Double sourceDataInMB() { + return this.sourceDataInMB; + } + + /** + * Set the source data transit in MB. + * + * @param sourceDataInMB the sourceDataInMB value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withSourceDataInMB(Double sourceDataInMB) { + this.sourceDataInMB = sourceDataInMB; + return this; + } + + /** + * Get the PS data transit in MB. + * + * @return the psDataInMB value + */ + public Double psDataInMB() { + return this.psDataInMB; + } + + /** + * Set the PS data transit in MB. + * + * @param psDataInMB the psDataInMB value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withPsDataInMB(Double psDataInMB) { + this.psDataInMB = psDataInMB; + return this; + } + + /** + * Get the target data transit in MB. + * + * @return the targetDataInMB value + */ + public Double targetDataInMB() { + return this.targetDataInMB; + } + + /** + * Set the target data transit in MB. + * + * @param targetDataInMB the targetDataInMB value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withTargetDataInMB(Double targetDataInMB) { + this.targetDataInMB = targetDataInMB; + return this; + } + + /** + * Get a value indicating whether disk is resized. + * + * @return the diskResized value + */ + public String diskResized() { + return this.diskResized; + } + + /** + * Set a value indicating whether disk is resized. + * + * @param diskResized the diskResized value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withDiskResized(String diskResized) { + this.diskResized = diskResized; + return this; + } + + /** + * Get the last RPO calculated time. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the last RPO calculated time. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the InMageProtectedDiskDetails object itself. + */ + public InMageProtectedDiskDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReplicationDetails.java new file mode 100644 index 0000000000000..9cbf438567a2f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReplicationDetails.java @@ -0,0 +1,992 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMage provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMageReplicationDetails extends ReplicationProviderSpecificSettings { + /** + * The active location of the VM. If the VM is being protected from Azure, + * this field will take values from { Azure, OnPrem }. If the VM is being + * protected between two data-centers, this field will be OnPrem always. + */ + @JsonProperty(value = "activeSiteType") + private String activeSiteType; + + /** + * The CPU count of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmCpuCount") + private Integer sourceVmCpuCount; + + /** + * The RAM size of the VM on the primary side. + */ + @JsonProperty(value = "sourceVmRamSizeInMB") + private Integer sourceVmRamSizeInMB; + + /** + * The OS details. + */ + @JsonProperty(value = "osDetails") + private OSDiskDetails osDetails; + + /** + * The protection stage. + */ + @JsonProperty(value = "protectionStage") + private String protectionStage; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * The protection state for the vm. + */ + @JsonProperty(value = "vmProtectionState") + private String vmProtectionState; + + /** + * The protection state description for the vm. + */ + @JsonProperty(value = "vmProtectionStateDescription") + private String vmProtectionStateDescription; + + /** + * The resync details of the machine. + */ + @JsonProperty(value = "resyncDetails") + private InitialReplicationDetails resyncDetails; + + /** + * The retention window start time. + */ + @JsonProperty(value = "retentionWindowStart") + private DateTime retentionWindowStart; + + /** + * The retention window end time. + */ + @JsonProperty(value = "retentionWindowEnd") + private DateTime retentionWindowEnd; + + /** + * The compressed data change rate in MB. + */ + @JsonProperty(value = "compressedDataRateInMB") + private Double compressedDataRateInMB; + + /** + * The uncompressed data change rate in MB. + */ + @JsonProperty(value = "uncompressedDataRateInMB") + private Double uncompressedDataRateInMB; + + /** + * The RPO in seconds. + */ + @JsonProperty(value = "rpoInSeconds") + private Long rpoInSeconds; + + /** + * The list of protected disks. + */ + @JsonProperty(value = "protectedDisks") + private List protectedDisks; + + /** + * The source IP address. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The last heartbeat received from the source server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * The process server Id. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The master target Id. + */ + @JsonProperty(value = "masterTargetId") + private String masterTargetId; + + /** + * The collection of Consistency points. + */ + @JsonProperty(value = "consistencyPoints") + private Map consistencyPoints; + + /** + * A value indicating whether any disk is resized for this VM. + */ + @JsonProperty(value = "diskResized") + private String diskResized; + + /** + * A value indicating whether the source server requires a restart after + * update. + */ + @JsonProperty(value = "rebootAfterUpdateStatus") + private String rebootAfterUpdateStatus; + + /** + * The multi vm group Id, if any. + */ + @JsonProperty(value = "multiVmGroupId") + private String multiVmGroupId; + + /** + * The multi vm group name, if any. + */ + @JsonProperty(value = "multiVmGroupName") + private String multiVmGroupName; + + /** + * A value indicating whether the multi vm sync is enabled or disabled. + */ + @JsonProperty(value = "multiVmSyncStatus") + private String multiVmSyncStatus; + + /** + * The agent details. + */ + @JsonProperty(value = "agentDetails") + private InMageAgentDetails agentDetails; + + /** + * The vCenter infrastructure Id. + */ + @JsonProperty(value = "vCenterInfrastructureId") + private String vCenterInfrastructureId; + + /** + * The infrastructure VM Id. + */ + @JsonProperty(value = "infrastructureVmId") + private String infrastructureVmId; + + /** + * The PE Network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * A value indicating the discovery type of the machine. + */ + @JsonProperty(value = "discoveryType") + private String discoveryType; + + /** + * A value indicating the underlying Azure storage account. If the VM is + * not running in Azure, this value shall be set to null. + */ + @JsonProperty(value = "azureStorageAccountId") + private String azureStorageAccountId; + + /** + * The data stores of the on-premise machine Value can be list of strings + * that contain data store names. + */ + @JsonProperty(value = "datastores") + private List datastores; + + /** + * The validation errors of the on-premise machine Value can be list of + * validation errors. + */ + @JsonProperty(value = "validationErrors") + private List validationErrors; + + /** + * The last RPO calculated time. + */ + @JsonProperty(value = "lastRpoCalculatedTime") + private DateTime lastRpoCalculatedTime; + + /** + * The last update time received from on-prem components. + */ + @JsonProperty(value = "lastUpdateReceivedTime") + private DateTime lastUpdateReceivedTime; + + /** + * The replica id of the protected item. + */ + @JsonProperty(value = "replicaId") + private String replicaId; + + /** + * The OS Version of the protected item. + */ + @JsonProperty(value = "osVersion") + private String osVersion; + + /** + * Get the active location of the VM. If the VM is being protected from Azure, this field will take values from { Azure, OnPrem }. If the VM is being protected between two data-centers, this field will be OnPrem always. + * + * @return the activeSiteType value + */ + public String activeSiteType() { + return this.activeSiteType; + } + + /** + * Set the active location of the VM. If the VM is being protected from Azure, this field will take values from { Azure, OnPrem }. If the VM is being protected between two data-centers, this field will be OnPrem always. + * + * @param activeSiteType the activeSiteType value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withActiveSiteType(String activeSiteType) { + this.activeSiteType = activeSiteType; + return this; + } + + /** + * Get the CPU count of the VM on the primary side. + * + * @return the sourceVmCpuCount value + */ + public Integer sourceVmCpuCount() { + return this.sourceVmCpuCount; + } + + /** + * Set the CPU count of the VM on the primary side. + * + * @param sourceVmCpuCount the sourceVmCpuCount value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withSourceVmCpuCount(Integer sourceVmCpuCount) { + this.sourceVmCpuCount = sourceVmCpuCount; + return this; + } + + /** + * Get the RAM size of the VM on the primary side. + * + * @return the sourceVmRamSizeInMB value + */ + public Integer sourceVmRamSizeInMB() { + return this.sourceVmRamSizeInMB; + } + + /** + * Set the RAM size of the VM on the primary side. + * + * @param sourceVmRamSizeInMB the sourceVmRamSizeInMB value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withSourceVmRamSizeInMB(Integer sourceVmRamSizeInMB) { + this.sourceVmRamSizeInMB = sourceVmRamSizeInMB; + return this; + } + + /** + * Get the OS details. + * + * @return the osDetails value + */ + public OSDiskDetails osDetails() { + return this.osDetails; + } + + /** + * Set the OS details. + * + * @param osDetails the osDetails value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withOsDetails(OSDiskDetails osDetails) { + this.osDetails = osDetails; + return this; + } + + /** + * Get the protection stage. + * + * @return the protectionStage value + */ + public String protectionStage() { + return this.protectionStage; + } + + /** + * Set the protection stage. + * + * @param protectionStage the protectionStage value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withProtectionStage(String protectionStage) { + this.protectionStage = protectionStage; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set the virtual machine Id. + * + * @param vmId the vmId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get the protection state for the vm. + * + * @return the vmProtectionState value + */ + public String vmProtectionState() { + return this.vmProtectionState; + } + + /** + * Set the protection state for the vm. + * + * @param vmProtectionState the vmProtectionState value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withVmProtectionState(String vmProtectionState) { + this.vmProtectionState = vmProtectionState; + return this; + } + + /** + * Get the protection state description for the vm. + * + * @return the vmProtectionStateDescription value + */ + public String vmProtectionStateDescription() { + return this.vmProtectionStateDescription; + } + + /** + * Set the protection state description for the vm. + * + * @param vmProtectionStateDescription the vmProtectionStateDescription value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withVmProtectionStateDescription(String vmProtectionStateDescription) { + this.vmProtectionStateDescription = vmProtectionStateDescription; + return this; + } + + /** + * Get the resync details of the machine. + * + * @return the resyncDetails value + */ + public InitialReplicationDetails resyncDetails() { + return this.resyncDetails; + } + + /** + * Set the resync details of the machine. + * + * @param resyncDetails the resyncDetails value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withResyncDetails(InitialReplicationDetails resyncDetails) { + this.resyncDetails = resyncDetails; + return this; + } + + /** + * Get the retention window start time. + * + * @return the retentionWindowStart value + */ + public DateTime retentionWindowStart() { + return this.retentionWindowStart; + } + + /** + * Set the retention window start time. + * + * @param retentionWindowStart the retentionWindowStart value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withRetentionWindowStart(DateTime retentionWindowStart) { + this.retentionWindowStart = retentionWindowStart; + return this; + } + + /** + * Get the retention window end time. + * + * @return the retentionWindowEnd value + */ + public DateTime retentionWindowEnd() { + return this.retentionWindowEnd; + } + + /** + * Set the retention window end time. + * + * @param retentionWindowEnd the retentionWindowEnd value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withRetentionWindowEnd(DateTime retentionWindowEnd) { + this.retentionWindowEnd = retentionWindowEnd; + return this; + } + + /** + * Get the compressed data change rate in MB. + * + * @return the compressedDataRateInMB value + */ + public Double compressedDataRateInMB() { + return this.compressedDataRateInMB; + } + + /** + * Set the compressed data change rate in MB. + * + * @param compressedDataRateInMB the compressedDataRateInMB value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withCompressedDataRateInMB(Double compressedDataRateInMB) { + this.compressedDataRateInMB = compressedDataRateInMB; + return this; + } + + /** + * Get the uncompressed data change rate in MB. + * + * @return the uncompressedDataRateInMB value + */ + public Double uncompressedDataRateInMB() { + return this.uncompressedDataRateInMB; + } + + /** + * Set the uncompressed data change rate in MB. + * + * @param uncompressedDataRateInMB the uncompressedDataRateInMB value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withUncompressedDataRateInMB(Double uncompressedDataRateInMB) { + this.uncompressedDataRateInMB = uncompressedDataRateInMB; + return this; + } + + /** + * Get the RPO in seconds. + * + * @return the rpoInSeconds value + */ + public Long rpoInSeconds() { + return this.rpoInSeconds; + } + + /** + * Set the RPO in seconds. + * + * @param rpoInSeconds the rpoInSeconds value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withRpoInSeconds(Long rpoInSeconds) { + this.rpoInSeconds = rpoInSeconds; + return this; + } + + /** + * Get the list of protected disks. + * + * @return the protectedDisks value + */ + public List protectedDisks() { + return this.protectedDisks; + } + + /** + * Set the list of protected disks. + * + * @param protectedDisks the protectedDisks value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withProtectedDisks(List protectedDisks) { + this.protectedDisks = protectedDisks; + return this; + } + + /** + * Get the source IP address. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the source IP address. + * + * @param ipAddress the ipAddress value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the last heartbeat received from the source server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from the source server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get the process server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the process server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the master target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the master target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the collection of Consistency points. + * + * @return the consistencyPoints value + */ + public Map consistencyPoints() { + return this.consistencyPoints; + } + + /** + * Set the collection of Consistency points. + * + * @param consistencyPoints the consistencyPoints value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withConsistencyPoints(Map consistencyPoints) { + this.consistencyPoints = consistencyPoints; + return this; + } + + /** + * Get a value indicating whether any disk is resized for this VM. + * + * @return the diskResized value + */ + public String diskResized() { + return this.diskResized; + } + + /** + * Set a value indicating whether any disk is resized for this VM. + * + * @param diskResized the diskResized value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withDiskResized(String diskResized) { + this.diskResized = diskResized; + return this; + } + + /** + * Get a value indicating whether the source server requires a restart after update. + * + * @return the rebootAfterUpdateStatus value + */ + public String rebootAfterUpdateStatus() { + return this.rebootAfterUpdateStatus; + } + + /** + * Set a value indicating whether the source server requires a restart after update. + * + * @param rebootAfterUpdateStatus the rebootAfterUpdateStatus value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withRebootAfterUpdateStatus(String rebootAfterUpdateStatus) { + this.rebootAfterUpdateStatus = rebootAfterUpdateStatus; + return this; + } + + /** + * Get the multi vm group Id, if any. + * + * @return the multiVmGroupId value + */ + public String multiVmGroupId() { + return this.multiVmGroupId; + } + + /** + * Set the multi vm group Id, if any. + * + * @param multiVmGroupId the multiVmGroupId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withMultiVmGroupId(String multiVmGroupId) { + this.multiVmGroupId = multiVmGroupId; + return this; + } + + /** + * Get the multi vm group name, if any. + * + * @return the multiVmGroupName value + */ + public String multiVmGroupName() { + return this.multiVmGroupName; + } + + /** + * Set the multi vm group name, if any. + * + * @param multiVmGroupName the multiVmGroupName value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withMultiVmGroupName(String multiVmGroupName) { + this.multiVmGroupName = multiVmGroupName; + return this; + } + + /** + * Get a value indicating whether the multi vm sync is enabled or disabled. + * + * @return the multiVmSyncStatus value + */ + public String multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether the multi vm sync is enabled or disabled. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withMultiVmSyncStatus(String multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + + /** + * Get the agent details. + * + * @return the agentDetails value + */ + public InMageAgentDetails agentDetails() { + return this.agentDetails; + } + + /** + * Set the agent details. + * + * @param agentDetails the agentDetails value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withAgentDetails(InMageAgentDetails agentDetails) { + this.agentDetails = agentDetails; + return this; + } + + /** + * Get the vCenter infrastructure Id. + * + * @return the vCenterInfrastructureId value + */ + public String vCenterInfrastructureId() { + return this.vCenterInfrastructureId; + } + + /** + * Set the vCenter infrastructure Id. + * + * @param vCenterInfrastructureId the vCenterInfrastructureId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withVCenterInfrastructureId(String vCenterInfrastructureId) { + this.vCenterInfrastructureId = vCenterInfrastructureId; + return this; + } + + /** + * Get the infrastructure VM Id. + * + * @return the infrastructureVmId value + */ + public String infrastructureVmId() { + return this.infrastructureVmId; + } + + /** + * Set the infrastructure VM Id. + * + * @param infrastructureVmId the infrastructureVmId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withInfrastructureVmId(String infrastructureVmId) { + this.infrastructureVmId = infrastructureVmId; + return this; + } + + /** + * Get the PE Network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the PE Network details. + * + * @param vmNics the vmNics value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get a value indicating the discovery type of the machine. + * + * @return the discoveryType value + */ + public String discoveryType() { + return this.discoveryType; + } + + /** + * Set a value indicating the discovery type of the machine. + * + * @param discoveryType the discoveryType value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withDiscoveryType(String discoveryType) { + this.discoveryType = discoveryType; + return this; + } + + /** + * Get a value indicating the underlying Azure storage account. If the VM is not running in Azure, this value shall be set to null. + * + * @return the azureStorageAccountId value + */ + public String azureStorageAccountId() { + return this.azureStorageAccountId; + } + + /** + * Set a value indicating the underlying Azure storage account. If the VM is not running in Azure, this value shall be set to null. + * + * @param azureStorageAccountId the azureStorageAccountId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withAzureStorageAccountId(String azureStorageAccountId) { + this.azureStorageAccountId = azureStorageAccountId; + return this; + } + + /** + * Get the data stores of the on-premise machine Value can be list of strings that contain data store names. + * + * @return the datastores value + */ + public List datastores() { + return this.datastores; + } + + /** + * Set the data stores of the on-premise machine Value can be list of strings that contain data store names. + * + * @param datastores the datastores value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withDatastores(List datastores) { + this.datastores = datastores; + return this; + } + + /** + * Get the validation errors of the on-premise machine Value can be list of validation errors. + * + * @return the validationErrors value + */ + public List validationErrors() { + return this.validationErrors; + } + + /** + * Set the validation errors of the on-premise machine Value can be list of validation errors. + * + * @param validationErrors the validationErrors value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withValidationErrors(List validationErrors) { + this.validationErrors = validationErrors; + return this; + } + + /** + * Get the last RPO calculated time. + * + * @return the lastRpoCalculatedTime value + */ + public DateTime lastRpoCalculatedTime() { + return this.lastRpoCalculatedTime; + } + + /** + * Set the last RPO calculated time. + * + * @param lastRpoCalculatedTime the lastRpoCalculatedTime value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withLastRpoCalculatedTime(DateTime lastRpoCalculatedTime) { + this.lastRpoCalculatedTime = lastRpoCalculatedTime; + return this; + } + + /** + * Get the last update time received from on-prem components. + * + * @return the lastUpdateReceivedTime value + */ + public DateTime lastUpdateReceivedTime() { + return this.lastUpdateReceivedTime; + } + + /** + * Set the last update time received from on-prem components. + * + * @param lastUpdateReceivedTime the lastUpdateReceivedTime value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withLastUpdateReceivedTime(DateTime lastUpdateReceivedTime) { + this.lastUpdateReceivedTime = lastUpdateReceivedTime; + return this; + } + + /** + * Get the replica id of the protected item. + * + * @return the replicaId value + */ + public String replicaId() { + return this.replicaId; + } + + /** + * Set the replica id of the protected item. + * + * @param replicaId the replicaId value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withReplicaId(String replicaId) { + this.replicaId = replicaId; + return this; + } + + /** + * Get the OS Version of the protected item. + * + * @return the osVersion value + */ + public String osVersion() { + return this.osVersion; + } + + /** + * Set the OS Version of the protected item. + * + * @param osVersion the osVersion value to set + * @return the InMageReplicationDetails object itself. + */ + public InMageReplicationDetails withOsVersion(String osVersion) { + this.osVersion = osVersion; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReprotectInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReprotectInput.java new file mode 100644 index 0000000000000..817ac731d9edd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageReprotectInput.java @@ -0,0 +1,230 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * InMageAzureV2 specific provider input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class InMageReprotectInput extends ReverseReplicationProviderSpecificInput { + /** + * The Master Target Id. + */ + @JsonProperty(value = "masterTargetId", required = true) + private String masterTargetId; + + /** + * The Process Server Id. + */ + @JsonProperty(value = "processServerId", required = true) + private String processServerId; + + /** + * The retention drive to use on the MT. + */ + @JsonProperty(value = "retentionDrive", required = true) + private String retentionDrive; + + /** + * The CS account Id. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * The target data store name. + */ + @JsonProperty(value = "datastoreName") + private String datastoreName; + + /** + * The enable disk exclusion input. + */ + @JsonProperty(value = "diskExclusionInput") + private InMageDiskExclusionInput diskExclusionInput; + + /** + * The Policy Id. + */ + @JsonProperty(value = "profileId", required = true) + private String profileId; + + /** + * The disks to include list. + */ + @JsonProperty(value = "disksToInclude") + private List disksToInclude; + + /** + * Get the Master Target Id. + * + * @return the masterTargetId value + */ + public String masterTargetId() { + return this.masterTargetId; + } + + /** + * Set the Master Target Id. + * + * @param masterTargetId the masterTargetId value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withMasterTargetId(String masterTargetId) { + this.masterTargetId = masterTargetId; + return this; + } + + /** + * Get the Process Server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the Process Server Id. + * + * @param processServerId the processServerId value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the retention drive to use on the MT. + * + * @return the retentionDrive value + */ + public String retentionDrive() { + return this.retentionDrive; + } + + /** + * Set the retention drive to use on the MT. + * + * @param retentionDrive the retentionDrive value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withRetentionDrive(String retentionDrive) { + this.retentionDrive = retentionDrive; + return this; + } + + /** + * Get the CS account Id. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS account Id. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + + /** + * Get the target data store name. + * + * @return the datastoreName value + */ + public String datastoreName() { + return this.datastoreName; + } + + /** + * Set the target data store name. + * + * @param datastoreName the datastoreName value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withDatastoreName(String datastoreName) { + this.datastoreName = datastoreName; + return this; + } + + /** + * Get the enable disk exclusion input. + * + * @return the diskExclusionInput value + */ + public InMageDiskExclusionInput diskExclusionInput() { + return this.diskExclusionInput; + } + + /** + * Set the enable disk exclusion input. + * + * @param diskExclusionInput the diskExclusionInput value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withDiskExclusionInput(InMageDiskExclusionInput diskExclusionInput) { + this.diskExclusionInput = diskExclusionInput; + return this; + } + + /** + * Get the Policy Id. + * + * @return the profileId value + */ + public String profileId() { + return this.profileId; + } + + /** + * Set the Policy Id. + * + * @param profileId the profileId value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withProfileId(String profileId) { + this.profileId = profileId; + return this; + } + + /** + * Get the disks to include list. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the disks to include list. + * + * @param disksToInclude the disksToInclude value to set + * @return the InMageReprotectInput object itself. + */ + public InMageReprotectInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageV2RpRecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageV2RpRecoveryPointType.java new file mode 100644 index 0000000000000..421eae03a0586 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageV2RpRecoveryPointType.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for InMageV2RpRecoveryPointType. + */ +public final class InMageV2RpRecoveryPointType extends ExpandableStringEnum { + /** Static value Latest for InMageV2RpRecoveryPointType. */ + public static final InMageV2RpRecoveryPointType LATEST = fromString("Latest"); + + /** Static value LatestApplicationConsistent for InMageV2RpRecoveryPointType. */ + public static final InMageV2RpRecoveryPointType LATEST_APPLICATION_CONSISTENT = fromString("LatestApplicationConsistent"); + + /** Static value LatestCrashConsistent for InMageV2RpRecoveryPointType. */ + public static final InMageV2RpRecoveryPointType LATEST_CRASH_CONSISTENT = fromString("LatestCrashConsistent"); + + /** Static value LatestProcessed for InMageV2RpRecoveryPointType. */ + public static final InMageV2RpRecoveryPointType LATEST_PROCESSED = fromString("LatestProcessed"); + + /** + * Creates or finds a InMageV2RpRecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding InMageV2RpRecoveryPointType + */ + @JsonCreator + public static InMageV2RpRecoveryPointType fromString(String name) { + return fromString(name, InMageV2RpRecoveryPointType.class); + } + + /** + * @return known InMageV2RpRecoveryPointType values + */ + public static Collection values() { + return values(InMageV2RpRecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageVolumeExclusionOptions.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageVolumeExclusionOptions.java new file mode 100644 index 0000000000000..aa55f067b4d02 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InMageVolumeExclusionOptions.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Guest disk signature based disk exclusion option when doing enable + * protection of virtual machine in InMage provider. + */ +public class InMageVolumeExclusionOptions { + /** + * The volume label. The disk having any volume with this label will be + * excluded from replication. + */ + @JsonProperty(value = "volumeLabel") + private String volumeLabel; + + /** + * The value indicating whether to exclude multi volume disk or not. If a + * disk has multiple volumes and one of the volume has label matching with + * VolumeLabel this disk will be excluded from replication if + * OnlyExcludeIfSingleVolume is false. + */ + @JsonProperty(value = "onlyExcludeIfSingleVolume") + private String onlyExcludeIfSingleVolume; + + /** + * Get the volume label. The disk having any volume with this label will be excluded from replication. + * + * @return the volumeLabel value + */ + public String volumeLabel() { + return this.volumeLabel; + } + + /** + * Set the volume label. The disk having any volume with this label will be excluded from replication. + * + * @param volumeLabel the volumeLabel value to set + * @return the InMageVolumeExclusionOptions object itself. + */ + public InMageVolumeExclusionOptions withVolumeLabel(String volumeLabel) { + this.volumeLabel = volumeLabel; + return this; + } + + /** + * Get the value indicating whether to exclude multi volume disk or not. If a disk has multiple volumes and one of the volume has label matching with VolumeLabel this disk will be excluded from replication if OnlyExcludeIfSingleVolume is false. + * + * @return the onlyExcludeIfSingleVolume value + */ + public String onlyExcludeIfSingleVolume() { + return this.onlyExcludeIfSingleVolume; + } + + /** + * Set the value indicating whether to exclude multi volume disk or not. If a disk has multiple volumes and one of the volume has label matching with VolumeLabel this disk will be excluded from replication if OnlyExcludeIfSingleVolume is false. + * + * @param onlyExcludeIfSingleVolume the onlyExcludeIfSingleVolume value to set + * @return the InMageVolumeExclusionOptions object itself. + */ + public InMageVolumeExclusionOptions withOnlyExcludeIfSingleVolume(String onlyExcludeIfSingleVolume) { + this.onlyExcludeIfSingleVolume = onlyExcludeIfSingleVolume; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InconsistentVmDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InconsistentVmDetails.java new file mode 100644 index 0000000000000..fdd156ec51527 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InconsistentVmDetails.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * This class stores the monitoring details for consistency check of + * inconsistent Protected Entity. + */ +public class InconsistentVmDetails { + /** + * The Vm name. + */ + @JsonProperty(value = "vmName") + private String vmName; + + /** + * The Cloud name. + */ + @JsonProperty(value = "cloudName") + private String cloudName; + + /** + * The list of details regarding state of the Protected Entity in SRS and + * On prem. + */ + @JsonProperty(value = "details") + private List details; + + /** + * The list of error ids. + */ + @JsonProperty(value = "errorIds") + private List errorIds; + + /** + * Get the Vm name. + * + * @return the vmName value + */ + public String vmName() { + return this.vmName; + } + + /** + * Set the Vm name. + * + * @param vmName the vmName value to set + * @return the InconsistentVmDetails object itself. + */ + public InconsistentVmDetails withVmName(String vmName) { + this.vmName = vmName; + return this; + } + + /** + * Get the Cloud name. + * + * @return the cloudName value + */ + public String cloudName() { + return this.cloudName; + } + + /** + * Set the Cloud name. + * + * @param cloudName the cloudName value to set + * @return the InconsistentVmDetails object itself. + */ + public InconsistentVmDetails withCloudName(String cloudName) { + this.cloudName = cloudName; + return this; + } + + /** + * Get the list of details regarding state of the Protected Entity in SRS and On prem. + * + * @return the details value + */ + public List details() { + return this.details; + } + + /** + * Set the list of details regarding state of the Protected Entity in SRS and On prem. + * + * @param details the details value to set + * @return the InconsistentVmDetails object itself. + */ + public InconsistentVmDetails withDetails(List details) { + this.details = details; + return this; + } + + /** + * Get the list of error ids. + * + * @return the errorIds value + */ + public List errorIds() { + return this.errorIds; + } + + /** + * Set the list of error ids. + * + * @param errorIds the errorIds value to set + * @return the InconsistentVmDetails object itself. + */ + public InconsistentVmDetails withErrorIds(List errorIds) { + this.errorIds = errorIds; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InitialReplicationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InitialReplicationDetails.java new file mode 100644 index 0000000000000..bd5e425b8fceb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InitialReplicationDetails.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Initial replication details. + */ +public class InitialReplicationDetails { + /** + * Initial replication type. + */ + @JsonProperty(value = "initialReplicationType") + private String initialReplicationType; + + /** + * The initial replication progress percentage. + */ + @JsonProperty(value = "initialReplicationProgressPercentage") + private String initialReplicationProgressPercentage; + + /** + * Get initial replication type. + * + * @return the initialReplicationType value + */ + public String initialReplicationType() { + return this.initialReplicationType; + } + + /** + * Set initial replication type. + * + * @param initialReplicationType the initialReplicationType value to set + * @return the InitialReplicationDetails object itself. + */ + public InitialReplicationDetails withInitialReplicationType(String initialReplicationType) { + this.initialReplicationType = initialReplicationType; + return this; + } + + /** + * Get the initial replication progress percentage. + * + * @return the initialReplicationProgressPercentage value + */ + public String initialReplicationProgressPercentage() { + return this.initialReplicationProgressPercentage; + } + + /** + * Set the initial replication progress percentage. + * + * @param initialReplicationProgressPercentage the initialReplicationProgressPercentage value to set + * @return the InitialReplicationDetails object itself. + */ + public InitialReplicationDetails withInitialReplicationProgressPercentage(String initialReplicationProgressPercentage) { + this.initialReplicationProgressPercentage = initialReplicationProgressPercentage; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InlineWorkflowTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InlineWorkflowTaskDetails.java new file mode 100644 index 0000000000000..a545c79086885 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InlineWorkflowTaskDetails.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the inline workflow task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InlineWorkflowTaskDetails") +public class InlineWorkflowTaskDetails extends GroupTaskDetails { + /** + * The list of child workflow ids. + */ + @JsonProperty(value = "workflowIds") + private List workflowIds; + + /** + * Get the list of child workflow ids. + * + * @return the workflowIds value + */ + public List workflowIds() { + return this.workflowIds; + } + + /** + * Set the list of child workflow ids. + * + * @param workflowIds the workflowIds value to set + * @return the InlineWorkflowTaskDetails object itself. + */ + public InlineWorkflowTaskDetails withWorkflowIds(List workflowIds) { + this.workflowIds = workflowIds; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InnerHealthError.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InnerHealthError.java new file mode 100644 index 0000000000000..02a084b2e304a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InnerHealthError.java @@ -0,0 +1,335 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Implements InnerHealthError class. HealthError object has a list of + * InnerHealthErrors as child errors. InnerHealthError is used because this + * will prevent an infinite loop of structures when Hydra tries to + * auto-generate the contract. We are exposing the related health errors as + * inner health errors and all API consumers can utilize this in the same + * fashion as Exception -&gt; InnerException. + */ +public class InnerHealthError { + /** + * Source of error. + */ + @JsonProperty(value = "errorSource") + private String errorSource; + + /** + * Type of error. + */ + @JsonProperty(value = "errorType") + private String errorType; + + /** + * Level of error. + */ + @JsonProperty(value = "errorLevel") + private String errorLevel; + + /** + * Category of error. + */ + @JsonProperty(value = "errorCategory") + private String errorCategory; + + /** + * Error code. + */ + @JsonProperty(value = "errorCode") + private String errorCode; + + /** + * Summary message of the entity. + */ + @JsonProperty(value = "summaryMessage") + private String summaryMessage; + + /** + * Error message. + */ + @JsonProperty(value = "errorMessage") + private String errorMessage; + + /** + * Possible causes of error. + */ + @JsonProperty(value = "possibleCauses") + private String possibleCauses; + + /** + * Recommended action to resolve error. + */ + @JsonProperty(value = "recommendedAction") + private String recommendedAction; + + /** + * Error creation time (UTC). + */ + @JsonProperty(value = "creationTimeUtc") + private DateTime creationTimeUtc; + + /** + * DRA error message. + */ + @JsonProperty(value = "recoveryProviderErrorMessage") + private String recoveryProviderErrorMessage; + + /** + * ID of the entity. + */ + @JsonProperty(value = "entityId") + private String entityId; + + /** + * Get source of error. + * + * @return the errorSource value + */ + public String errorSource() { + return this.errorSource; + } + + /** + * Set source of error. + * + * @param errorSource the errorSource value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorSource(String errorSource) { + this.errorSource = errorSource; + return this; + } + + /** + * Get type of error. + * + * @return the errorType value + */ + public String errorType() { + return this.errorType; + } + + /** + * Set type of error. + * + * @param errorType the errorType value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorType(String errorType) { + this.errorType = errorType; + return this; + } + + /** + * Get level of error. + * + * @return the errorLevel value + */ + public String errorLevel() { + return this.errorLevel; + } + + /** + * Set level of error. + * + * @param errorLevel the errorLevel value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorLevel(String errorLevel) { + this.errorLevel = errorLevel; + return this; + } + + /** + * Get category of error. + * + * @return the errorCategory value + */ + public String errorCategory() { + return this.errorCategory; + } + + /** + * Set category of error. + * + * @param errorCategory the errorCategory value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorCategory(String errorCategory) { + this.errorCategory = errorCategory; + return this; + } + + /** + * Get error code. + * + * @return the errorCode value + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set error code. + * + * @param errorCode the errorCode value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * Get summary message of the entity. + * + * @return the summaryMessage value + */ + public String summaryMessage() { + return this.summaryMessage; + } + + /** + * Set summary message of the entity. + * + * @param summaryMessage the summaryMessage value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withSummaryMessage(String summaryMessage) { + this.summaryMessage = summaryMessage; + return this; + } + + /** + * Get error message. + * + * @return the errorMessage value + */ + public String errorMessage() { + return this.errorMessage; + } + + /** + * Set error message. + * + * @param errorMessage the errorMessage value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + return this; + } + + /** + * Get possible causes of error. + * + * @return the possibleCauses value + */ + public String possibleCauses() { + return this.possibleCauses; + } + + /** + * Set possible causes of error. + * + * @param possibleCauses the possibleCauses value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withPossibleCauses(String possibleCauses) { + this.possibleCauses = possibleCauses; + return this; + } + + /** + * Get recommended action to resolve error. + * + * @return the recommendedAction value + */ + public String recommendedAction() { + return this.recommendedAction; + } + + /** + * Set recommended action to resolve error. + * + * @param recommendedAction the recommendedAction value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withRecommendedAction(String recommendedAction) { + this.recommendedAction = recommendedAction; + return this; + } + + /** + * Get error creation time (UTC). + * + * @return the creationTimeUtc value + */ + public DateTime creationTimeUtc() { + return this.creationTimeUtc; + } + + /** + * Set error creation time (UTC). + * + * @param creationTimeUtc the creationTimeUtc value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withCreationTimeUtc(DateTime creationTimeUtc) { + this.creationTimeUtc = creationTimeUtc; + return this; + } + + /** + * Get dRA error message. + * + * @return the recoveryProviderErrorMessage value + */ + public String recoveryProviderErrorMessage() { + return this.recoveryProviderErrorMessage; + } + + /** + * Set dRA error message. + * + * @param recoveryProviderErrorMessage the recoveryProviderErrorMessage value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withRecoveryProviderErrorMessage(String recoveryProviderErrorMessage) { + this.recoveryProviderErrorMessage = recoveryProviderErrorMessage; + return this; + } + + /** + * Get iD of the entity. + * + * @return the entityId value + */ + public String entityId() { + return this.entityId; + } + + /** + * Set iD of the entity. + * + * @param entityId the entityId value to set + * @return the InnerHealthError object itself. + */ + public InnerHealthError withEntityId(String entityId) { + this.entityId = entityId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InputEndpoint.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InputEndpoint.java new file mode 100644 index 0000000000000..bf6d7dbb4e11c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/InputEndpoint.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure VM input endpoint details. + */ +public class InputEndpoint { + /** + * The input endpoint name. + */ + @JsonProperty(value = "endpointName") + private String endpointName; + + /** + * The input endpoint private port. + */ + @JsonProperty(value = "privatePort") + private Integer privatePort; + + /** + * The input endpoint public port. + */ + @JsonProperty(value = "publicPort") + private Integer publicPort; + + /** + * The input endpoint protocol. + */ + @JsonProperty(value = "protocol") + private String protocol; + + /** + * Get the input endpoint name. + * + * @return the endpointName value + */ + public String endpointName() { + return this.endpointName; + } + + /** + * Set the input endpoint name. + * + * @param endpointName the endpointName value to set + * @return the InputEndpoint object itself. + */ + public InputEndpoint withEndpointName(String endpointName) { + this.endpointName = endpointName; + return this; + } + + /** + * Get the input endpoint private port. + * + * @return the privatePort value + */ + public Integer privatePort() { + return this.privatePort; + } + + /** + * Set the input endpoint private port. + * + * @param privatePort the privatePort value to set + * @return the InputEndpoint object itself. + */ + public InputEndpoint withPrivatePort(Integer privatePort) { + this.privatePort = privatePort; + return this; + } + + /** + * Get the input endpoint public port. + * + * @return the publicPort value + */ + public Integer publicPort() { + return this.publicPort; + } + + /** + * Set the input endpoint public port. + * + * @param publicPort the publicPort value to set + * @return the InputEndpoint object itself. + */ + public InputEndpoint withPublicPort(Integer publicPort) { + this.publicPort = publicPort; + return this; + } + + /** + * Get the input endpoint protocol. + * + * @return the protocol value + */ + public String protocol() { + return this.protocol; + } + + /** + * Set the input endpoint protocol. + * + * @param protocol the protocol value to set + * @return the InputEndpoint object itself. + */ + public InputEndpoint withProtocol(String protocol) { + this.protocol = protocol; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Job.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Job.java new file mode 100644 index 0000000000000..b10f3fa303e57 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Job.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.JobInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing Job. + */ +public interface Job extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + JobProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobDetails.java new file mode 100644 index 0000000000000..5ccc406da30e6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobDetails.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Job details based on specific job type. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("JobDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AsrJobDetails", value = AsrJobDetails.class), + @JsonSubTypes.Type(name = "ExportJobDetails", value = ExportJobDetails.class), + @JsonSubTypes.Type(name = "FailoverJobDetails", value = FailoverJobDetails.class), + @JsonSubTypes.Type(name = "SwitchProtectionJobDetails", value = SwitchProtectionJobDetails.class), + @JsonSubTypes.Type(name = "TestFailoverJobDetails", value = TestFailoverJobDetails.class) +}) +public class JobDetails { + /** + * The affected object properties like source server, source cloud, target + * server, target cloud etc. based on the workflow object details. + */ + @JsonProperty(value = "affectedObjectDetails") + private Map affectedObjectDetails; + + /** + * Get the affected object properties like source server, source cloud, target server, target cloud etc. based on the workflow object details. + * + * @return the affectedObjectDetails value + */ + public Map affectedObjectDetails() { + return this.affectedObjectDetails; + } + + /** + * Set the affected object properties like source server, source cloud, target server, target cloud etc. based on the workflow object details. + * + * @param affectedObjectDetails the affectedObjectDetails value to set + * @return the JobDetails object itself. + */ + public JobDetails withAffectedObjectDetails(Map affectedObjectDetails) { + this.affectedObjectDetails = affectedObjectDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobEntity.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobEntity.java new file mode 100644 index 0000000000000..1074b9f5614c0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobEntity.java @@ -0,0 +1,174 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * This class contains the minimal job details required to navigate to the + * desired drill down. + */ +public class JobEntity { + /** + * The job id. + */ + @JsonProperty(value = "jobId") + private String jobId; + + /** + * The job display name. + */ + @JsonProperty(value = "jobFriendlyName") + private String jobFriendlyName; + + /** + * The object id. + */ + @JsonProperty(value = "targetObjectId") + private String targetObjectId; + + /** + * The object name. + */ + @JsonProperty(value = "targetObjectName") + private String targetObjectName; + + /** + * The workflow affected object type. + */ + @JsonProperty(value = "targetInstanceType") + private String targetInstanceType; + + /** + * The job name. Enum type ScenarioName. + */ + @JsonProperty(value = "jobScenarioName") + private String jobScenarioName; + + /** + * Get the job id. + * + * @return the jobId value + */ + public String jobId() { + return this.jobId; + } + + /** + * Set the job id. + * + * @param jobId the jobId value to set + * @return the JobEntity object itself. + */ + public JobEntity withJobId(String jobId) { + this.jobId = jobId; + return this; + } + + /** + * Get the job display name. + * + * @return the jobFriendlyName value + */ + public String jobFriendlyName() { + return this.jobFriendlyName; + } + + /** + * Set the job display name. + * + * @param jobFriendlyName the jobFriendlyName value to set + * @return the JobEntity object itself. + */ + public JobEntity withJobFriendlyName(String jobFriendlyName) { + this.jobFriendlyName = jobFriendlyName; + return this; + } + + /** + * Get the object id. + * + * @return the targetObjectId value + */ + public String targetObjectId() { + return this.targetObjectId; + } + + /** + * Set the object id. + * + * @param targetObjectId the targetObjectId value to set + * @return the JobEntity object itself. + */ + public JobEntity withTargetObjectId(String targetObjectId) { + this.targetObjectId = targetObjectId; + return this; + } + + /** + * Get the object name. + * + * @return the targetObjectName value + */ + public String targetObjectName() { + return this.targetObjectName; + } + + /** + * Set the object name. + * + * @param targetObjectName the targetObjectName value to set + * @return the JobEntity object itself. + */ + public JobEntity withTargetObjectName(String targetObjectName) { + this.targetObjectName = targetObjectName; + return this; + } + + /** + * Get the workflow affected object type. + * + * @return the targetInstanceType value + */ + public String targetInstanceType() { + return this.targetInstanceType; + } + + /** + * Set the workflow affected object type. + * + * @param targetInstanceType the targetInstanceType value to set + * @return the JobEntity object itself. + */ + public JobEntity withTargetInstanceType(String targetInstanceType) { + this.targetInstanceType = targetInstanceType; + return this; + } + + /** + * Get the job name. Enum type ScenarioName. + * + * @return the jobScenarioName value + */ + public String jobScenarioName() { + return this.jobScenarioName; + } + + /** + * Set the job name. Enum type ScenarioName. + * + * @param jobScenarioName the jobScenarioName value to set + * @return the JobEntity object itself. + */ + public JobEntity withJobScenarioName(String jobScenarioName) { + this.jobScenarioName = jobScenarioName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobErrorDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobErrorDetails.java new file mode 100644 index 0000000000000..4588cf7f6beea --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobErrorDetails.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * This class contains the error details per object. + */ +public class JobErrorDetails { + /** + * The Service error details. + */ + @JsonProperty(value = "serviceErrorDetails") + private ServiceError serviceErrorDetails; + + /** + * The Provider error details. + */ + @JsonProperty(value = "providerErrorDetails") + private ProviderError providerErrorDetails; + + /** + * Error level of error. + */ + @JsonProperty(value = "errorLevel") + private String errorLevel; + + /** + * The creation time of job error. + */ + @JsonProperty(value = "creationTime") + private DateTime creationTime; + + /** + * The Id of the task. + */ + @JsonProperty(value = "taskId") + private String taskId; + + /** + * Get the Service error details. + * + * @return the serviceErrorDetails value + */ + public ServiceError serviceErrorDetails() { + return this.serviceErrorDetails; + } + + /** + * Set the Service error details. + * + * @param serviceErrorDetails the serviceErrorDetails value to set + * @return the JobErrorDetails object itself. + */ + public JobErrorDetails withServiceErrorDetails(ServiceError serviceErrorDetails) { + this.serviceErrorDetails = serviceErrorDetails; + return this; + } + + /** + * Get the Provider error details. + * + * @return the providerErrorDetails value + */ + public ProviderError providerErrorDetails() { + return this.providerErrorDetails; + } + + /** + * Set the Provider error details. + * + * @param providerErrorDetails the providerErrorDetails value to set + * @return the JobErrorDetails object itself. + */ + public JobErrorDetails withProviderErrorDetails(ProviderError providerErrorDetails) { + this.providerErrorDetails = providerErrorDetails; + return this; + } + + /** + * Get error level of error. + * + * @return the errorLevel value + */ + public String errorLevel() { + return this.errorLevel; + } + + /** + * Set error level of error. + * + * @param errorLevel the errorLevel value to set + * @return the JobErrorDetails object itself. + */ + public JobErrorDetails withErrorLevel(String errorLevel) { + this.errorLevel = errorLevel; + return this; + } + + /** + * Get the creation time of job error. + * + * @return the creationTime value + */ + public DateTime creationTime() { + return this.creationTime; + } + + /** + * Set the creation time of job error. + * + * @param creationTime the creationTime value to set + * @return the JobErrorDetails object itself. + */ + public JobErrorDetails withCreationTime(DateTime creationTime) { + this.creationTime = creationTime; + return this; + } + + /** + * Get the Id of the task. + * + * @return the taskId value + */ + public String taskId() { + return this.taskId; + } + + /** + * Set the Id of the task. + * + * @param taskId the taskId value to set + * @return the JobErrorDetails object itself. + */ + public JobErrorDetails withTaskId(String taskId) { + this.taskId = taskId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobProperties.java new file mode 100644 index 0000000000000..a73fe2a1ecc32 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobProperties.java @@ -0,0 +1,387 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Job custom data details. + */ +public class JobProperties { + /** + * The activity id. + */ + @JsonProperty(value = "activityId") + private String activityId; + + /** + * The ScenarioName. + */ + @JsonProperty(value = "scenarioName") + private String scenarioName; + + /** + * The DisplayName. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The status of the Job. It is one of these values - NotStarted, + * InProgress, Succeeded, Failed, Cancelled, Suspended or Other. + */ + @JsonProperty(value = "state") + private String state; + + /** + * The description of the state of the Job. For e.g. - For Succeeded state, + * description can be Completed, PartiallySucceeded, + * CompletedWithInformation or Skipped. + */ + @JsonProperty(value = "stateDescription") + private String stateDescription; + + /** + * The tasks. + */ + @JsonProperty(value = "tasks") + private List tasks; + + /** + * The errors. + */ + @JsonProperty(value = "errors") + private List errors; + + /** + * The start time. + */ + @JsonProperty(value = "startTime") + private DateTime startTime; + + /** + * The end time. + */ + @JsonProperty(value = "endTime") + private DateTime endTime; + + /** + * The Allowed action the job. + */ + @JsonProperty(value = "allowedActions") + private List allowedActions; + + /** + * The affected Object Id. + */ + @JsonProperty(value = "targetObjectId") + private String targetObjectId; + + /** + * The name of the affected object. + */ + @JsonProperty(value = "targetObjectName") + private String targetObjectName; + + /** + * The type of the affected object which is of + * {Microsoft.Azure.SiteRecovery.V2015_11_10.AffectedObjectType} class. + */ + @JsonProperty(value = "targetInstanceType") + private String targetInstanceType; + + /** + * The custom job details like test failover job details. + */ + @JsonProperty(value = "customDetails") + private JobDetails customDetails; + + /** + * Get the activity id. + * + * @return the activityId value + */ + public String activityId() { + return this.activityId; + } + + /** + * Set the activity id. + * + * @param activityId the activityId value to set + * @return the JobProperties object itself. + */ + public JobProperties withActivityId(String activityId) { + this.activityId = activityId; + return this; + } + + /** + * Get the ScenarioName. + * + * @return the scenarioName value + */ + public String scenarioName() { + return this.scenarioName; + } + + /** + * Set the ScenarioName. + * + * @param scenarioName the scenarioName value to set + * @return the JobProperties object itself. + */ + public JobProperties withScenarioName(String scenarioName) { + this.scenarioName = scenarioName; + return this; + } + + /** + * Get the DisplayName. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the DisplayName. + * + * @param friendlyName the friendlyName value to set + * @return the JobProperties object itself. + */ + public JobProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the status of the Job. It is one of these values - NotStarted, InProgress, Succeeded, Failed, Cancelled, Suspended or Other. + * + * @return the state value + */ + public String state() { + return this.state; + } + + /** + * Set the status of the Job. It is one of these values - NotStarted, InProgress, Succeeded, Failed, Cancelled, Suspended or Other. + * + * @param state the state value to set + * @return the JobProperties object itself. + */ + public JobProperties withState(String state) { + this.state = state; + return this; + } + + /** + * Get the description of the state of the Job. For e.g. - For Succeeded state, description can be Completed, PartiallySucceeded, CompletedWithInformation or Skipped. + * + * @return the stateDescription value + */ + public String stateDescription() { + return this.stateDescription; + } + + /** + * Set the description of the state of the Job. For e.g. - For Succeeded state, description can be Completed, PartiallySucceeded, CompletedWithInformation or Skipped. + * + * @param stateDescription the stateDescription value to set + * @return the JobProperties object itself. + */ + public JobProperties withStateDescription(String stateDescription) { + this.stateDescription = stateDescription; + return this; + } + + /** + * Get the tasks. + * + * @return the tasks value + */ + public List tasks() { + return this.tasks; + } + + /** + * Set the tasks. + * + * @param tasks the tasks value to set + * @return the JobProperties object itself. + */ + public JobProperties withTasks(List tasks) { + this.tasks = tasks; + return this; + } + + /** + * Get the errors. + * + * @return the errors value + */ + public List errors() { + return this.errors; + } + + /** + * Set the errors. + * + * @param errors the errors value to set + * @return the JobProperties object itself. + */ + public JobProperties withErrors(List errors) { + this.errors = errors; + return this; + } + + /** + * Get the start time. + * + * @return the startTime value + */ + public DateTime startTime() { + return this.startTime; + } + + /** + * Set the start time. + * + * @param startTime the startTime value to set + * @return the JobProperties object itself. + */ + public JobProperties withStartTime(DateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * Get the end time. + * + * @return the endTime value + */ + public DateTime endTime() { + return this.endTime; + } + + /** + * Set the end time. + * + * @param endTime the endTime value to set + * @return the JobProperties object itself. + */ + public JobProperties withEndTime(DateTime endTime) { + this.endTime = endTime; + return this; + } + + /** + * Get the Allowed action the job. + * + * @return the allowedActions value + */ + public List allowedActions() { + return this.allowedActions; + } + + /** + * Set the Allowed action the job. + * + * @param allowedActions the allowedActions value to set + * @return the JobProperties object itself. + */ + public JobProperties withAllowedActions(List allowedActions) { + this.allowedActions = allowedActions; + return this; + } + + /** + * Get the affected Object Id. + * + * @return the targetObjectId value + */ + public String targetObjectId() { + return this.targetObjectId; + } + + /** + * Set the affected Object Id. + * + * @param targetObjectId the targetObjectId value to set + * @return the JobProperties object itself. + */ + public JobProperties withTargetObjectId(String targetObjectId) { + this.targetObjectId = targetObjectId; + return this; + } + + /** + * Get the name of the affected object. + * + * @return the targetObjectName value + */ + public String targetObjectName() { + return this.targetObjectName; + } + + /** + * Set the name of the affected object. + * + * @param targetObjectName the targetObjectName value to set + * @return the JobProperties object itself. + */ + public JobProperties withTargetObjectName(String targetObjectName) { + this.targetObjectName = targetObjectName; + return this; + } + + /** + * Get the type of the affected object which is of {Microsoft.Azure.SiteRecovery.V2015_11_10.AffectedObjectType} class. + * + * @return the targetInstanceType value + */ + public String targetInstanceType() { + return this.targetInstanceType; + } + + /** + * Set the type of the affected object which is of {Microsoft.Azure.SiteRecovery.V2015_11_10.AffectedObjectType} class. + * + * @param targetInstanceType the targetInstanceType value to set + * @return the JobProperties object itself. + */ + public JobProperties withTargetInstanceType(String targetInstanceType) { + this.targetInstanceType = targetInstanceType; + return this; + } + + /** + * Get the custom job details like test failover job details. + * + * @return the customDetails value + */ + public JobDetails customDetails() { + return this.customDetails; + } + + /** + * Set the custom job details like test failover job details. + * + * @param customDetails the customDetails value to set + * @return the JobProperties object itself. + */ + public JobProperties withCustomDetails(JobDetails customDetails) { + this.customDetails = customDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobQueryParameter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobQueryParameter.java new file mode 100644 index 0000000000000..062b9fbac86fb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobQueryParameter.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Query parameter to enumerate jobs. + */ +public class JobQueryParameter { + /** + * Date time to get jobs from. + */ + @JsonProperty(value = "startTime") + private String startTime; + + /** + * Date time to get jobs up to. + */ + @JsonProperty(value = "endTime") + private String endTime; + + /** + * The Id of the fabric to search jobs under. + */ + @JsonProperty(value = "fabricId") + private String fabricId; + + /** + * The type of objects. + */ + @JsonProperty(value = "affectedObjectTypes") + private String affectedObjectTypes; + + /** + * The states of the job to be filtered can be in. + */ + @JsonProperty(value = "jobStatus") + private String jobStatus; + + /** + * Get date time to get jobs from. + * + * @return the startTime value + */ + public String startTime() { + return this.startTime; + } + + /** + * Set date time to get jobs from. + * + * @param startTime the startTime value to set + * @return the JobQueryParameter object itself. + */ + public JobQueryParameter withStartTime(String startTime) { + this.startTime = startTime; + return this; + } + + /** + * Get date time to get jobs up to. + * + * @return the endTime value + */ + public String endTime() { + return this.endTime; + } + + /** + * Set date time to get jobs up to. + * + * @param endTime the endTime value to set + * @return the JobQueryParameter object itself. + */ + public JobQueryParameter withEndTime(String endTime) { + this.endTime = endTime; + return this; + } + + /** + * Get the Id of the fabric to search jobs under. + * + * @return the fabricId value + */ + public String fabricId() { + return this.fabricId; + } + + /** + * Set the Id of the fabric to search jobs under. + * + * @param fabricId the fabricId value to set + * @return the JobQueryParameter object itself. + */ + public JobQueryParameter withFabricId(String fabricId) { + this.fabricId = fabricId; + return this; + } + + /** + * Get the type of objects. + * + * @return the affectedObjectTypes value + */ + public String affectedObjectTypes() { + return this.affectedObjectTypes; + } + + /** + * Set the type of objects. + * + * @param affectedObjectTypes the affectedObjectTypes value to set + * @return the JobQueryParameter object itself. + */ + public JobQueryParameter withAffectedObjectTypes(String affectedObjectTypes) { + this.affectedObjectTypes = affectedObjectTypes; + return this; + } + + /** + * Get the states of the job to be filtered can be in. + * + * @return the jobStatus value + */ + public String jobStatus() { + return this.jobStatus; + } + + /** + * Set the states of the job to be filtered can be in. + * + * @param jobStatus the jobStatus value to set + * @return the JobQueryParameter object itself. + */ + public JobQueryParameter withJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobStatusEventDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobStatusEventDetails.java new file mode 100644 index 0000000000000..e84009188f68a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobStatusEventDetails.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Model class for event details of a job status event. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("JobStatus") +public class JobStatusEventDetails extends EventSpecificDetails { + /** + * Job arm id for the event. + */ + @JsonProperty(value = "jobId") + private String jobId; + + /** + * JobName for the Event. + */ + @JsonProperty(value = "jobFriendlyName") + private String jobFriendlyName; + + /** + * JobStatus for the Event. + */ + @JsonProperty(value = "jobStatus") + private String jobStatus; + + /** + * AffectedObjectType for the event. + */ + @JsonProperty(value = "affectedObjectType") + private String affectedObjectType; + + /** + * Get job arm id for the event. + * + * @return the jobId value + */ + public String jobId() { + return this.jobId; + } + + /** + * Set job arm id for the event. + * + * @param jobId the jobId value to set + * @return the JobStatusEventDetails object itself. + */ + public JobStatusEventDetails withJobId(String jobId) { + this.jobId = jobId; + return this; + } + + /** + * Get jobName for the Event. + * + * @return the jobFriendlyName value + */ + public String jobFriendlyName() { + return this.jobFriendlyName; + } + + /** + * Set jobName for the Event. + * + * @param jobFriendlyName the jobFriendlyName value to set + * @return the JobStatusEventDetails object itself. + */ + public JobStatusEventDetails withJobFriendlyName(String jobFriendlyName) { + this.jobFriendlyName = jobFriendlyName; + return this; + } + + /** + * Get jobStatus for the Event. + * + * @return the jobStatus value + */ + public String jobStatus() { + return this.jobStatus; + } + + /** + * Set jobStatus for the Event. + * + * @param jobStatus the jobStatus value to set + * @return the JobStatusEventDetails object itself. + */ + public JobStatusEventDetails withJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + return this; + } + + /** + * Get affectedObjectType for the event. + * + * @return the affectedObjectType value + */ + public String affectedObjectType() { + return this.affectedObjectType; + } + + /** + * Set affectedObjectType for the event. + * + * @param affectedObjectType the affectedObjectType value to set + * @return the JobStatusEventDetails object itself. + */ + public JobStatusEventDetails withAffectedObjectType(String affectedObjectType) { + this.affectedObjectType = affectedObjectType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobTaskDetails.java new file mode 100644 index 0000000000000..820720e577abe --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/JobTaskDetails.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents a task which is actually a workflow so that one can + * navigate to its individual drill down. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("JobTaskDetails") +public class JobTaskDetails extends TaskTypeDetails { + /** + * The job entity. + */ + @JsonProperty(value = "jobTask") + private JobEntity jobTask; + + /** + * Get the job entity. + * + * @return the jobTask value + */ + public JobEntity jobTask() { + return this.jobTask; + } + + /** + * Set the job entity. + * + * @param jobTask the jobTask value to set + * @return the JobTaskDetails object itself. + */ + public JobTaskDetails withJobTask(JobEntity jobTask) { + this.jobTask = jobTask; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/KeyEncryptionKeyInfo.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/KeyEncryptionKeyInfo.java new file mode 100644 index 0000000000000..10ac7fe64466f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/KeyEncryptionKeyInfo.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Key Encryption Key (KEK) information. + */ +public class KeyEncryptionKeyInfo { + /** + * The key url / identifier. + */ + @JsonProperty(value = "keyIdentifier") + private String keyIdentifier; + + /** + * The KeyVault resource ARM id for key. + */ + @JsonProperty(value = "keyVaultResourceArmId") + private String keyVaultResourceArmId; + + /** + * Get the key url / identifier. + * + * @return the keyIdentifier value + */ + public String keyIdentifier() { + return this.keyIdentifier; + } + + /** + * Set the key url / identifier. + * + * @param keyIdentifier the keyIdentifier value to set + * @return the KeyEncryptionKeyInfo object itself. + */ + public KeyEncryptionKeyInfo withKeyIdentifier(String keyIdentifier) { + this.keyIdentifier = keyIdentifier; + return this; + } + + /** + * Get the KeyVault resource ARM id for key. + * + * @return the keyVaultResourceArmId value + */ + public String keyVaultResourceArmId() { + return this.keyVaultResourceArmId; + } + + /** + * Set the KeyVault resource ARM id for key. + * + * @param keyVaultResourceArmId the keyVaultResourceArmId value to set + * @return the KeyEncryptionKeyInfo object itself. + */ + public KeyEncryptionKeyInfo withKeyVaultResourceArmId(String keyVaultResourceArmId) { + this.keyVaultResourceArmId = keyVaultResourceArmId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LicenseType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LicenseType.java new file mode 100644 index 0000000000000..995dd78e61595 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LicenseType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for LicenseType. + */ +public final class LicenseType extends ExpandableStringEnum { + /** Static value NotSpecified for LicenseType. */ + public static final LicenseType NOT_SPECIFIED = fromString("NotSpecified"); + + /** Static value NoLicenseType for LicenseType. */ + public static final LicenseType NO_LICENSE_TYPE = fromString("NoLicenseType"); + + /** Static value WindowsServer for LicenseType. */ + public static final LicenseType WINDOWS_SERVER = fromString("WindowsServer"); + + /** + * Creates or finds a LicenseType from its string representation. + * @param name a name to look for + * @return the corresponding LicenseType + */ + @JsonCreator + public static LicenseType fromString(String name) { + return fromString(name, LicenseType.class); + } + + /** + * @return known LicenseType values + */ + public static Collection values() { + return values(LicenseType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetwork.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetwork.java new file mode 100644 index 0000000000000..bd53360d11d6b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetwork.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.LogicalNetworkInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing LogicalNetwork. + */ +public interface LogicalNetwork extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + LogicalNetworkProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetworkProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetworkProperties.java new file mode 100644 index 0000000000000..4644551aea6a8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/LogicalNetworkProperties.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Logical Network Properties. + */ +public class LogicalNetworkProperties { + /** + * The Friendly Name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * A value indicating whether Network Virtualization is enabled for the + * logical network. + */ + @JsonProperty(value = "networkVirtualizationStatus") + private String networkVirtualizationStatus; + + /** + * A value indicating whether logical network is used as private test + * network by test failover. + */ + @JsonProperty(value = "logicalNetworkUsage") + private String logicalNetworkUsage; + + /** + * A value indicating whether logical network definitions are isolated. + */ + @JsonProperty(value = "logicalNetworkDefinitionsStatus") + private String logicalNetworkDefinitionsStatus; + + /** + * Get the Friendly Name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the Friendly Name. + * + * @param friendlyName the friendlyName value to set + * @return the LogicalNetworkProperties object itself. + */ + public LogicalNetworkProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get a value indicating whether Network Virtualization is enabled for the logical network. + * + * @return the networkVirtualizationStatus value + */ + public String networkVirtualizationStatus() { + return this.networkVirtualizationStatus; + } + + /** + * Set a value indicating whether Network Virtualization is enabled for the logical network. + * + * @param networkVirtualizationStatus the networkVirtualizationStatus value to set + * @return the LogicalNetworkProperties object itself. + */ + public LogicalNetworkProperties withNetworkVirtualizationStatus(String networkVirtualizationStatus) { + this.networkVirtualizationStatus = networkVirtualizationStatus; + return this; + } + + /** + * Get a value indicating whether logical network is used as private test network by test failover. + * + * @return the logicalNetworkUsage value + */ + public String logicalNetworkUsage() { + return this.logicalNetworkUsage; + } + + /** + * Set a value indicating whether logical network is used as private test network by test failover. + * + * @param logicalNetworkUsage the logicalNetworkUsage value to set + * @return the LogicalNetworkProperties object itself. + */ + public LogicalNetworkProperties withLogicalNetworkUsage(String logicalNetworkUsage) { + this.logicalNetworkUsage = logicalNetworkUsage; + return this; + } + + /** + * Get a value indicating whether logical network definitions are isolated. + * + * @return the logicalNetworkDefinitionsStatus value + */ + public String logicalNetworkDefinitionsStatus() { + return this.logicalNetworkDefinitionsStatus; + } + + /** + * Set a value indicating whether logical network definitions are isolated. + * + * @param logicalNetworkDefinitionsStatus the logicalNetworkDefinitionsStatus value to set + * @return the LogicalNetworkProperties object itself. + */ + public LogicalNetworkProperties withLogicalNetworkDefinitionsStatus(String logicalNetworkDefinitionsStatus) { + this.logicalNetworkDefinitionsStatus = logicalNetworkDefinitionsStatus; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ManualActionTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ManualActionTaskDetails.java new file mode 100644 index 0000000000000..4a43c393951d5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ManualActionTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the manual action task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ManualActionTaskDetails") +public class ManualActionTaskDetails extends TaskTypeDetails { + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The instructions. + */ + @JsonProperty(value = "instructions") + private String instructions; + + /** + * The observation. + */ + @JsonProperty(value = "observation") + private String observation; + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the ManualActionTaskDetails object itself. + */ + public ManualActionTaskDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the instructions. + * + * @return the instructions value + */ + public String instructions() { + return this.instructions; + } + + /** + * Set the instructions. + * + * @param instructions the instructions value to set + * @return the ManualActionTaskDetails object itself. + */ + public ManualActionTaskDetails withInstructions(String instructions) { + this.instructions = instructions; + return this; + } + + /** + * Get the observation. + * + * @return the observation value + */ + public String observation() { + return this.observation; + } + + /** + * Set the observation. + * + * @param observation the observation value to set + * @return the ManualActionTaskDetails object itself. + */ + public ManualActionTaskDetails withObservation(String observation) { + this.observation = observation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MasterTargetServer.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MasterTargetServer.java new file mode 100644 index 0000000000000..df9a923ef334b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MasterTargetServer.java @@ -0,0 +1,487 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Details of a Master Target Server. + */ +public class MasterTargetServer { + /** + * The server Id. + */ + @JsonProperty(value = "id") + private String id; + + /** + * The IP address of the server. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The server name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The OS type of the server. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The version of the scout component on the server. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * The last heartbeat received from the server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * Version status. + */ + @JsonProperty(value = "versionStatus") + private String versionStatus; + + /** + * The retention volumes of Master target Server. + */ + @JsonProperty(value = "retentionVolumes") + private List retentionVolumes; + + /** + * The list of data stores in the fabric. + */ + @JsonProperty(value = "dataStores") + private List dataStores; + + /** + * Validation errors. + */ + @JsonProperty(value = "validationErrors") + private List validationErrors; + + /** + * Health errors. + */ + @JsonProperty(value = "healthErrors") + private List healthErrors; + + /** + * Disk count of the master target. + */ + @JsonProperty(value = "diskCount") + private Integer diskCount; + + /** + * OS Version of the master target. + */ + @JsonProperty(value = "osVersion") + private String osVersion; + + /** + * Agent expiry date. + */ + @JsonProperty(value = "agentExpiryDate") + private DateTime agentExpiryDate; + + /** + * MARS agent version. + */ + @JsonProperty(value = "marsAgentVersion") + private String marsAgentVersion; + + /** + * MARS agent expiry date. + */ + @JsonProperty(value = "marsAgentExpiryDate") + private DateTime marsAgentExpiryDate; + + /** + * Agent version details. + */ + @JsonProperty(value = "agentVersionDetails") + private VersionDetails agentVersionDetails; + + /** + * Mars agent version details. + */ + @JsonProperty(value = "marsAgentVersionDetails") + private VersionDetails marsAgentVersionDetails; + + /** + * Get the server Id. + * + * @return the id value + */ + public String id() { + return this.id; + } + + /** + * Set the server Id. + * + * @param id the id value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withId(String id) { + this.id = id; + return this; + } + + /** + * Get the IP address of the server. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the server. + * + * @param ipAddress the ipAddress value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the server name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the server name. + * + * @param name the name value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withName(String name) { + this.name = name; + return this; + } + + /** + * Get the OS type of the server. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type of the server. + * + * @param osType the osType value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the version of the scout component on the server. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the version of the scout component on the server. + * + * @param agentVersion the agentVersion value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get the last heartbeat received from the server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from the server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get version status. + * + * @return the versionStatus value + */ + public String versionStatus() { + return this.versionStatus; + } + + /** + * Set version status. + * + * @param versionStatus the versionStatus value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withVersionStatus(String versionStatus) { + this.versionStatus = versionStatus; + return this; + } + + /** + * Get the retention volumes of Master target Server. + * + * @return the retentionVolumes value + */ + public List retentionVolumes() { + return this.retentionVolumes; + } + + /** + * Set the retention volumes of Master target Server. + * + * @param retentionVolumes the retentionVolumes value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withRetentionVolumes(List retentionVolumes) { + this.retentionVolumes = retentionVolumes; + return this; + } + + /** + * Get the list of data stores in the fabric. + * + * @return the dataStores value + */ + public List dataStores() { + return this.dataStores; + } + + /** + * Set the list of data stores in the fabric. + * + * @param dataStores the dataStores value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withDataStores(List dataStores) { + this.dataStores = dataStores; + return this; + } + + /** + * Get validation errors. + * + * @return the validationErrors value + */ + public List validationErrors() { + return this.validationErrors; + } + + /** + * Set validation errors. + * + * @param validationErrors the validationErrors value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withValidationErrors(List validationErrors) { + this.validationErrors = validationErrors; + return this; + } + + /** + * Get health errors. + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Set health errors. + * + * @param healthErrors the healthErrors value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withHealthErrors(List healthErrors) { + this.healthErrors = healthErrors; + return this; + } + + /** + * Get disk count of the master target. + * + * @return the diskCount value + */ + public Integer diskCount() { + return this.diskCount; + } + + /** + * Set disk count of the master target. + * + * @param diskCount the diskCount value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withDiskCount(Integer diskCount) { + this.diskCount = diskCount; + return this; + } + + /** + * Get oS Version of the master target. + * + * @return the osVersion value + */ + public String osVersion() { + return this.osVersion; + } + + /** + * Set oS Version of the master target. + * + * @param osVersion the osVersion value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withOsVersion(String osVersion) { + this.osVersion = osVersion; + return this; + } + + /** + * Get agent expiry date. + * + * @return the agentExpiryDate value + */ + public DateTime agentExpiryDate() { + return this.agentExpiryDate; + } + + /** + * Set agent expiry date. + * + * @param agentExpiryDate the agentExpiryDate value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withAgentExpiryDate(DateTime agentExpiryDate) { + this.agentExpiryDate = agentExpiryDate; + return this; + } + + /** + * Get mARS agent version. + * + * @return the marsAgentVersion value + */ + public String marsAgentVersion() { + return this.marsAgentVersion; + } + + /** + * Set mARS agent version. + * + * @param marsAgentVersion the marsAgentVersion value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withMarsAgentVersion(String marsAgentVersion) { + this.marsAgentVersion = marsAgentVersion; + return this; + } + + /** + * Get mARS agent expiry date. + * + * @return the marsAgentExpiryDate value + */ + public DateTime marsAgentExpiryDate() { + return this.marsAgentExpiryDate; + } + + /** + * Set mARS agent expiry date. + * + * @param marsAgentExpiryDate the marsAgentExpiryDate value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withMarsAgentExpiryDate(DateTime marsAgentExpiryDate) { + this.marsAgentExpiryDate = marsAgentExpiryDate; + return this; + } + + /** + * Get agent version details. + * + * @return the agentVersionDetails value + */ + public VersionDetails agentVersionDetails() { + return this.agentVersionDetails; + } + + /** + * Set agent version details. + * + * @param agentVersionDetails the agentVersionDetails value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withAgentVersionDetails(VersionDetails agentVersionDetails) { + this.agentVersionDetails = agentVersionDetails; + return this; + } + + /** + * Get mars agent version details. + * + * @return the marsAgentVersionDetails value + */ + public VersionDetails marsAgentVersionDetails() { + return this.marsAgentVersionDetails; + } + + /** + * Set mars agent version details. + * + * @param marsAgentVersionDetails the marsAgentVersionDetails value to set + * @return the MasterTargetServer object itself. + */ + public MasterTargetServer withMarsAgentVersionDetails(VersionDetails marsAgentVersionDetails) { + this.marsAgentVersionDetails = marsAgentVersionDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInput.java new file mode 100644 index 0000000000000..898e7bf0242e9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input for migrate. + */ +public class MigrateInput { + /** + * Migrate input properties. + */ + @JsonProperty(value = "properties", required = true) + private MigrateInputProperties properties; + + /** + * Get migrate input properties. + * + * @return the properties value + */ + public MigrateInputProperties properties() { + return this.properties; + } + + /** + * Set migrate input properties. + * + * @param properties the properties value to set + * @return the MigrateInput object itself. + */ + public MigrateInput withProperties(MigrateInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInputProperties.java new file mode 100644 index 0000000000000..431d13ab23719 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Migrate input properties. + */ +public class MigrateInputProperties { + /** + * The provider specific details. + */ + @JsonProperty(value = "providerSpecificDetails", required = true) + private MigrateProviderSpecificInput providerSpecificDetails; + + /** + * Get the provider specific details. + * + * @return the providerSpecificDetails value + */ + public MigrateProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific details. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the MigrateInputProperties object itself. + */ + public MigrateInputProperties withProviderSpecificDetails(MigrateProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateProviderSpecificInput.java new file mode 100644 index 0000000000000..3ade71df7af11 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrateProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Migrate provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("MigrateProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtMigrateInput.class) +}) +public class MigrateProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItem.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItem.java new file mode 100644 index 0000000000000..44c6f850e7e2e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItem.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.MigrationItemInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing MigrationItem. + */ +public interface MigrationItem extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + MigrationItemProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the MigrationItem definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationProtectionContainer, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of MigrationItem definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a MigrationItem definition. + */ + interface Blank extends WithReplicationProtectionContainer { + } + + /** + * The stage of the migrationitem definition allowing to specify ReplicationProtectionContainer. + */ + interface WithReplicationProtectionContainer { + /** + * Specifies fabricName, protectionContainerName. + * @param fabricName Fabric name + * @param protectionContainerName Protection container name + * @return the next definition stage + */ + WithProperties withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName); + } + + /** + * The stage of the migrationitem definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Enable migration input properties + * @return the next definition stage + */ + WithCreate withProperties(EnableMigrationInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a MigrationItem update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of MigrationItem update stages. + */ + interface UpdateStages { + /** + * The stage of the migrationitem update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Update migration item input properties + * @return the next update stage + */ + Update withProperties(UpdateMigrationItemInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemOperation.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemOperation.java new file mode 100644 index 0000000000000..792390cb9c42e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemOperation.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MigrationItemOperation. + */ +public final class MigrationItemOperation extends ExpandableStringEnum { + /** Static value DisableMigration for MigrationItemOperation. */ + public static final MigrationItemOperation DISABLE_MIGRATION = fromString("DisableMigration"); + + /** Static value TestMigrate for MigrationItemOperation. */ + public static final MigrationItemOperation TEST_MIGRATE = fromString("TestMigrate"); + + /** Static value TestMigrateCleanup for MigrationItemOperation. */ + public static final MigrationItemOperation TEST_MIGRATE_CLEANUP = fromString("TestMigrateCleanup"); + + /** Static value Migrate for MigrationItemOperation. */ + public static final MigrationItemOperation MIGRATE = fromString("Migrate"); + + /** + * Creates or finds a MigrationItemOperation from its string representation. + * @param name a name to look for + * @return the corresponding MigrationItemOperation + */ + @JsonCreator + public static MigrationItemOperation fromString(String name) { + return fromString(name, MigrationItemOperation.class); + } + + /** + * @return known MigrationItemOperation values + */ + public static Collection values() { + return values(MigrationItemOperation.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemProperties.java new file mode 100644 index 0000000000000..15e75144aa9af --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemProperties.java @@ -0,0 +1,231 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Migration item properties. + */ +public class MigrationItemProperties { + /** + * The on-premise virtual machine name. + */ + @JsonProperty(value = "machineName", access = JsonProperty.Access.WRITE_ONLY) + private String machineName; + + /** + * The ARM Id of policy governing this item. + */ + @JsonProperty(value = "policyId", access = JsonProperty.Access.WRITE_ONLY) + private String policyId; + + /** + * The name of policy governing this item. + */ + @JsonProperty(value = "policyFriendlyName", access = JsonProperty.Access.WRITE_ONLY) + private String policyFriendlyName; + + /** + * The recovery services provider ARM Id. + */ + @JsonProperty(value = "recoveryServicesProviderId", access = JsonProperty.Access.WRITE_ONLY) + private String recoveryServicesProviderId; + + /** + * The migration status. Possible values include: 'None', + * 'EnableMigrationInProgress', 'EnableMigrationFailed', + * 'DisableMigrationInProgress', 'DisableMigrationFailed', + * 'InitialSeedingInProgress', 'InitialSeedingFailed', 'Replicating', + * 'MigrationInProgress', 'MigrationSucceeded', 'MigrationFailed'. + */ + @JsonProperty(value = "migrationState", access = JsonProperty.Access.WRITE_ONLY) + private MigrationState migrationState; + + /** + * The migration state description. + */ + @JsonProperty(value = "migrationStateDescription", access = JsonProperty.Access.WRITE_ONLY) + private String migrationStateDescription; + + /** + * The test migrate state. Possible values include: 'None', + * 'TestMigrationInProgress', 'TestMigrationSucceeded', + * 'TestMigrationFailed', 'TestMigrationCleanupInProgress'. + */ + @JsonProperty(value = "testMigrateState", access = JsonProperty.Access.WRITE_ONLY) + private TestMigrationState testMigrateState; + + /** + * The test migrate state description. + */ + @JsonProperty(value = "testMigrateStateDescription", access = JsonProperty.Access.WRITE_ONLY) + private String testMigrateStateDescription; + + /** + * The consolidated health. + */ + @JsonProperty(value = "health", access = JsonProperty.Access.WRITE_ONLY) + private String health; + + /** + * The list of health errors. + */ + @JsonProperty(value = "healthErrors", access = JsonProperty.Access.WRITE_ONLY) + private List healthErrors; + + /** + * The allowed operations on the migration item, based on the current + * migration state of the item. + */ + @JsonProperty(value = "allowedOperations", access = JsonProperty.Access.WRITE_ONLY) + private List allowedOperations; + + /** + * The current job details. + */ + @JsonProperty(value = "currentJob", access = JsonProperty.Access.WRITE_ONLY) + private CurrentJobDetails currentJob; + + /** + * The migration provider custom settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private MigrationProviderSpecificSettings providerSpecificDetails; + + /** + * Get the on-premise virtual machine name. + * + * @return the machineName value + */ + public String machineName() { + return this.machineName; + } + + /** + * Get the ARM Id of policy governing this item. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Get the name of policy governing this item. + * + * @return the policyFriendlyName value + */ + public String policyFriendlyName() { + return this.policyFriendlyName; + } + + /** + * Get the recovery services provider ARM Id. + * + * @return the recoveryServicesProviderId value + */ + public String recoveryServicesProviderId() { + return this.recoveryServicesProviderId; + } + + /** + * Get the migration status. Possible values include: 'None', 'EnableMigrationInProgress', 'EnableMigrationFailed', 'DisableMigrationInProgress', 'DisableMigrationFailed', 'InitialSeedingInProgress', 'InitialSeedingFailed', 'Replicating', 'MigrationInProgress', 'MigrationSucceeded', 'MigrationFailed'. + * + * @return the migrationState value + */ + public MigrationState migrationState() { + return this.migrationState; + } + + /** + * Get the migration state description. + * + * @return the migrationStateDescription value + */ + public String migrationStateDescription() { + return this.migrationStateDescription; + } + + /** + * Get the test migrate state. Possible values include: 'None', 'TestMigrationInProgress', 'TestMigrationSucceeded', 'TestMigrationFailed', 'TestMigrationCleanupInProgress'. + * + * @return the testMigrateState value + */ + public TestMigrationState testMigrateState() { + return this.testMigrateState; + } + + /** + * Get the test migrate state description. + * + * @return the testMigrateStateDescription value + */ + public String testMigrateStateDescription() { + return this.testMigrateStateDescription; + } + + /** + * Get the consolidated health. + * + * @return the health value + */ + public String health() { + return this.health; + } + + /** + * Get the list of health errors. + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Get the allowed operations on the migration item, based on the current migration state of the item. + * + * @return the allowedOperations value + */ + public List allowedOperations() { + return this.allowedOperations; + } + + /** + * Get the current job details. + * + * @return the currentJob value + */ + public CurrentJobDetails currentJob() { + return this.currentJob; + } + + /** + * Get the migration provider custom settings. + * + * @return the providerSpecificDetails value + */ + public MigrationProviderSpecificSettings providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the migration provider custom settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the MigrationItemProperties object itself. + */ + public MigrationItemProperties withProviderSpecificDetails(MigrationProviderSpecificSettings providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemsQueryParameter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemsQueryParameter.java new file mode 100644 index 0000000000000..24ef28725f3f7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationItemsQueryParameter.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Query parameter to enumerate migration items. + */ +public class MigrationItemsQueryParameter { + /** + * The source fabric name filter. + */ + @JsonProperty(value = "sourceFabricName") + private String sourceFabricName; + + /** + * The replication provider type. + */ + @JsonProperty(value = "instanceType") + private String instanceType; + + /** + * Get the source fabric name filter. + * + * @return the sourceFabricName value + */ + public String sourceFabricName() { + return this.sourceFabricName; + } + + /** + * Set the source fabric name filter. + * + * @param sourceFabricName the sourceFabricName value to set + * @return the MigrationItemsQueryParameter object itself. + */ + public MigrationItemsQueryParameter withSourceFabricName(String sourceFabricName) { + this.sourceFabricName = sourceFabricName; + return this; + } + + /** + * Get the replication provider type. + * + * @return the instanceType value + */ + public String instanceType() { + return this.instanceType; + } + + /** + * Set the replication provider type. + * + * @param instanceType the instanceType value to set + * @return the MigrationItemsQueryParameter object itself. + */ + public MigrationItemsQueryParameter withInstanceType(String instanceType) { + this.instanceType = instanceType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationProviderSpecificSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationProviderSpecificSettings.java new file mode 100644 index 0000000000000..429e4c642eb24 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationProviderSpecificSettings.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Migration provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("MigrationProviderSpecificSettings") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtMigrationDetails.class) +}) +public class MigrationProviderSpecificSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoint.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoint.java new file mode 100644 index 0000000000000..70b43702153b1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoint.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.MigrationRecoveryPointInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing MigrationRecoveryPoint. + */ +public interface MigrationRecoveryPoint extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + MigrationRecoveryPointProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointProperties.java new file mode 100644 index 0000000000000..b5fdcd77f9397 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointProperties.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Migration item recovery point properties. + */ +public class MigrationRecoveryPointProperties { + /** + * The recovery point time. + */ + @JsonProperty(value = "recoveryPointTime", access = JsonProperty.Access.WRITE_ONLY) + private DateTime recoveryPointTime; + + /** + * The recovery point type. Possible values include: 'NotSpecified', + * 'ApplicationConsistent', 'CrashConsistent'. + */ + @JsonProperty(value = "recoveryPointType", access = JsonProperty.Access.WRITE_ONLY) + private MigrationRecoveryPointType recoveryPointType; + + /** + * Get the recovery point time. + * + * @return the recoveryPointTime value + */ + public DateTime recoveryPointTime() { + return this.recoveryPointTime; + } + + /** + * Get the recovery point type. Possible values include: 'NotSpecified', 'ApplicationConsistent', 'CrashConsistent'. + * + * @return the recoveryPointType value + */ + public MigrationRecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointType.java new file mode 100644 index 0000000000000..d1f8ffa257e46 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPointType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MigrationRecoveryPointType. + */ +public final class MigrationRecoveryPointType extends ExpandableStringEnum { + /** Static value NotSpecified for MigrationRecoveryPointType. */ + public static final MigrationRecoveryPointType NOT_SPECIFIED = fromString("NotSpecified"); + + /** Static value ApplicationConsistent for MigrationRecoveryPointType. */ + public static final MigrationRecoveryPointType APPLICATION_CONSISTENT = fromString("ApplicationConsistent"); + + /** Static value CrashConsistent for MigrationRecoveryPointType. */ + public static final MigrationRecoveryPointType CRASH_CONSISTENT = fromString("CrashConsistent"); + + /** + * Creates or finds a MigrationRecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding MigrationRecoveryPointType + */ + @JsonCreator + public static MigrationRecoveryPointType fromString(String name) { + return fromString(name, MigrationRecoveryPointType.class); + } + + /** + * @return known MigrationRecoveryPointType values + */ + public static Collection values() { + return values(MigrationRecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoints.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoints.java new file mode 100644 index 0000000000000..70e62e8119f67 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationRecoveryPoints.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.MigrationRecoveryPointsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing MigrationRecoveryPoints. + */ +public interface MigrationRecoveryPoints extends HasInner { + /** + * Gets a recovery point for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param migrationRecoveryPointName The migration recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName); + + /** + * Gets the recovery points for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationMigrationItemsAsync(final String fabricName, final String protectionContainerName, final String migrationItemName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationState.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationState.java new file mode 100644 index 0000000000000..70a4134a9d706 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MigrationState.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MigrationState. + */ +public final class MigrationState extends ExpandableStringEnum { + /** Static value None for MigrationState. */ + public static final MigrationState NONE = fromString("None"); + + /** Static value EnableMigrationInProgress for MigrationState. */ + public static final MigrationState ENABLE_MIGRATION_IN_PROGRESS = fromString("EnableMigrationInProgress"); + + /** Static value EnableMigrationFailed for MigrationState. */ + public static final MigrationState ENABLE_MIGRATION_FAILED = fromString("EnableMigrationFailed"); + + /** Static value DisableMigrationInProgress for MigrationState. */ + public static final MigrationState DISABLE_MIGRATION_IN_PROGRESS = fromString("DisableMigrationInProgress"); + + /** Static value DisableMigrationFailed for MigrationState. */ + public static final MigrationState DISABLE_MIGRATION_FAILED = fromString("DisableMigrationFailed"); + + /** Static value InitialSeedingInProgress for MigrationState. */ + public static final MigrationState INITIAL_SEEDING_IN_PROGRESS = fromString("InitialSeedingInProgress"); + + /** Static value InitialSeedingFailed for MigrationState. */ + public static final MigrationState INITIAL_SEEDING_FAILED = fromString("InitialSeedingFailed"); + + /** Static value Replicating for MigrationState. */ + public static final MigrationState REPLICATING = fromString("Replicating"); + + /** Static value MigrationInProgress for MigrationState. */ + public static final MigrationState MIGRATION_IN_PROGRESS = fromString("MigrationInProgress"); + + /** Static value MigrationSucceeded for MigrationState. */ + public static final MigrationState MIGRATION_SUCCEEDED = fromString("MigrationSucceeded"); + + /** Static value MigrationFailed for MigrationState. */ + public static final MigrationState MIGRATION_FAILED = fromString("MigrationFailed"); + + /** + * Creates or finds a MigrationState from its string representation. + * @param name a name to look for + * @return the corresponding MigrationState + */ + @JsonCreator + public static MigrationState fromString(String name) { + return fromString(name, MigrationState.class); + } + + /** + * @return known MigrationState values + */ + public static Collection values() { + return values(MigrationState.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MobilityServiceUpdate.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MobilityServiceUpdate.java new file mode 100644 index 0000000000000..650d9681bd111 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MobilityServiceUpdate.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The Mobility Service update details. + */ +public class MobilityServiceUpdate { + /** + * The version of the latest update. + */ + @JsonProperty(value = "version") + private String version; + + /** + * The reboot status of the update - whether it is required or not. + */ + @JsonProperty(value = "rebootStatus") + private String rebootStatus; + + /** + * The OS type. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * Get the version of the latest update. + * + * @return the version value + */ + public String version() { + return this.version; + } + + /** + * Set the version of the latest update. + * + * @param version the version value to set + * @return the MobilityServiceUpdate object itself. + */ + public MobilityServiceUpdate withVersion(String version) { + this.version = version; + return this; + } + + /** + * Get the reboot status of the update - whether it is required or not. + * + * @return the rebootStatus value + */ + public String rebootStatus() { + return this.rebootStatus; + } + + /** + * Set the reboot status of the update - whether it is required or not. + * + * @param rebootStatus the rebootStatus value to set + * @return the MobilityServiceUpdate object itself. + */ + public MobilityServiceUpdate withRebootStatus(String rebootStatus) { + this.rebootStatus = rebootStatus; + return this; + } + + /** + * Get the OS type. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type. + * + * @param osType the osType value to set + * @return the MobilityServiceUpdate object itself. + */ + public MobilityServiceUpdate withOsType(String osType) { + this.osType = osType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmGroupCreateOption.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmGroupCreateOption.java new file mode 100644 index 0000000000000..b355fd10f41fd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmGroupCreateOption.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MultiVmGroupCreateOption. + */ +public final class MultiVmGroupCreateOption extends ExpandableStringEnum { + /** Static value AutoCreated for MultiVmGroupCreateOption. */ + public static final MultiVmGroupCreateOption AUTO_CREATED = fromString("AutoCreated"); + + /** Static value UserSpecified for MultiVmGroupCreateOption. */ + public static final MultiVmGroupCreateOption USER_SPECIFIED = fromString("UserSpecified"); + + /** + * Creates or finds a MultiVmGroupCreateOption from its string representation. + * @param name a name to look for + * @return the corresponding MultiVmGroupCreateOption + */ + @JsonCreator + public static MultiVmGroupCreateOption fromString(String name) { + return fromString(name, MultiVmGroupCreateOption.class); + } + + /** + * @return known MultiVmGroupCreateOption values + */ + public static Collection values() { + return values(MultiVmGroupCreateOption.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncPointOption.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncPointOption.java new file mode 100644 index 0000000000000..c39aacfcba51f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncPointOption.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MultiVmSyncPointOption. + */ +public final class MultiVmSyncPointOption extends ExpandableStringEnum { + /** Static value UseMultiVmSyncRecoveryPoint for MultiVmSyncPointOption. */ + public static final MultiVmSyncPointOption USE_MULTI_VM_SYNC_RECOVERY_POINT = fromString("UseMultiVmSyncRecoveryPoint"); + + /** Static value UsePerVmRecoveryPoint for MultiVmSyncPointOption. */ + public static final MultiVmSyncPointOption USE_PER_VM_RECOVERY_POINT = fromString("UsePerVmRecoveryPoint"); + + /** + * Creates or finds a MultiVmSyncPointOption from its string representation. + * @param name a name to look for + * @return the corresponding MultiVmSyncPointOption + */ + @JsonCreator + public static MultiVmSyncPointOption fromString(String name) { + return fromString(name, MultiVmSyncPointOption.class); + } + + /** + * @return known MultiVmSyncPointOption values + */ + public static Collection values() { + return values(MultiVmSyncPointOption.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncStatus.java new file mode 100644 index 0000000000000..86e4085a4e1e1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/MultiVmSyncStatus.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for MultiVmSyncStatus. + */ +public final class MultiVmSyncStatus extends ExpandableStringEnum { + /** Static value Enabled for MultiVmSyncStatus. */ + public static final MultiVmSyncStatus ENABLED = fromString("Enabled"); + + /** Static value Disabled for MultiVmSyncStatus. */ + public static final MultiVmSyncStatus DISABLED = fromString("Disabled"); + + /** + * Creates or finds a MultiVmSyncStatus from its string representation. + * @param name a name to look for + * @return the corresponding MultiVmSyncStatus + */ + @JsonCreator + public static MultiVmSyncStatus fromString(String name) { + return fromString(name, MultiVmSyncStatus.class); + } + + /** + * @return known MultiVmSyncStatus values + */ + public static Collection values() { + return values(MultiVmSyncStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Network.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Network.java new file mode 100644 index 0000000000000..f4f764f496cd6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Network.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.NetworkInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing Network. + */ +public interface Network extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + NetworkProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMapping.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMapping.java new file mode 100644 index 0000000000000..ede0249dbfd6c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMapping.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.NetworkMappingInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing NetworkMapping. + */ +public interface NetworkMapping extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + NetworkMappingProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the NetworkMapping definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationNetwork, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of NetworkMapping definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a NetworkMapping definition. + */ + interface Blank extends WithReplicationNetwork { + } + + /** + * The stage of the networkmapping definition allowing to specify ReplicationNetwork. + */ + interface WithReplicationNetwork { + /** + * Specifies fabricName, networkName. + * @param fabricName Primary fabric name + * @param networkName Primary network name + * @return the next definition stage + */ + WithProperties withExistingReplicationNetwork(String fabricName, String networkName); + } + + /** + * The stage of the networkmapping definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Input properties for creating network mapping + * @return the next definition stage + */ + WithCreate withProperties(CreateNetworkMappingInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a NetworkMapping update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of NetworkMapping update stages. + */ + interface UpdateStages { + /** + * The stage of the networkmapping update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The input properties needed to update network mapping + * @return the next update stage + */ + Update withProperties(UpdateNetworkMappingInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingFabricSpecificSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingFabricSpecificSettings.java new file mode 100644 index 0000000000000..ebfa1d71151ce --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingFabricSpecificSettings.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Network Mapping fabric specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("NetworkMappingFabricSpecificSettings") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AzureToAzure", value = AzureToAzureNetworkMappingSettings.class), + @JsonSubTypes.Type(name = "VmmToAzure", value = VmmToAzureNetworkMappingSettings.class), + @JsonSubTypes.Type(name = "VmmToVmm", value = VmmToVmmNetworkMappingSettings.class) +}) +public class NetworkMappingFabricSpecificSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingProperties.java new file mode 100644 index 0000000000000..bd1fc2be3d289 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkMappingProperties.java @@ -0,0 +1,251 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Network Mapping Properties. + */ +public class NetworkMappingProperties { + /** + * The pairing state for network mapping. + */ + @JsonProperty(value = "state") + private String state; + + /** + * The primary network friendly name. + */ + @JsonProperty(value = "primaryNetworkFriendlyName") + private String primaryNetworkFriendlyName; + + /** + * The primary network id for network mapping. + */ + @JsonProperty(value = "primaryNetworkId") + private String primaryNetworkId; + + /** + * The primary fabric friendly name. + */ + @JsonProperty(value = "primaryFabricFriendlyName") + private String primaryFabricFriendlyName; + + /** + * The recovery network friendly name. + */ + @JsonProperty(value = "recoveryNetworkFriendlyName") + private String recoveryNetworkFriendlyName; + + /** + * The recovery network id for network mapping. + */ + @JsonProperty(value = "recoveryNetworkId") + private String recoveryNetworkId; + + /** + * The recovery fabric ARM id. + */ + @JsonProperty(value = "recoveryFabricArmId") + private String recoveryFabricArmId; + + /** + * The recovery fabric friendly name. + */ + @JsonProperty(value = "recoveryFabricFriendlyName") + private String recoveryFabricFriendlyName; + + /** + * The fabric specific settings. + */ + @JsonProperty(value = "fabricSpecificSettings") + private NetworkMappingFabricSpecificSettings fabricSpecificSettings; + + /** + * Get the pairing state for network mapping. + * + * @return the state value + */ + public String state() { + return this.state; + } + + /** + * Set the pairing state for network mapping. + * + * @param state the state value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withState(String state) { + this.state = state; + return this; + } + + /** + * Get the primary network friendly name. + * + * @return the primaryNetworkFriendlyName value + */ + public String primaryNetworkFriendlyName() { + return this.primaryNetworkFriendlyName; + } + + /** + * Set the primary network friendly name. + * + * @param primaryNetworkFriendlyName the primaryNetworkFriendlyName value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withPrimaryNetworkFriendlyName(String primaryNetworkFriendlyName) { + this.primaryNetworkFriendlyName = primaryNetworkFriendlyName; + return this; + } + + /** + * Get the primary network id for network mapping. + * + * @return the primaryNetworkId value + */ + public String primaryNetworkId() { + return this.primaryNetworkId; + } + + /** + * Set the primary network id for network mapping. + * + * @param primaryNetworkId the primaryNetworkId value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withPrimaryNetworkId(String primaryNetworkId) { + this.primaryNetworkId = primaryNetworkId; + return this; + } + + /** + * Get the primary fabric friendly name. + * + * @return the primaryFabricFriendlyName value + */ + public String primaryFabricFriendlyName() { + return this.primaryFabricFriendlyName; + } + + /** + * Set the primary fabric friendly name. + * + * @param primaryFabricFriendlyName the primaryFabricFriendlyName value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withPrimaryFabricFriendlyName(String primaryFabricFriendlyName) { + this.primaryFabricFriendlyName = primaryFabricFriendlyName; + return this; + } + + /** + * Get the recovery network friendly name. + * + * @return the recoveryNetworkFriendlyName value + */ + public String recoveryNetworkFriendlyName() { + return this.recoveryNetworkFriendlyName; + } + + /** + * Set the recovery network friendly name. + * + * @param recoveryNetworkFriendlyName the recoveryNetworkFriendlyName value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withRecoveryNetworkFriendlyName(String recoveryNetworkFriendlyName) { + this.recoveryNetworkFriendlyName = recoveryNetworkFriendlyName; + return this; + } + + /** + * Get the recovery network id for network mapping. + * + * @return the recoveryNetworkId value + */ + public String recoveryNetworkId() { + return this.recoveryNetworkId; + } + + /** + * Set the recovery network id for network mapping. + * + * @param recoveryNetworkId the recoveryNetworkId value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withRecoveryNetworkId(String recoveryNetworkId) { + this.recoveryNetworkId = recoveryNetworkId; + return this; + } + + /** + * Get the recovery fabric ARM id. + * + * @return the recoveryFabricArmId value + */ + public String recoveryFabricArmId() { + return this.recoveryFabricArmId; + } + + /** + * Set the recovery fabric ARM id. + * + * @param recoveryFabricArmId the recoveryFabricArmId value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withRecoveryFabricArmId(String recoveryFabricArmId) { + this.recoveryFabricArmId = recoveryFabricArmId; + return this; + } + + /** + * Get the recovery fabric friendly name. + * + * @return the recoveryFabricFriendlyName value + */ + public String recoveryFabricFriendlyName() { + return this.recoveryFabricFriendlyName; + } + + /** + * Set the recovery fabric friendly name. + * + * @param recoveryFabricFriendlyName the recoveryFabricFriendlyName value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withRecoveryFabricFriendlyName(String recoveryFabricFriendlyName) { + this.recoveryFabricFriendlyName = recoveryFabricFriendlyName; + return this; + } + + /** + * Get the fabric specific settings. + * + * @return the fabricSpecificSettings value + */ + public NetworkMappingFabricSpecificSettings fabricSpecificSettings() { + return this.fabricSpecificSettings; + } + + /** + * Set the fabric specific settings. + * + * @param fabricSpecificSettings the fabricSpecificSettings value to set + * @return the NetworkMappingProperties object itself. + */ + public NetworkMappingProperties withFabricSpecificSettings(NetworkMappingFabricSpecificSettings fabricSpecificSettings) { + this.fabricSpecificSettings = fabricSpecificSettings; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkProperties.java new file mode 100644 index 0000000000000..968cee888a154 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/NetworkProperties.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Network Properties. + */ +public class NetworkProperties { + /** + * The Fabric Type. + */ + @JsonProperty(value = "fabricType") + private String fabricType; + + /** + * The List of subnets. + */ + @JsonProperty(value = "subnets") + private List subnets; + + /** + * The Friendly Name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The Network Type. + */ + @JsonProperty(value = "networkType") + private String networkType; + + /** + * Get the Fabric Type. + * + * @return the fabricType value + */ + public String fabricType() { + return this.fabricType; + } + + /** + * Set the Fabric Type. + * + * @param fabricType the fabricType value to set + * @return the NetworkProperties object itself. + */ + public NetworkProperties withFabricType(String fabricType) { + this.fabricType = fabricType; + return this; + } + + /** + * Get the List of subnets. + * + * @return the subnets value + */ + public List subnets() { + return this.subnets; + } + + /** + * Set the List of subnets. + * + * @param subnets the subnets value to set + * @return the NetworkProperties object itself. + */ + public NetworkProperties withSubnets(List subnets) { + this.subnets = subnets; + return this; + } + + /** + * Get the Friendly Name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the Friendly Name. + * + * @param friendlyName the friendlyName value to set + * @return the NetworkProperties object itself. + */ + public NetworkProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the Network Type. + * + * @return the networkType value + */ + public String networkType() { + return this.networkType; + } + + /** + * Set the Network Type. + * + * @param networkType the networkType value to set + * @return the NetworkProperties object itself. + */ + public NetworkProperties withNetworkType(String networkType) { + this.networkType = networkType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDetails.java new file mode 100644 index 0000000000000..a7e4ebe732d10 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDetails.java @@ -0,0 +1,173 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Disk Details. + */ +public class OSDetails { + /** + * VM Disk details. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * Product type. + */ + @JsonProperty(value = "productType") + private String productType; + + /** + * The OSEdition. + */ + @JsonProperty(value = "osEdition") + private String osEdition; + + /** + * The OS Version. + */ + @JsonProperty(value = "oSVersion") + private String oSVersion; + + /** + * The OS Major Version. + */ + @JsonProperty(value = "oSMajorVersion") + private String oSMajorVersion; + + /** + * The OS Minor Version. + */ + @JsonProperty(value = "oSMinorVersion") + private String oSMinorVersion; + + /** + * Get vM Disk details. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set vM Disk details. + * + * @param osType the osType value to set + * @return the OSDetails object itself. + */ + public OSDetails withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get product type. + * + * @return the productType value + */ + public String productType() { + return this.productType; + } + + /** + * Set product type. + * + * @param productType the productType value to set + * @return the OSDetails object itself. + */ + public OSDetails withProductType(String productType) { + this.productType = productType; + return this; + } + + /** + * Get the OSEdition. + * + * @return the osEdition value + */ + public String osEdition() { + return this.osEdition; + } + + /** + * Set the OSEdition. + * + * @param osEdition the osEdition value to set + * @return the OSDetails object itself. + */ + public OSDetails withOsEdition(String osEdition) { + this.osEdition = osEdition; + return this; + } + + /** + * Get the OS Version. + * + * @return the oSVersion value + */ + public String oSVersion() { + return this.oSVersion; + } + + /** + * Set the OS Version. + * + * @param oSVersion the oSVersion value to set + * @return the OSDetails object itself. + */ + public OSDetails withOSVersion(String oSVersion) { + this.oSVersion = oSVersion; + return this; + } + + /** + * Get the OS Major Version. + * + * @return the oSMajorVersion value + */ + public String oSMajorVersion() { + return this.oSMajorVersion; + } + + /** + * Set the OS Major Version. + * + * @param oSMajorVersion the oSMajorVersion value to set + * @return the OSDetails object itself. + */ + public OSDetails withOSMajorVersion(String oSMajorVersion) { + this.oSMajorVersion = oSMajorVersion; + return this; + } + + /** + * Get the OS Minor Version. + * + * @return the oSMinorVersion value + */ + public String oSMinorVersion() { + return this.oSMinorVersion; + } + + /** + * Set the OS Minor Version. + * + * @param oSMinorVersion the oSMinorVersion value to set + * @return the OSDetails object itself. + */ + public OSDetails withOSMinorVersion(String oSMinorVersion) { + this.oSMinorVersion = oSMinorVersion; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDiskDetails.java new file mode 100644 index 0000000000000..c653d30205585 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OSDiskDetails.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Details of the OS Disk. + */ +public class OSDiskDetails { + /** + * The id of the disk containing the OS. + */ + @JsonProperty(value = "osVhdId") + private String osVhdId; + + /** + * The type of the OS on the VM. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The OS disk VHD name. + */ + @JsonProperty(value = "vhdName") + private String vhdName; + + /** + * Get the id of the disk containing the OS. + * + * @return the osVhdId value + */ + public String osVhdId() { + return this.osVhdId; + } + + /** + * Set the id of the disk containing the OS. + * + * @param osVhdId the osVhdId value to set + * @return the OSDiskDetails object itself. + */ + public OSDiskDetails withOsVhdId(String osVhdId) { + this.osVhdId = osVhdId; + return this; + } + + /** + * Get the type of the OS on the VM. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the type of the OS on the VM. + * + * @param osType the osType value to set + * @return the OSDiskDetails object itself. + */ + public OSDiskDetails withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the OS disk VHD name. + * + * @return the vhdName value + */ + public String vhdName() { + return this.vhdName; + } + + /** + * Set the OS disk VHD name. + * + * @param vhdName the vhdName value to set + * @return the OSDiskDetails object itself. + */ + public OSDiskDetails withVhdName(String vhdName) { + this.vhdName = vhdName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Operations.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Operations.java new file mode 100644 index 0000000000000..47c7da7c24b03 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Operations.java @@ -0,0 +1,19 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsListing; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.OperationsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing Operations. + */ +public interface Operations extends SupportsListing, HasInner { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OperationsDiscovery.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OperationsDiscovery.java new file mode 100644 index 0000000000000..fb28280913a70 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/OperationsDiscovery.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.OperationsDiscoveryInner; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing OperationsDiscovery. + */ +public interface OperationsDiscovery extends HasInner, HasManager { + /** + * @return the display value. + */ + Display display(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the origin value. + */ + String origin(); + + /** + * @return the properties value. + */ + Object properties(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInput.java new file mode 100644 index 0000000000000..271d92881ffc9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover. + */ +public class PlannedFailoverInput { + /** + * Planned failover input properties. + */ + @JsonProperty(value = "properties") + private PlannedFailoverInputProperties properties; + + /** + * Get planned failover input properties. + * + * @return the properties value + */ + public PlannedFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set planned failover input properties. + * + * @param properties the properties value to set + * @return the PlannedFailoverInput object itself. + */ + public PlannedFailoverInput withProperties(PlannedFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInputProperties.java new file mode 100644 index 0000000000000..44b558ce9cde6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PlannedFailoverInputProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover input properties. + */ +public class PlannedFailoverInputProperties { + /** + * Failover direction. + */ + @JsonProperty(value = "failoverDirection") + private String failoverDirection; + + /** + * Provider specific settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private ProviderSpecificFailoverInput providerSpecificDetails; + + /** + * Get failover direction. + * + * @return the failoverDirection value + */ + public String failoverDirection() { + return this.failoverDirection; + } + + /** + * Set failover direction. + * + * @param failoverDirection the failoverDirection value to set + * @return the PlannedFailoverInputProperties object itself. + */ + public PlannedFailoverInputProperties withFailoverDirection(String failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get provider specific settings. + * + * @return the providerSpecificDetails value + */ + public ProviderSpecificFailoverInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the PlannedFailoverInputProperties object itself. + */ + public PlannedFailoverInputProperties withProviderSpecificDetails(ProviderSpecificFailoverInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Policy.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Policy.java new file mode 100644 index 0000000000000..4832ecb292bcc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Policy.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.PolicyInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing Policy. + */ +public interface Policy extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + PolicyProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the Policy definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithVault, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of Policy definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a Policy definition. + */ + interface Blank extends WithVault { + } + + /** + * The stage of the policy definition allowing to specify Vault. + */ + interface WithVault { + /** + * Specifies . + * @return the next definition stage + */ + WithProperties withExistingVault(); + } + + /** + * The stage of the policy definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Policy creation properties + * @return the next definition stage + */ + WithCreate withProperties(CreatePolicyInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a Policy update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of Policy update stages. + */ + interface UpdateStages { + /** + * The stage of the policy update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The ReplicationProviderSettings + * @return the next update stage + */ + Update withProperties(UpdatePolicyInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProperties.java new file mode 100644 index 0000000000000..1588d7b813ea7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Protection profile custom data details. + */ +public class PolicyProperties { + /** + * The FriendlyName. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The ReplicationChannelSetting. + */ + @JsonProperty(value = "providerSpecificDetails") + private PolicyProviderSpecificDetails providerSpecificDetails; + + /** + * Get the FriendlyName. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the FriendlyName. + * + * @param friendlyName the friendlyName value to set + * @return the PolicyProperties object itself. + */ + public PolicyProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the ReplicationChannelSetting. + * + * @return the providerSpecificDetails value + */ + public PolicyProviderSpecificDetails providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the ReplicationChannelSetting. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the PolicyProperties object itself. + */ + public PolicyProperties withProviderSpecificDetails(PolicyProviderSpecificDetails providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificDetails.java new file mode 100644 index 0000000000000..805c358347b8f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificDetails.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Base class for Provider specific details for policies. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("PolicyProviderSpecificDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2APolicyDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzurePolicyDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaBasePolicyDetails", value = HyperVReplicaBasePolicyDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012R2", value = HyperVReplicaBluePolicyDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012", value = HyperVReplicaPolicyDetails.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2PolicyDetails.class), + @JsonSubTypes.Type(name = "InMageBasePolicyDetails", value = InMageBasePolicyDetails.class), + @JsonSubTypes.Type(name = "InMage", value = InMagePolicyDetails.class), + @JsonSubTypes.Type(name = "RcmAzureMigration", value = RcmAzureMigrationPolicyDetails.class), + @JsonSubTypes.Type(name = "VMwareCbt", value = VmwareCbtPolicyDetails.class) +}) +public class PolicyProviderSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificInput.java new file mode 100644 index 0000000000000..d81e30898a806 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PolicyProviderSpecificInput.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Base class for provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("PolicyProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2APolicyCreationInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzurePolicyInput.class), + @JsonSubTypes.Type(name = "HyperVReplica2012R2", value = HyperVReplicaBluePolicyInput.class), + @JsonSubTypes.Type(name = "HyperVReplica2012", value = HyperVReplicaPolicyInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2PolicyInput.class), + @JsonSubTypes.Type(name = "InMage", value = InMagePolicyInput.class), + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtPolicyCreationInput.class) +}) +public class PolicyProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PossibleOperationsDirections.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PossibleOperationsDirections.java new file mode 100644 index 0000000000000..4cbd7e7233b23 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PossibleOperationsDirections.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for PossibleOperationsDirections. + */ +public final class PossibleOperationsDirections extends ExpandableStringEnum { + /** Static value PrimaryToRecovery for PossibleOperationsDirections. */ + public static final PossibleOperationsDirections PRIMARY_TO_RECOVERY = fromString("PrimaryToRecovery"); + + /** Static value RecoveryToPrimary for PossibleOperationsDirections. */ + public static final PossibleOperationsDirections RECOVERY_TO_PRIMARY = fromString("RecoveryToPrimary"); + + /** + * Creates or finds a PossibleOperationsDirections from its string representation. + * @param name a name to look for + * @return the corresponding PossibleOperationsDirections + */ + @JsonCreator + public static PossibleOperationsDirections fromString(String name) { + return fromString(name, PossibleOperationsDirections.class); + } + + /** + * @return known PossibleOperationsDirections values + */ + public static Collection values() { + return values(PossibleOperationsDirections.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PresenceStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PresenceStatus.java new file mode 100644 index 0000000000000..9f061cff31aa6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/PresenceStatus.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for PresenceStatus. + */ +public final class PresenceStatus extends ExpandableStringEnum { + /** Static value Unknown for PresenceStatus. */ + public static final PresenceStatus UNKNOWN = fromString("Unknown"); + + /** Static value Present for PresenceStatus. */ + public static final PresenceStatus PRESENT = fromString("Present"); + + /** Static value NotPresent for PresenceStatus. */ + public static final PresenceStatus NOT_PRESENT = fromString("NotPresent"); + + /** + * Creates or finds a PresenceStatus from its string representation. + * @param name a name to look for + * @return the corresponding PresenceStatus + */ + @JsonCreator + public static PresenceStatus fromString(String name) { + return fromString(name, PresenceStatus.class); + } + + /** + * @return known PresenceStatus values + */ + public static Collection values() { + return values(PresenceStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProcessServer.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProcessServer.java new file mode 100644 index 0000000000000..1f51e1e5febba --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProcessServer.java @@ -0,0 +1,749 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Details of the Process Server. + */ +public class ProcessServer { + /** + * The Process Server's friendly name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The Process Server Id. + */ + @JsonProperty(value = "id") + private String id; + + /** + * The IP address of the server. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The OS type of the server. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The version of the scout component on the server. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * The last heartbeat received from the server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * Version status. + */ + @JsonProperty(value = "versionStatus") + private String versionStatus; + + /** + * The list of the mobility service updates available on the Process + * Server. + */ + @JsonProperty(value = "mobilityServiceUpdates") + private List mobilityServiceUpdates; + + /** + * The agent generated Id. + */ + @JsonProperty(value = "hostId") + private String hostId; + + /** + * The servers configured with this PS. + */ + @JsonProperty(value = "machineCount") + private String machineCount; + + /** + * The number of replication pairs configured in this PS. + */ + @JsonProperty(value = "replicationPairCount") + private String replicationPairCount; + + /** + * The percentage of the system load. + */ + @JsonProperty(value = "systemLoad") + private String systemLoad; + + /** + * The system load status. + */ + @JsonProperty(value = "systemLoadStatus") + private String systemLoadStatus; + + /** + * The percentage of the CPU load. + */ + @JsonProperty(value = "cpuLoad") + private String cpuLoad; + + /** + * The CPU load status. + */ + @JsonProperty(value = "cpuLoadStatus") + private String cpuLoadStatus; + + /** + * The total memory. + */ + @JsonProperty(value = "totalMemoryInBytes") + private Long totalMemoryInBytes; + + /** + * The available memory. + */ + @JsonProperty(value = "availableMemoryInBytes") + private Long availableMemoryInBytes; + + /** + * The memory usage status. + */ + @JsonProperty(value = "memoryUsageStatus") + private String memoryUsageStatus; + + /** + * The total space. + */ + @JsonProperty(value = "totalSpaceInBytes") + private Long totalSpaceInBytes; + + /** + * The available space. + */ + @JsonProperty(value = "availableSpaceInBytes") + private Long availableSpaceInBytes; + + /** + * The space usage status. + */ + @JsonProperty(value = "spaceUsageStatus") + private String spaceUsageStatus; + + /** + * The PS service status. + */ + @JsonProperty(value = "psServiceStatus") + private String psServiceStatus; + + /** + * The PS SSL cert expiry date. + */ + @JsonProperty(value = "sslCertExpiryDate") + private DateTime sslCertExpiryDate; + + /** + * CS SSL cert expiry date. + */ + @JsonProperty(value = "sslCertExpiryRemainingDays") + private Integer sslCertExpiryRemainingDays; + + /** + * OS Version of the process server. Note: This will get populated if user + * has CS version greater than 9.12.0.0. + */ + @JsonProperty(value = "osVersion") + private String osVersion; + + /** + * Health errors. + */ + @JsonProperty(value = "healthErrors") + private List healthErrors; + + /** + * Agent expiry date. + */ + @JsonProperty(value = "agentExpiryDate") + private DateTime agentExpiryDate; + + /** + * The agent version details. + */ + @JsonProperty(value = "agentVersionDetails") + private VersionDetails agentVersionDetails; + + /** + * Get the Process Server's friendly name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the Process Server's friendly name. + * + * @param friendlyName the friendlyName value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the Process Server Id. + * + * @return the id value + */ + public String id() { + return this.id; + } + + /** + * Set the Process Server Id. + * + * @param id the id value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withId(String id) { + this.id = id; + return this; + } + + /** + * Get the IP address of the server. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the server. + * + * @param ipAddress the ipAddress value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the OS type of the server. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OS type of the server. + * + * @param osType the osType value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the version of the scout component on the server. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the version of the scout component on the server. + * + * @param agentVersion the agentVersion value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get the last heartbeat received from the server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from the server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get version status. + * + * @return the versionStatus value + */ + public String versionStatus() { + return this.versionStatus; + } + + /** + * Set version status. + * + * @param versionStatus the versionStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withVersionStatus(String versionStatus) { + this.versionStatus = versionStatus; + return this; + } + + /** + * Get the list of the mobility service updates available on the Process Server. + * + * @return the mobilityServiceUpdates value + */ + public List mobilityServiceUpdates() { + return this.mobilityServiceUpdates; + } + + /** + * Set the list of the mobility service updates available on the Process Server. + * + * @param mobilityServiceUpdates the mobilityServiceUpdates value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withMobilityServiceUpdates(List mobilityServiceUpdates) { + this.mobilityServiceUpdates = mobilityServiceUpdates; + return this; + } + + /** + * Get the agent generated Id. + * + * @return the hostId value + */ + public String hostId() { + return this.hostId; + } + + /** + * Set the agent generated Id. + * + * @param hostId the hostId value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withHostId(String hostId) { + this.hostId = hostId; + return this; + } + + /** + * Get the servers configured with this PS. + * + * @return the machineCount value + */ + public String machineCount() { + return this.machineCount; + } + + /** + * Set the servers configured with this PS. + * + * @param machineCount the machineCount value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withMachineCount(String machineCount) { + this.machineCount = machineCount; + return this; + } + + /** + * Get the number of replication pairs configured in this PS. + * + * @return the replicationPairCount value + */ + public String replicationPairCount() { + return this.replicationPairCount; + } + + /** + * Set the number of replication pairs configured in this PS. + * + * @param replicationPairCount the replicationPairCount value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withReplicationPairCount(String replicationPairCount) { + this.replicationPairCount = replicationPairCount; + return this; + } + + /** + * Get the percentage of the system load. + * + * @return the systemLoad value + */ + public String systemLoad() { + return this.systemLoad; + } + + /** + * Set the percentage of the system load. + * + * @param systemLoad the systemLoad value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withSystemLoad(String systemLoad) { + this.systemLoad = systemLoad; + return this; + } + + /** + * Get the system load status. + * + * @return the systemLoadStatus value + */ + public String systemLoadStatus() { + return this.systemLoadStatus; + } + + /** + * Set the system load status. + * + * @param systemLoadStatus the systemLoadStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withSystemLoadStatus(String systemLoadStatus) { + this.systemLoadStatus = systemLoadStatus; + return this; + } + + /** + * Get the percentage of the CPU load. + * + * @return the cpuLoad value + */ + public String cpuLoad() { + return this.cpuLoad; + } + + /** + * Set the percentage of the CPU load. + * + * @param cpuLoad the cpuLoad value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withCpuLoad(String cpuLoad) { + this.cpuLoad = cpuLoad; + return this; + } + + /** + * Get the CPU load status. + * + * @return the cpuLoadStatus value + */ + public String cpuLoadStatus() { + return this.cpuLoadStatus; + } + + /** + * Set the CPU load status. + * + * @param cpuLoadStatus the cpuLoadStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withCpuLoadStatus(String cpuLoadStatus) { + this.cpuLoadStatus = cpuLoadStatus; + return this; + } + + /** + * Get the total memory. + * + * @return the totalMemoryInBytes value + */ + public Long totalMemoryInBytes() { + return this.totalMemoryInBytes; + } + + /** + * Set the total memory. + * + * @param totalMemoryInBytes the totalMemoryInBytes value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withTotalMemoryInBytes(Long totalMemoryInBytes) { + this.totalMemoryInBytes = totalMemoryInBytes; + return this; + } + + /** + * Get the available memory. + * + * @return the availableMemoryInBytes value + */ + public Long availableMemoryInBytes() { + return this.availableMemoryInBytes; + } + + /** + * Set the available memory. + * + * @param availableMemoryInBytes the availableMemoryInBytes value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withAvailableMemoryInBytes(Long availableMemoryInBytes) { + this.availableMemoryInBytes = availableMemoryInBytes; + return this; + } + + /** + * Get the memory usage status. + * + * @return the memoryUsageStatus value + */ + public String memoryUsageStatus() { + return this.memoryUsageStatus; + } + + /** + * Set the memory usage status. + * + * @param memoryUsageStatus the memoryUsageStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withMemoryUsageStatus(String memoryUsageStatus) { + this.memoryUsageStatus = memoryUsageStatus; + return this; + } + + /** + * Get the total space. + * + * @return the totalSpaceInBytes value + */ + public Long totalSpaceInBytes() { + return this.totalSpaceInBytes; + } + + /** + * Set the total space. + * + * @param totalSpaceInBytes the totalSpaceInBytes value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withTotalSpaceInBytes(Long totalSpaceInBytes) { + this.totalSpaceInBytes = totalSpaceInBytes; + return this; + } + + /** + * Get the available space. + * + * @return the availableSpaceInBytes value + */ + public Long availableSpaceInBytes() { + return this.availableSpaceInBytes; + } + + /** + * Set the available space. + * + * @param availableSpaceInBytes the availableSpaceInBytes value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withAvailableSpaceInBytes(Long availableSpaceInBytes) { + this.availableSpaceInBytes = availableSpaceInBytes; + return this; + } + + /** + * Get the space usage status. + * + * @return the spaceUsageStatus value + */ + public String spaceUsageStatus() { + return this.spaceUsageStatus; + } + + /** + * Set the space usage status. + * + * @param spaceUsageStatus the spaceUsageStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withSpaceUsageStatus(String spaceUsageStatus) { + this.spaceUsageStatus = spaceUsageStatus; + return this; + } + + /** + * Get the PS service status. + * + * @return the psServiceStatus value + */ + public String psServiceStatus() { + return this.psServiceStatus; + } + + /** + * Set the PS service status. + * + * @param psServiceStatus the psServiceStatus value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withPsServiceStatus(String psServiceStatus) { + this.psServiceStatus = psServiceStatus; + return this; + } + + /** + * Get the PS SSL cert expiry date. + * + * @return the sslCertExpiryDate value + */ + public DateTime sslCertExpiryDate() { + return this.sslCertExpiryDate; + } + + /** + * Set the PS SSL cert expiry date. + * + * @param sslCertExpiryDate the sslCertExpiryDate value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withSslCertExpiryDate(DateTime sslCertExpiryDate) { + this.sslCertExpiryDate = sslCertExpiryDate; + return this; + } + + /** + * Get cS SSL cert expiry date. + * + * @return the sslCertExpiryRemainingDays value + */ + public Integer sslCertExpiryRemainingDays() { + return this.sslCertExpiryRemainingDays; + } + + /** + * Set cS SSL cert expiry date. + * + * @param sslCertExpiryRemainingDays the sslCertExpiryRemainingDays value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withSslCertExpiryRemainingDays(Integer sslCertExpiryRemainingDays) { + this.sslCertExpiryRemainingDays = sslCertExpiryRemainingDays; + return this; + } + + /** + * Get oS Version of the process server. Note: This will get populated if user has CS version greater than 9.12.0.0. + * + * @return the osVersion value + */ + public String osVersion() { + return this.osVersion; + } + + /** + * Set oS Version of the process server. Note: This will get populated if user has CS version greater than 9.12.0.0. + * + * @param osVersion the osVersion value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withOsVersion(String osVersion) { + this.osVersion = osVersion; + return this; + } + + /** + * Get health errors. + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Set health errors. + * + * @param healthErrors the healthErrors value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withHealthErrors(List healthErrors) { + this.healthErrors = healthErrors; + return this; + } + + /** + * Get agent expiry date. + * + * @return the agentExpiryDate value + */ + public DateTime agentExpiryDate() { + return this.agentExpiryDate; + } + + /** + * Set agent expiry date. + * + * @param agentExpiryDate the agentExpiryDate value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withAgentExpiryDate(DateTime agentExpiryDate) { + this.agentExpiryDate = agentExpiryDate; + return this; + } + + /** + * Get the agent version details. + * + * @return the agentVersionDetails value + */ + public VersionDetails agentVersionDetails() { + return this.agentVersionDetails; + } + + /** + * Set the agent version details. + * + * @param agentVersionDetails the agentVersionDetails value to set + * @return the ProcessServer object itself. + */ + public ProcessServer withAgentVersionDetails(VersionDetails agentVersionDetails) { + this.agentVersionDetails = agentVersionDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItem.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItem.java new file mode 100644 index 0000000000000..e80943070106d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItem.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ProtectableItemInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing ProtectableItem. + */ +public interface ProtectableItem extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + ProtectableItemProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemProperties.java new file mode 100644 index 0000000000000..9a21231a31f9c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemProperties.java @@ -0,0 +1,200 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Replication protected item custom data details. + */ +public class ProtectableItemProperties { + /** + * The name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The protection status. + */ + @JsonProperty(value = "protectionStatus") + private String protectionStatus; + + /** + * The ARM resource of protected items. + */ + @JsonProperty(value = "replicationProtectedItemId") + private String replicationProtectedItemId; + + /** + * The recovery provider ARM Id. + */ + @JsonProperty(value = "recoveryServicesProviderId") + private String recoveryServicesProviderId; + + /** + * The Current protection readiness errors. + */ + @JsonProperty(value = "protectionReadinessErrors") + private List protectionReadinessErrors; + + /** + * The list of replication providers supported for the protectable item. + */ + @JsonProperty(value = "supportedReplicationProviders") + private List supportedReplicationProviders; + + /** + * The Replication provider custom settings. + */ + @JsonProperty(value = "customDetails") + private ConfigurationSettings customDetails; + + /** + * Get the name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the name. + * + * @param friendlyName the friendlyName value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the protection status. + * + * @return the protectionStatus value + */ + public String protectionStatus() { + return this.protectionStatus; + } + + /** + * Set the protection status. + * + * @param protectionStatus the protectionStatus value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withProtectionStatus(String protectionStatus) { + this.protectionStatus = protectionStatus; + return this; + } + + /** + * Get the ARM resource of protected items. + * + * @return the replicationProtectedItemId value + */ + public String replicationProtectedItemId() { + return this.replicationProtectedItemId; + } + + /** + * Set the ARM resource of protected items. + * + * @param replicationProtectedItemId the replicationProtectedItemId value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withReplicationProtectedItemId(String replicationProtectedItemId) { + this.replicationProtectedItemId = replicationProtectedItemId; + return this; + } + + /** + * Get the recovery provider ARM Id. + * + * @return the recoveryServicesProviderId value + */ + public String recoveryServicesProviderId() { + return this.recoveryServicesProviderId; + } + + /** + * Set the recovery provider ARM Id. + * + * @param recoveryServicesProviderId the recoveryServicesProviderId value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withRecoveryServicesProviderId(String recoveryServicesProviderId) { + this.recoveryServicesProviderId = recoveryServicesProviderId; + return this; + } + + /** + * Get the Current protection readiness errors. + * + * @return the protectionReadinessErrors value + */ + public List protectionReadinessErrors() { + return this.protectionReadinessErrors; + } + + /** + * Set the Current protection readiness errors. + * + * @param protectionReadinessErrors the protectionReadinessErrors value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withProtectionReadinessErrors(List protectionReadinessErrors) { + this.protectionReadinessErrors = protectionReadinessErrors; + return this; + } + + /** + * Get the list of replication providers supported for the protectable item. + * + * @return the supportedReplicationProviders value + */ + public List supportedReplicationProviders() { + return this.supportedReplicationProviders; + } + + /** + * Set the list of replication providers supported for the protectable item. + * + * @param supportedReplicationProviders the supportedReplicationProviders value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withSupportedReplicationProviders(List supportedReplicationProviders) { + this.supportedReplicationProviders = supportedReplicationProviders; + return this; + } + + /** + * Get the Replication provider custom settings. + * + * @return the customDetails value + */ + public ConfigurationSettings customDetails() { + return this.customDetails; + } + + /** + * Set the Replication provider custom settings. + * + * @param customDetails the customDetails value to set + * @return the ProtectableItemProperties object itself. + */ + public ProtectableItemProperties withCustomDetails(ConfigurationSettings customDetails) { + this.customDetails = customDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemQueryParameter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemQueryParameter.java new file mode 100644 index 0000000000000..147f8b8ad9c24 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectableItemQueryParameter.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Query parameter to enumerate Protectable items. + */ +public class ProtectableItemQueryParameter { + /** + * State of the Protectable item query filter. + */ + @JsonProperty(value = "state") + private String state; + + /** + * Get state of the Protectable item query filter. + * + * @return the state value + */ + public String state() { + return this.state; + } + + /** + * Set state of the Protectable item query filter. + * + * @param state the state value to set + * @return the ProtectableItemQueryParameter object itself. + */ + public ProtectableItemQueryParameter withState(String state) { + this.state = state; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectedItemsQueryParameter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectedItemsQueryParameter.java new file mode 100644 index 0000000000000..c8530cced01b0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectedItemsQueryParameter.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Query parameter to enumerate protected items. + */ +public class ProtectedItemsQueryParameter { + /** + * The source fabric name filter. + */ + @JsonProperty(value = "sourceFabricName") + private String sourceFabricName; + + /** + * The recovery plan filter. + */ + @JsonProperty(value = "recoveryPlanName") + private String recoveryPlanName; + + /** + * The vCenter name filter. + */ + @JsonProperty(value = "vCenterName") + private String vCenterName; + + /** + * The replication provider type. + */ + @JsonProperty(value = "instanceType") + private String instanceType; + + /** + * Whether Multi VM group is auto created or specified by user. Possible + * values include: 'AutoCreated', 'UserSpecified'. + */ + @JsonProperty(value = "multiVmGroupCreateOption") + private MultiVmGroupCreateOption multiVmGroupCreateOption; + + /** + * Get the source fabric name filter. + * + * @return the sourceFabricName value + */ + public String sourceFabricName() { + return this.sourceFabricName; + } + + /** + * Set the source fabric name filter. + * + * @param sourceFabricName the sourceFabricName value to set + * @return the ProtectedItemsQueryParameter object itself. + */ + public ProtectedItemsQueryParameter withSourceFabricName(String sourceFabricName) { + this.sourceFabricName = sourceFabricName; + return this; + } + + /** + * Get the recovery plan filter. + * + * @return the recoveryPlanName value + */ + public String recoveryPlanName() { + return this.recoveryPlanName; + } + + /** + * Set the recovery plan filter. + * + * @param recoveryPlanName the recoveryPlanName value to set + * @return the ProtectedItemsQueryParameter object itself. + */ + public ProtectedItemsQueryParameter withRecoveryPlanName(String recoveryPlanName) { + this.recoveryPlanName = recoveryPlanName; + return this; + } + + /** + * Get the vCenter name filter. + * + * @return the vCenterName value + */ + public String vCenterName() { + return this.vCenterName; + } + + /** + * Set the vCenter name filter. + * + * @param vCenterName the vCenterName value to set + * @return the ProtectedItemsQueryParameter object itself. + */ + public ProtectedItemsQueryParameter withVCenterName(String vCenterName) { + this.vCenterName = vCenterName; + return this; + } + + /** + * Get the replication provider type. + * + * @return the instanceType value + */ + public String instanceType() { + return this.instanceType; + } + + /** + * Set the replication provider type. + * + * @param instanceType the instanceType value to set + * @return the ProtectedItemsQueryParameter object itself. + */ + public ProtectedItemsQueryParameter withInstanceType(String instanceType) { + this.instanceType = instanceType; + return this; + } + + /** + * Get whether Multi VM group is auto created or specified by user. Possible values include: 'AutoCreated', 'UserSpecified'. + * + * @return the multiVmGroupCreateOption value + */ + public MultiVmGroupCreateOption multiVmGroupCreateOption() { + return this.multiVmGroupCreateOption; + } + + /** + * Set whether Multi VM group is auto created or specified by user. Possible values include: 'AutoCreated', 'UserSpecified'. + * + * @param multiVmGroupCreateOption the multiVmGroupCreateOption value to set + * @return the ProtectedItemsQueryParameter object itself. + */ + public ProtectedItemsQueryParameter withMultiVmGroupCreateOption(MultiVmGroupCreateOption multiVmGroupCreateOption) { + this.multiVmGroupCreateOption = multiVmGroupCreateOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainer.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainer.java new file mode 100644 index 0000000000000..c9af135010fb6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainer.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ProtectionContainerInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; +import java.util.List; + +/** + * Type representing ProtectionContainer. + */ +public interface ProtectionContainer extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + ProtectionContainerProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the ProtectionContainer definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationFabric, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of ProtectionContainer definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a ProtectionContainer definition. + */ + interface Blank extends WithReplicationFabric { + } + + /** + * The stage of the protectioncontainer definition allowing to specify ReplicationFabric. + */ + interface WithReplicationFabric { + /** + * Specifies fabricName. + * @param fabricName Unique fabric ARM name + * @return the next definition stage + */ + WithProperties withExistingReplicationFabric(String fabricName); + } + + /** + * The stage of the protectioncontainer definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Create protection container input properties + * @return the next definition stage + */ + WithCreate withProperties(CreateProtectionContainerInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a ProtectionContainer update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of ProtectionContainer update stages. + */ + interface UpdateStages { + /** + * The stage of the protectioncontainer update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Create protection container input properties + * @return the next update stage + */ + Update withProperties(CreateProtectionContainerInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerFabricSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerFabricSpecificDetails.java new file mode 100644 index 0000000000000..110117d3084f5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerFabricSpecificDetails.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Base class for fabric specific details of container. + */ +public class ProtectionContainerFabricSpecificDetails { + /** + * Gets the class type. Overridden in derived classes. + */ + @JsonProperty(value = "instanceType", access = JsonProperty.Access.WRITE_ONLY) + private String instanceType; + + /** + * Get gets the class type. Overridden in derived classes. + * + * @return the instanceType value + */ + public String instanceType() { + return this.instanceType; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMapping.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMapping.java new file mode 100644 index 0000000000000..f34ed3efc632d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMapping.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ProtectionContainerMappingInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing ProtectionContainerMapping. + */ +public interface ProtectionContainerMapping extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + ProtectionContainerMappingProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the ProtectionContainerMapping definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationProtectionContainer, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of ProtectionContainerMapping definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a ProtectionContainerMapping definition. + */ + interface Blank extends WithReplicationProtectionContainer { + } + + /** + * The stage of the protectioncontainermapping definition allowing to specify ReplicationProtectionContainer. + */ + interface WithReplicationProtectionContainer { + /** + * Specifies fabricName, protectionContainerName. + * @param fabricName Fabric name + * @param protectionContainerName Protection container name + * @return the next definition stage + */ + WithProperties withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName); + } + + /** + * The stage of the protectioncontainermapping definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Configure protection input properties + * @return the next definition stage + */ + WithCreate withProperties(CreateProtectionContainerMappingInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a ProtectionContainerMapping update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of ProtectionContainerMapping update stages. + */ + interface UpdateStages { + /** + * The stage of the protectioncontainermapping update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Update protection container mapping input properties + * @return the next update stage + */ + Update withProperties(UpdateProtectionContainerMappingInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProperties.java new file mode 100644 index 0000000000000..fa224d59851f4 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProperties.java @@ -0,0 +1,304 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Protection container mapping properties. + */ +public class ProtectionContainerMappingProperties { + /** + * Paired protection container ARM ID. + */ + @JsonProperty(value = "targetProtectionContainerId") + private String targetProtectionContainerId; + + /** + * Friendly name of paired container. + */ + @JsonProperty(value = "targetProtectionContainerFriendlyName") + private String targetProtectionContainerFriendlyName; + + /** + * Provider specific provider details. + */ + @JsonProperty(value = "providerSpecificDetails") + private ProtectionContainerMappingProviderSpecificDetails providerSpecificDetails; + + /** + * Health of pairing. + */ + @JsonProperty(value = "health") + private String health; + + /** + * Health error. + */ + @JsonProperty(value = "healthErrorDetails") + private List healthErrorDetails; + + /** + * Policy ARM Id. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * Association Status. + */ + @JsonProperty(value = "state") + private String state; + + /** + * Friendly name of source protection container. + */ + @JsonProperty(value = "sourceProtectionContainerFriendlyName") + private String sourceProtectionContainerFriendlyName; + + /** + * Friendly name of source fabric. + */ + @JsonProperty(value = "sourceFabricFriendlyName") + private String sourceFabricFriendlyName; + + /** + * Friendly name of target fabric. + */ + @JsonProperty(value = "targetFabricFriendlyName") + private String targetFabricFriendlyName; + + /** + * Friendly name of replication policy. + */ + @JsonProperty(value = "policyFriendlyName") + private String policyFriendlyName; + + /** + * Get paired protection container ARM ID. + * + * @return the targetProtectionContainerId value + */ + public String targetProtectionContainerId() { + return this.targetProtectionContainerId; + } + + /** + * Set paired protection container ARM ID. + * + * @param targetProtectionContainerId the targetProtectionContainerId value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withTargetProtectionContainerId(String targetProtectionContainerId) { + this.targetProtectionContainerId = targetProtectionContainerId; + return this; + } + + /** + * Get friendly name of paired container. + * + * @return the targetProtectionContainerFriendlyName value + */ + public String targetProtectionContainerFriendlyName() { + return this.targetProtectionContainerFriendlyName; + } + + /** + * Set friendly name of paired container. + * + * @param targetProtectionContainerFriendlyName the targetProtectionContainerFriendlyName value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withTargetProtectionContainerFriendlyName(String targetProtectionContainerFriendlyName) { + this.targetProtectionContainerFriendlyName = targetProtectionContainerFriendlyName; + return this; + } + + /** + * Get provider specific provider details. + * + * @return the providerSpecificDetails value + */ + public ProtectionContainerMappingProviderSpecificDetails providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific provider details. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withProviderSpecificDetails(ProtectionContainerMappingProviderSpecificDetails providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + + /** + * Get health of pairing. + * + * @return the health value + */ + public String health() { + return this.health; + } + + /** + * Set health of pairing. + * + * @param health the health value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withHealth(String health) { + this.health = health; + return this; + } + + /** + * Get health error. + * + * @return the healthErrorDetails value + */ + public List healthErrorDetails() { + return this.healthErrorDetails; + } + + /** + * Set health error. + * + * @param healthErrorDetails the healthErrorDetails value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withHealthErrorDetails(List healthErrorDetails) { + this.healthErrorDetails = healthErrorDetails; + return this; + } + + /** + * Get policy ARM Id. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set policy ARM Id. + * + * @param policyId the policyId value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get association Status. + * + * @return the state value + */ + public String state() { + return this.state; + } + + /** + * Set association Status. + * + * @param state the state value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withState(String state) { + this.state = state; + return this; + } + + /** + * Get friendly name of source protection container. + * + * @return the sourceProtectionContainerFriendlyName value + */ + public String sourceProtectionContainerFriendlyName() { + return this.sourceProtectionContainerFriendlyName; + } + + /** + * Set friendly name of source protection container. + * + * @param sourceProtectionContainerFriendlyName the sourceProtectionContainerFriendlyName value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withSourceProtectionContainerFriendlyName(String sourceProtectionContainerFriendlyName) { + this.sourceProtectionContainerFriendlyName = sourceProtectionContainerFriendlyName; + return this; + } + + /** + * Get friendly name of source fabric. + * + * @return the sourceFabricFriendlyName value + */ + public String sourceFabricFriendlyName() { + return this.sourceFabricFriendlyName; + } + + /** + * Set friendly name of source fabric. + * + * @param sourceFabricFriendlyName the sourceFabricFriendlyName value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withSourceFabricFriendlyName(String sourceFabricFriendlyName) { + this.sourceFabricFriendlyName = sourceFabricFriendlyName; + return this; + } + + /** + * Get friendly name of target fabric. + * + * @return the targetFabricFriendlyName value + */ + public String targetFabricFriendlyName() { + return this.targetFabricFriendlyName; + } + + /** + * Set friendly name of target fabric. + * + * @param targetFabricFriendlyName the targetFabricFriendlyName value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withTargetFabricFriendlyName(String targetFabricFriendlyName) { + this.targetFabricFriendlyName = targetFabricFriendlyName; + return this; + } + + /** + * Get friendly name of replication policy. + * + * @return the policyFriendlyName value + */ + public String policyFriendlyName() { + return this.policyFriendlyName; + } + + /** + * Set friendly name of replication policy. + * + * @param policyFriendlyName the policyFriendlyName value to set + * @return the ProtectionContainerMappingProperties object itself. + */ + public ProtectionContainerMappingProperties withPolicyFriendlyName(String policyFriendlyName) { + this.policyFriendlyName = policyFriendlyName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProviderSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProviderSpecificDetails.java new file mode 100644 index 0000000000000..aa656290e2430 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerMappingProviderSpecificDetails.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Container mapping provider specific details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ProtectionContainerMappingProviderSpecificDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AProtectionContainerMappingDetails.class), + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtProtectionContainerMappingDetails.class) +}) +public class ProtectionContainerMappingProviderSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerProperties.java new file mode 100644 index 0000000000000..d993137e598c7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProtectionContainerProperties.java @@ -0,0 +1,199 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Protection profile custom data details. + */ +public class ProtectionContainerProperties { + /** + * Fabric friendly name. + */ + @JsonProperty(value = "fabricFriendlyName") + private String fabricFriendlyName; + + /** + * The name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The fabric type. + */ + @JsonProperty(value = "fabricType") + private String fabricType; + + /** + * Number of protected PEs. + */ + @JsonProperty(value = "protectedItemCount") + private Integer protectedItemCount; + + /** + * The pairing status of this cloud. + */ + @JsonProperty(value = "pairingStatus") + private String pairingStatus; + + /** + * The role of this cloud. + */ + @JsonProperty(value = "role") + private String role; + + /** + * Fabric specific details. + */ + @JsonProperty(value = "fabricSpecificDetails") + private ProtectionContainerFabricSpecificDetails fabricSpecificDetails; + + /** + * Get fabric friendly name. + * + * @return the fabricFriendlyName value + */ + public String fabricFriendlyName() { + return this.fabricFriendlyName; + } + + /** + * Set fabric friendly name. + * + * @param fabricFriendlyName the fabricFriendlyName value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withFabricFriendlyName(String fabricFriendlyName) { + this.fabricFriendlyName = fabricFriendlyName; + return this; + } + + /** + * Get the name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the name. + * + * @param friendlyName the friendlyName value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the fabric type. + * + * @return the fabricType value + */ + public String fabricType() { + return this.fabricType; + } + + /** + * Set the fabric type. + * + * @param fabricType the fabricType value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withFabricType(String fabricType) { + this.fabricType = fabricType; + return this; + } + + /** + * Get number of protected PEs. + * + * @return the protectedItemCount value + */ + public Integer protectedItemCount() { + return this.protectedItemCount; + } + + /** + * Set number of protected PEs. + * + * @param protectedItemCount the protectedItemCount value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withProtectedItemCount(Integer protectedItemCount) { + this.protectedItemCount = protectedItemCount; + return this; + } + + /** + * Get the pairing status of this cloud. + * + * @return the pairingStatus value + */ + public String pairingStatus() { + return this.pairingStatus; + } + + /** + * Set the pairing status of this cloud. + * + * @param pairingStatus the pairingStatus value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withPairingStatus(String pairingStatus) { + this.pairingStatus = pairingStatus; + return this; + } + + /** + * Get the role of this cloud. + * + * @return the role value + */ + public String role() { + return this.role; + } + + /** + * Set the role of this cloud. + * + * @param role the role value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withRole(String role) { + this.role = role; + return this; + } + + /** + * Get fabric specific details. + * + * @return the fabricSpecificDetails value + */ + public ProtectionContainerFabricSpecificDetails fabricSpecificDetails() { + return this.fabricSpecificDetails; + } + + /** + * Set fabric specific details. + * + * @param fabricSpecificDetails the fabricSpecificDetails value to set + * @return the ProtectionContainerProperties object itself. + */ + public ProtectionContainerProperties withFabricSpecificDetails(ProtectionContainerFabricSpecificDetails fabricSpecificDetails) { + this.fabricSpecificDetails = fabricSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderError.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderError.java new file mode 100644 index 0000000000000..26ad3a4c99a7e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderError.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * This class contains the error details per object. + */ +public class ProviderError { + /** + * The Error code. + */ + @JsonProperty(value = "errorCode") + private Integer errorCode; + + /** + * The Error message. + */ + @JsonProperty(value = "errorMessage") + private String errorMessage; + + /** + * The Provider error Id. + */ + @JsonProperty(value = "errorId") + private String errorId; + + /** + * The possible causes for the error. + */ + @JsonProperty(value = "possibleCauses") + private String possibleCauses; + + /** + * The recommended action to resolve the error. + */ + @JsonProperty(value = "recommendedAction") + private String recommendedAction; + + /** + * Get the Error code. + * + * @return the errorCode value + */ + public Integer errorCode() { + return this.errorCode; + } + + /** + * Set the Error code. + * + * @param errorCode the errorCode value to set + * @return the ProviderError object itself. + */ + public ProviderError withErrorCode(Integer errorCode) { + this.errorCode = errorCode; + return this; + } + + /** + * Get the Error message. + * + * @return the errorMessage value + */ + public String errorMessage() { + return this.errorMessage; + } + + /** + * Set the Error message. + * + * @param errorMessage the errorMessage value to set + * @return the ProviderError object itself. + */ + public ProviderError withErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + return this; + } + + /** + * Get the Provider error Id. + * + * @return the errorId value + */ + public String errorId() { + return this.errorId; + } + + /** + * Set the Provider error Id. + * + * @param errorId the errorId value to set + * @return the ProviderError object itself. + */ + public ProviderError withErrorId(String errorId) { + this.errorId = errorId; + return this; + } + + /** + * Get the possible causes for the error. + * + * @return the possibleCauses value + */ + public String possibleCauses() { + return this.possibleCauses; + } + + /** + * Set the possible causes for the error. + * + * @param possibleCauses the possibleCauses value to set + * @return the ProviderError object itself. + */ + public ProviderError withPossibleCauses(String possibleCauses) { + this.possibleCauses = possibleCauses; + return this; + } + + /** + * Get the recommended action to resolve the error. + * + * @return the recommendedAction value + */ + public String recommendedAction() { + return this.recommendedAction; + } + + /** + * Set the recommended action to resolve the error. + * + * @param recommendedAction the recommendedAction value to set + * @return the ProviderError object itself. + */ + public ProviderError withRecommendedAction(String recommendedAction) { + this.recommendedAction = recommendedAction; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificFailoverInput.java new file mode 100644 index 0000000000000..1bab9c6da96e1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificFailoverInput.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific failover input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ProviderSpecificFailoverInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AFailoverProviderInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzureFailback", value = HyperVReplicaAzureFailbackProviderInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureFailoverProviderInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2FailoverProviderInput.class), + @JsonSubTypes.Type(name = "InMage", value = InMageFailoverProviderInput.class) +}) +public class ProviderSpecificFailoverInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificRecoveryPointDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificRecoveryPointDetails.java new file mode 100644 index 0000000000000..b6c68586010ee --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ProviderSpecificRecoveryPointDetails.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Replication provider specific recovery point details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ProviderSpecificRecoveryPointDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2ARecoveryPointDetails.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2RecoveryPointDetails.class) +}) +public class ProviderSpecificRecoveryPointDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RcmAzureMigrationPolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RcmAzureMigrationPolicyDetails.java new file mode 100644 index 0000000000000..7b3679329c5ff --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RcmAzureMigrationPolicyDetails.java @@ -0,0 +1,153 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * RCM based Azure migration specific policy details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("RcmAzureMigration") +public class RcmAzureMigrationPolicyDetails extends PolicyProviderSpecificDetails { + /** + * The recovery point threshold in minutes. + */ + @JsonProperty(value = "recoveryPointThresholdInMinutes") + private Integer recoveryPointThresholdInMinutes; + + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistory") + private Integer recoveryPointHistory; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * A value indicating whether multi-VM sync has to be enabled. Possible + * values include: 'Enabled', 'Disabled'. + */ + @JsonProperty(value = "multiVmSyncStatus") + private MultiVmSyncStatus multiVmSyncStatus; + + /** + * The crash consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * Get the recovery point threshold in minutes. + * + * @return the recoveryPointThresholdInMinutes value + */ + public Integer recoveryPointThresholdInMinutes() { + return this.recoveryPointThresholdInMinutes; + } + + /** + * Set the recovery point threshold in minutes. + * + * @param recoveryPointThresholdInMinutes the recoveryPointThresholdInMinutes value to set + * @return the RcmAzureMigrationPolicyDetails object itself. + */ + public RcmAzureMigrationPolicyDetails withRecoveryPointThresholdInMinutes(Integer recoveryPointThresholdInMinutes) { + this.recoveryPointThresholdInMinutes = recoveryPointThresholdInMinutes; + return this; + } + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistory value + */ + public Integer recoveryPointHistory() { + return this.recoveryPointHistory; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistory the recoveryPointHistory value to set + * @return the RcmAzureMigrationPolicyDetails object itself. + */ + public RcmAzureMigrationPolicyDetails withRecoveryPointHistory(Integer recoveryPointHistory) { + this.recoveryPointHistory = recoveryPointHistory; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the RcmAzureMigrationPolicyDetails object itself. + */ + public RcmAzureMigrationPolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get a value indicating whether multi-VM sync has to be enabled. Possible values include: 'Enabled', 'Disabled'. + * + * @return the multiVmSyncStatus value + */ + public MultiVmSyncStatus multiVmSyncStatus() { + return this.multiVmSyncStatus; + } + + /** + * Set a value indicating whether multi-VM sync has to be enabled. Possible values include: 'Enabled', 'Disabled'. + * + * @param multiVmSyncStatus the multiVmSyncStatus value to set + * @return the RcmAzureMigrationPolicyDetails object itself. + */ + public RcmAzureMigrationPolicyDetails withMultiVmSyncStatus(MultiVmSyncStatus multiVmSyncStatus) { + this.multiVmSyncStatus = multiVmSyncStatus; + return this; + } + + /** + * Get the crash consistent snapshot frequency in minutes. + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency in minutes. + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the RcmAzureMigrationPolicyDetails object itself. + */ + public RcmAzureMigrationPolicyDetails withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlan.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlan.java new file mode 100644 index 0000000000000..a8beee0353b78 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlan.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryPlanInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; +import java.util.List; + +/** + * Type representing RecoveryPlan. + */ +public interface RecoveryPlan extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + RecoveryPlanProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the RecoveryPlan definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithVault, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of RecoveryPlan definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a RecoveryPlan definition. + */ + interface Blank extends WithVault { + } + + /** + * The stage of the recoveryplan definition allowing to specify Vault. + */ + interface WithVault { + /** + * Specifies . + * @return the next definition stage + */ + WithProperties withExistingVault(); + } + + /** + * The stage of the recoveryplan definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Recovery plan creation properties + * @return the next definition stage + */ + WithCreate withProperties(CreateRecoveryPlanInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a RecoveryPlan update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of RecoveryPlan update stages. + */ + interface UpdateStages { + /** + * The stage of the recoveryplan update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Recovery plan update properties + * @return the next update stage + */ + Update withProperties(UpdateRecoveryPlanInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanA2AFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanA2AFailoverInput.java new file mode 100644 index 0000000000000..9d5d2fbca2c1b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanA2AFailoverInput.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan A2A failover input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("A2A") +public class RecoveryPlanA2AFailoverInput extends RecoveryPlanProviderSpecificFailoverInput { + /** + * The recovery point type. Possible values include: 'Latest', + * 'LatestApplicationConsistent', 'LatestCrashConsistent', + * 'LatestProcessed'. + */ + @JsonProperty(value = "recoveryPointType", required = true) + private A2ARpRecoveryPointType recoveryPointType; + + /** + * A value indicating whether to use recovery cloud service for TFO or not. + */ + @JsonProperty(value = "cloudServiceCreationOption") + private String cloudServiceCreationOption; + + /** + * A value indicating whether multi VM sync enabled VMs should use multi VM + * sync points for failover. Possible values include: + * 'UseMultiVmSyncRecoveryPoint', 'UsePerVmRecoveryPoint'. + */ + @JsonProperty(value = "multiVmSyncPointOption") + private MultiVmSyncPointOption multiVmSyncPointOption; + + /** + * Get the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestCrashConsistent', 'LatestProcessed'. + * + * @return the recoveryPointType value + */ + public A2ARpRecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestCrashConsistent', 'LatestProcessed'. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the RecoveryPlanA2AFailoverInput object itself. + */ + public RecoveryPlanA2AFailoverInput withRecoveryPointType(A2ARpRecoveryPointType recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + + /** + * Get a value indicating whether to use recovery cloud service for TFO or not. + * + * @return the cloudServiceCreationOption value + */ + public String cloudServiceCreationOption() { + return this.cloudServiceCreationOption; + } + + /** + * Set a value indicating whether to use recovery cloud service for TFO or not. + * + * @param cloudServiceCreationOption the cloudServiceCreationOption value to set + * @return the RecoveryPlanA2AFailoverInput object itself. + */ + public RecoveryPlanA2AFailoverInput withCloudServiceCreationOption(String cloudServiceCreationOption) { + this.cloudServiceCreationOption = cloudServiceCreationOption; + return this; + } + + /** + * Get a value indicating whether multi VM sync enabled VMs should use multi VM sync points for failover. Possible values include: 'UseMultiVmSyncRecoveryPoint', 'UsePerVmRecoveryPoint'. + * + * @return the multiVmSyncPointOption value + */ + public MultiVmSyncPointOption multiVmSyncPointOption() { + return this.multiVmSyncPointOption; + } + + /** + * Set a value indicating whether multi VM sync enabled VMs should use multi VM sync points for failover. Possible values include: 'UseMultiVmSyncRecoveryPoint', 'UsePerVmRecoveryPoint'. + * + * @param multiVmSyncPointOption the multiVmSyncPointOption value to set + * @return the RecoveryPlanA2AFailoverInput object itself. + */ + public RecoveryPlanA2AFailoverInput withMultiVmSyncPointOption(MultiVmSyncPointOption multiVmSyncPointOption) { + this.multiVmSyncPointOption = multiVmSyncPointOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAction.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAction.java new file mode 100644 index 0000000000000..ccf663c3bd6fc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAction.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan action details. + */ +public class RecoveryPlanAction { + /** + * The action name. + */ + @JsonProperty(value = "actionName", required = true) + private String actionName; + + /** + * The list of failover types. + */ + @JsonProperty(value = "failoverTypes", required = true) + private List failoverTypes; + + /** + * The list of failover directions. + */ + @JsonProperty(value = "failoverDirections", required = true) + private List failoverDirections; + + /** + * The custom details. + */ + @JsonProperty(value = "customDetails", required = true) + private RecoveryPlanActionDetails customDetails; + + /** + * Get the action name. + * + * @return the actionName value + */ + public String actionName() { + return this.actionName; + } + + /** + * Set the action name. + * + * @param actionName the actionName value to set + * @return the RecoveryPlanAction object itself. + */ + public RecoveryPlanAction withActionName(String actionName) { + this.actionName = actionName; + return this; + } + + /** + * Get the list of failover types. + * + * @return the failoverTypes value + */ + public List failoverTypes() { + return this.failoverTypes; + } + + /** + * Set the list of failover types. + * + * @param failoverTypes the failoverTypes value to set + * @return the RecoveryPlanAction object itself. + */ + public RecoveryPlanAction withFailoverTypes(List failoverTypes) { + this.failoverTypes = failoverTypes; + return this; + } + + /** + * Get the list of failover directions. + * + * @return the failoverDirections value + */ + public List failoverDirections() { + return this.failoverDirections; + } + + /** + * Set the list of failover directions. + * + * @param failoverDirections the failoverDirections value to set + * @return the RecoveryPlanAction object itself. + */ + public RecoveryPlanAction withFailoverDirections(List failoverDirections) { + this.failoverDirections = failoverDirections; + return this; + } + + /** + * Get the custom details. + * + * @return the customDetails value + */ + public RecoveryPlanActionDetails customDetails() { + return this.customDetails; + } + + /** + * Set the custom details. + * + * @param customDetails the customDetails value to set + * @return the RecoveryPlanAction object itself. + */ + public RecoveryPlanAction withCustomDetails(RecoveryPlanActionDetails customDetails) { + this.customDetails = customDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionDetails.java new file mode 100644 index 0000000000000..8aeb31b47f924 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionDetails.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Recovery plan action custom details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("RecoveryPlanActionDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AutomationRunbookActionDetails", value = RecoveryPlanAutomationRunbookActionDetails.class), + @JsonSubTypes.Type(name = "ManualActionDetails", value = RecoveryPlanManualActionDetails.class), + @JsonSubTypes.Type(name = "ScriptActionDetails", value = RecoveryPlanScriptActionDetails.class) +}) +public class RecoveryPlanActionDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionLocation.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionLocation.java new file mode 100644 index 0000000000000..a330d7b4461d2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanActionLocation.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for RecoveryPlanActionLocation. + */ +public final class RecoveryPlanActionLocation extends ExpandableStringEnum { + /** Static value Primary for RecoveryPlanActionLocation. */ + public static final RecoveryPlanActionLocation PRIMARY = fromString("Primary"); + + /** Static value Recovery for RecoveryPlanActionLocation. */ + public static final RecoveryPlanActionLocation RECOVERY = fromString("Recovery"); + + /** + * Creates or finds a RecoveryPlanActionLocation from its string representation. + * @param name a name to look for + * @return the corresponding RecoveryPlanActionLocation + */ + @JsonCreator + public static RecoveryPlanActionLocation fromString(String name) { + return fromString(name, RecoveryPlanActionLocation.class); + } + + /** + * @return known RecoveryPlanActionLocation values + */ + public static Collection values() { + return values(RecoveryPlanActionLocation.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAutomationRunbookActionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAutomationRunbookActionDetails.java new file mode 100644 index 0000000000000..710b75daaf55f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanAutomationRunbookActionDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan Automation runbook action details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("AutomationRunbookActionDetails") +public class RecoveryPlanAutomationRunbookActionDetails extends RecoveryPlanActionDetails { + /** + * The runbook ARM Id. + */ + @JsonProperty(value = "runbookId") + private String runbookId; + + /** + * The runbook timeout. + */ + @JsonProperty(value = "timeout") + private String timeout; + + /** + * The fabric location. Possible values include: 'Primary', 'Recovery'. + */ + @JsonProperty(value = "fabricLocation", required = true) + private RecoveryPlanActionLocation fabricLocation; + + /** + * Get the runbook ARM Id. + * + * @return the runbookId value + */ + public String runbookId() { + return this.runbookId; + } + + /** + * Set the runbook ARM Id. + * + * @param runbookId the runbookId value to set + * @return the RecoveryPlanAutomationRunbookActionDetails object itself. + */ + public RecoveryPlanAutomationRunbookActionDetails withRunbookId(String runbookId) { + this.runbookId = runbookId; + return this; + } + + /** + * Get the runbook timeout. + * + * @return the timeout value + */ + public String timeout() { + return this.timeout; + } + + /** + * Set the runbook timeout. + * + * @param timeout the timeout value to set + * @return the RecoveryPlanAutomationRunbookActionDetails object itself. + */ + public RecoveryPlanAutomationRunbookActionDetails withTimeout(String timeout) { + this.timeout = timeout; + return this; + } + + /** + * Get the fabric location. Possible values include: 'Primary', 'Recovery'. + * + * @return the fabricLocation value + */ + public RecoveryPlanActionLocation fabricLocation() { + return this.fabricLocation; + } + + /** + * Set the fabric location. Possible values include: 'Primary', 'Recovery'. + * + * @param fabricLocation the fabricLocation value to set + * @return the RecoveryPlanAutomationRunbookActionDetails object itself. + */ + public RecoveryPlanAutomationRunbookActionDetails withFabricLocation(RecoveryPlanActionLocation fabricLocation) { + this.fabricLocation = fabricLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroup.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroup.java new file mode 100644 index 0000000000000..a43b3384e13cf --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroup.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan group details. + */ +public class RecoveryPlanGroup { + /** + * The group type. Possible values include: 'Shutdown', 'Boot', 'Failover'. + */ + @JsonProperty(value = "groupType", required = true) + private RecoveryPlanGroupType groupType; + + /** + * The list of protected items. + */ + @JsonProperty(value = "replicationProtectedItems") + private List replicationProtectedItems; + + /** + * The start group actions. + */ + @JsonProperty(value = "startGroupActions") + private List startGroupActions; + + /** + * The end group actions. + */ + @JsonProperty(value = "endGroupActions") + private List endGroupActions; + + /** + * Get the group type. Possible values include: 'Shutdown', 'Boot', 'Failover'. + * + * @return the groupType value + */ + public RecoveryPlanGroupType groupType() { + return this.groupType; + } + + /** + * Set the group type. Possible values include: 'Shutdown', 'Boot', 'Failover'. + * + * @param groupType the groupType value to set + * @return the RecoveryPlanGroup object itself. + */ + public RecoveryPlanGroup withGroupType(RecoveryPlanGroupType groupType) { + this.groupType = groupType; + return this; + } + + /** + * Get the list of protected items. + * + * @return the replicationProtectedItems value + */ + public List replicationProtectedItems() { + return this.replicationProtectedItems; + } + + /** + * Set the list of protected items. + * + * @param replicationProtectedItems the replicationProtectedItems value to set + * @return the RecoveryPlanGroup object itself. + */ + public RecoveryPlanGroup withReplicationProtectedItems(List replicationProtectedItems) { + this.replicationProtectedItems = replicationProtectedItems; + return this; + } + + /** + * Get the start group actions. + * + * @return the startGroupActions value + */ + public List startGroupActions() { + return this.startGroupActions; + } + + /** + * Set the start group actions. + * + * @param startGroupActions the startGroupActions value to set + * @return the RecoveryPlanGroup object itself. + */ + public RecoveryPlanGroup withStartGroupActions(List startGroupActions) { + this.startGroupActions = startGroupActions; + return this; + } + + /** + * Get the end group actions. + * + * @return the endGroupActions value + */ + public List endGroupActions() { + return this.endGroupActions; + } + + /** + * Set the end group actions. + * + * @param endGroupActions the endGroupActions value to set + * @return the RecoveryPlanGroup object itself. + */ + public RecoveryPlanGroup withEndGroupActions(List endGroupActions) { + this.endGroupActions = endGroupActions; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupTaskDetails.java new file mode 100644 index 0000000000000..12a2da1362671 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the recovery plan group task. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("RecoveryPlanGroupTaskDetails") +public class RecoveryPlanGroupTaskDetails extends GroupTaskDetails { + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The group identifier. + */ + @JsonProperty(value = "groupId") + private String groupId; + + /** + * The group type. + */ + @JsonProperty(value = "rpGroupType") + private String rpGroupType; + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the RecoveryPlanGroupTaskDetails object itself. + */ + public RecoveryPlanGroupTaskDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the group identifier. + * + * @return the groupId value + */ + public String groupId() { + return this.groupId; + } + + /** + * Set the group identifier. + * + * @param groupId the groupId value to set + * @return the RecoveryPlanGroupTaskDetails object itself. + */ + public RecoveryPlanGroupTaskDetails withGroupId(String groupId) { + this.groupId = groupId; + return this; + } + + /** + * Get the group type. + * + * @return the rpGroupType value + */ + public String rpGroupType() { + return this.rpGroupType; + } + + /** + * Set the group type. + * + * @param rpGroupType the rpGroupType value to set + * @return the RecoveryPlanGroupTaskDetails object itself. + */ + public RecoveryPlanGroupTaskDetails withRpGroupType(String rpGroupType) { + this.rpGroupType = rpGroupType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupType.java new file mode 100644 index 0000000000000..b60bb398d8bc5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanGroupType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for RecoveryPlanGroupType. + */ +public final class RecoveryPlanGroupType extends ExpandableStringEnum { + /** Static value Shutdown for RecoveryPlanGroupType. */ + public static final RecoveryPlanGroupType SHUTDOWN = fromString("Shutdown"); + + /** Static value Boot for RecoveryPlanGroupType. */ + public static final RecoveryPlanGroupType BOOT = fromString("Boot"); + + /** Static value Failover for RecoveryPlanGroupType. */ + public static final RecoveryPlanGroupType FAILOVER = fromString("Failover"); + + /** + * Creates or finds a RecoveryPlanGroupType from its string representation. + * @param name a name to look for + * @return the corresponding RecoveryPlanGroupType + */ + @JsonCreator + public static RecoveryPlanGroupType fromString(String name) { + return fromString(name, RecoveryPlanGroupType.class); + } + + /** + * @return known RecoveryPlanGroupType values + */ + public static Collection values() { + return values(RecoveryPlanGroupType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailbackInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailbackInput.java new file mode 100644 index 0000000000000..c7785424e1823 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailbackInput.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan HVR Azure failback input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzureFailback") +public class RecoveryPlanHyperVReplicaAzureFailbackInput extends RecoveryPlanProviderSpecificFailoverInput { + /** + * The data sync option. Possible values include: 'ForDownTime', + * 'ForSynchronization'. + */ + @JsonProperty(value = "dataSyncOption", required = true) + private DataSyncStatus dataSyncOption; + + /** + * The ALR option. Possible values include: 'CreateVmIfNotFound', + * 'NoAction'. + */ + @JsonProperty(value = "recoveryVmCreationOption", required = true) + private AlternateLocationRecoveryOption recoveryVmCreationOption; + + /** + * Get the data sync option. Possible values include: 'ForDownTime', 'ForSynchronization'. + * + * @return the dataSyncOption value + */ + public DataSyncStatus dataSyncOption() { + return this.dataSyncOption; + } + + /** + * Set the data sync option. Possible values include: 'ForDownTime', 'ForSynchronization'. + * + * @param dataSyncOption the dataSyncOption value to set + * @return the RecoveryPlanHyperVReplicaAzureFailbackInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailbackInput withDataSyncOption(DataSyncStatus dataSyncOption) { + this.dataSyncOption = dataSyncOption; + return this; + } + + /** + * Get the ALR option. Possible values include: 'CreateVmIfNotFound', 'NoAction'. + * + * @return the recoveryVmCreationOption value + */ + public AlternateLocationRecoveryOption recoveryVmCreationOption() { + return this.recoveryVmCreationOption; + } + + /** + * Set the ALR option. Possible values include: 'CreateVmIfNotFound', 'NoAction'. + * + * @param recoveryVmCreationOption the recoveryVmCreationOption value to set + * @return the RecoveryPlanHyperVReplicaAzureFailbackInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailbackInput withRecoveryVmCreationOption(AlternateLocationRecoveryOption recoveryVmCreationOption) { + this.recoveryVmCreationOption = recoveryVmCreationOption; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailoverInput.java new file mode 100644 index 0000000000000..8b5b393f67598 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanHyperVReplicaAzureFailoverInput.java @@ -0,0 +1,126 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan HVR Azure failover input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("HyperVReplicaAzure") +public class RecoveryPlanHyperVReplicaAzureFailoverInput extends RecoveryPlanProviderSpecificFailoverInput { + /** + * The vault location. + */ + @JsonProperty(value = "vaultLocation", required = true) + private String vaultLocation; + + /** + * The primary KEK certificate PFX. + */ + @JsonProperty(value = "primaryKekCertificatePfx") + private String primaryKekCertificatePfx; + + /** + * The secondary KEK certificate PFX. + */ + @JsonProperty(value = "secondaryKekCertificatePfx") + private String secondaryKekCertificatePfx; + + /** + * The recovery point type. Possible values include: 'Latest', + * 'LatestApplicationConsistent', 'LatestProcessed'. + */ + @JsonProperty(value = "recoveryPointType") + private HyperVReplicaAzureRpRecoveryPointType recoveryPointType; + + /** + * Get the vault location. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set the vault location. + * + * @param vaultLocation the vaultLocation value to set + * @return the RecoveryPlanHyperVReplicaAzureFailoverInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailoverInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + + /** + * Get the primary KEK certificate PFX. + * + * @return the primaryKekCertificatePfx value + */ + public String primaryKekCertificatePfx() { + return this.primaryKekCertificatePfx; + } + + /** + * Set the primary KEK certificate PFX. + * + * @param primaryKekCertificatePfx the primaryKekCertificatePfx value to set + * @return the RecoveryPlanHyperVReplicaAzureFailoverInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailoverInput withPrimaryKekCertificatePfx(String primaryKekCertificatePfx) { + this.primaryKekCertificatePfx = primaryKekCertificatePfx; + return this; + } + + /** + * Get the secondary KEK certificate PFX. + * + * @return the secondaryKekCertificatePfx value + */ + public String secondaryKekCertificatePfx() { + return this.secondaryKekCertificatePfx; + } + + /** + * Set the secondary KEK certificate PFX. + * + * @param secondaryKekCertificatePfx the secondaryKekCertificatePfx value to set + * @return the RecoveryPlanHyperVReplicaAzureFailoverInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailoverInput withSecondaryKekCertificatePfx(String secondaryKekCertificatePfx) { + this.secondaryKekCertificatePfx = secondaryKekCertificatePfx; + return this; + } + + /** + * Get the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestProcessed'. + * + * @return the recoveryPointType value + */ + public HyperVReplicaAzureRpRecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestProcessed'. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the RecoveryPlanHyperVReplicaAzureFailoverInput object itself. + */ + public RecoveryPlanHyperVReplicaAzureFailoverInput withRecoveryPointType(HyperVReplicaAzureRpRecoveryPointType recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageAzureV2FailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageAzureV2FailoverInput.java new file mode 100644 index 0000000000000..43a13065e1a7a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageAzureV2FailoverInput.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan InMageAzureV2 failover input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMageAzureV2") +public class RecoveryPlanInMageAzureV2FailoverInput extends RecoveryPlanProviderSpecificFailoverInput { + /** + * The vault location. + */ + @JsonProperty(value = "vaultLocation", required = true) + private String vaultLocation; + + /** + * The recovery point type. Possible values include: 'Latest', + * 'LatestApplicationConsistent', 'LatestCrashConsistent', + * 'LatestProcessed'. + */ + @JsonProperty(value = "recoveryPointType", required = true) + private InMageV2RpRecoveryPointType recoveryPointType; + + /** + * A value indicating whether multi VM sync enabled VMs should use multi VM + * sync points for failover. + */ + @JsonProperty(value = "useMultiVmSyncPoint") + private String useMultiVmSyncPoint; + + /** + * Get the vault location. + * + * @return the vaultLocation value + */ + public String vaultLocation() { + return this.vaultLocation; + } + + /** + * Set the vault location. + * + * @param vaultLocation the vaultLocation value to set + * @return the RecoveryPlanInMageAzureV2FailoverInput object itself. + */ + public RecoveryPlanInMageAzureV2FailoverInput withVaultLocation(String vaultLocation) { + this.vaultLocation = vaultLocation; + return this; + } + + /** + * Get the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestCrashConsistent', 'LatestProcessed'. + * + * @return the recoveryPointType value + */ + public InMageV2RpRecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type. Possible values include: 'Latest', 'LatestApplicationConsistent', 'LatestCrashConsistent', 'LatestProcessed'. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the RecoveryPlanInMageAzureV2FailoverInput object itself. + */ + public RecoveryPlanInMageAzureV2FailoverInput withRecoveryPointType(InMageV2RpRecoveryPointType recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + + /** + * Get a value indicating whether multi VM sync enabled VMs should use multi VM sync points for failover. + * + * @return the useMultiVmSyncPoint value + */ + public String useMultiVmSyncPoint() { + return this.useMultiVmSyncPoint; + } + + /** + * Set a value indicating whether multi VM sync enabled VMs should use multi VM sync points for failover. + * + * @param useMultiVmSyncPoint the useMultiVmSyncPoint value to set + * @return the RecoveryPlanInMageAzureV2FailoverInput object itself. + */ + public RecoveryPlanInMageAzureV2FailoverInput withUseMultiVmSyncPoint(String useMultiVmSyncPoint) { + this.useMultiVmSyncPoint = useMultiVmSyncPoint; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageFailoverInput.java new file mode 100644 index 0000000000000..84fcd0b7fdb55 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanInMageFailoverInput.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan InMage failover input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("InMage") +public class RecoveryPlanInMageFailoverInput extends RecoveryPlanProviderSpecificFailoverInput { + /** + * The recovery point type. Possible values include: 'LatestTime', + * 'LatestTag', 'Custom'. + */ + @JsonProperty(value = "recoveryPointType", required = true) + private RpInMageRecoveryPointType recoveryPointType; + + /** + * Get the recovery point type. Possible values include: 'LatestTime', 'LatestTag', 'Custom'. + * + * @return the recoveryPointType value + */ + public RpInMageRecoveryPointType recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type. Possible values include: 'LatestTime', 'LatestTag', 'Custom'. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the RecoveryPlanInMageFailoverInput object itself. + */ + public RecoveryPlanInMageFailoverInput withRecoveryPointType(RpInMageRecoveryPointType recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanManualActionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanManualActionDetails.java new file mode 100644 index 0000000000000..37dffa760e2ad --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanManualActionDetails.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan manual action details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ManualActionDetails") +public class RecoveryPlanManualActionDetails extends RecoveryPlanActionDetails { + /** + * The manual action description. + */ + @JsonProperty(value = "description") + private String description; + + /** + * Get the manual action description. + * + * @return the description value + */ + public String description() { + return this.description; + } + + /** + * Set the manual action description. + * + * @param description the description value to set + * @return the RecoveryPlanManualActionDetails object itself. + */ + public RecoveryPlanManualActionDetails withDescription(String description) { + this.description = description; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInput.java new file mode 100644 index 0000000000000..5ce4a0368eaa2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan planned failover input. + */ +public class RecoveryPlanPlannedFailoverInput { + /** + * The recovery plan planned failover input properties. + */ + @JsonProperty(value = "properties", required = true) + private RecoveryPlanPlannedFailoverInputProperties properties; + + /** + * Get the recovery plan planned failover input properties. + * + * @return the properties value + */ + public RecoveryPlanPlannedFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set the recovery plan planned failover input properties. + * + * @param properties the properties value to set + * @return the RecoveryPlanPlannedFailoverInput object itself. + */ + public RecoveryPlanPlannedFailoverInput withProperties(RecoveryPlanPlannedFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInputProperties.java new file mode 100644 index 0000000000000..d972d84f159ef --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanPlannedFailoverInputProperties.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan planned failover input properties. + */ +public class RecoveryPlanPlannedFailoverInputProperties { + /** + * The failover direction. Possible values include: 'PrimaryToRecovery', + * 'RecoveryToPrimary'. + */ + @JsonProperty(value = "failoverDirection", required = true) + private PossibleOperationsDirections failoverDirection; + + /** + * The provider specific properties. + */ + @JsonProperty(value = "providerSpecificDetails") + private List providerSpecificDetails; + + /** + * Get the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @return the failoverDirection value + */ + public PossibleOperationsDirections failoverDirection() { + return this.failoverDirection; + } + + /** + * Set the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @param failoverDirection the failoverDirection value to set + * @return the RecoveryPlanPlannedFailoverInputProperties object itself. + */ + public RecoveryPlanPlannedFailoverInputProperties withFailoverDirection(PossibleOperationsDirections failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get the provider specific properties. + * + * @return the providerSpecificDetails value + */ + public List providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific properties. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the RecoveryPlanPlannedFailoverInputProperties object itself. + */ + public RecoveryPlanPlannedFailoverInputProperties withProviderSpecificDetails(List providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProperties.java new file mode 100644 index 0000000000000..632ebefad5ef1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProperties.java @@ -0,0 +1,409 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan custom details. + */ +public class RecoveryPlanProperties { + /** + * The friendly name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The primary fabric Id. + */ + @JsonProperty(value = "primaryFabricId") + private String primaryFabricId; + + /** + * The primary fabric friendly name. + */ + @JsonProperty(value = "primaryFabricFriendlyName") + private String primaryFabricFriendlyName; + + /** + * The recovery fabric Id. + */ + @JsonProperty(value = "recoveryFabricId") + private String recoveryFabricId; + + /** + * The recovery fabric friendly name. + */ + @JsonProperty(value = "recoveryFabricFriendlyName") + private String recoveryFabricFriendlyName; + + /** + * The failover deployment model. + */ + @JsonProperty(value = "failoverDeploymentModel") + private String failoverDeploymentModel; + + /** + * The list of replication providers. + */ + @JsonProperty(value = "replicationProviders") + private List replicationProviders; + + /** + * The list of allowed operations. + */ + @JsonProperty(value = "allowedOperations") + private List allowedOperations; + + /** + * The start time of the last planned failover. + */ + @JsonProperty(value = "lastPlannedFailoverTime") + private DateTime lastPlannedFailoverTime; + + /** + * The start time of the last unplanned failover. + */ + @JsonProperty(value = "lastUnplannedFailoverTime") + private DateTime lastUnplannedFailoverTime; + + /** + * The start time of the last test failover. + */ + @JsonProperty(value = "lastTestFailoverTime") + private DateTime lastTestFailoverTime; + + /** + * The current scenario details. + */ + @JsonProperty(value = "currentScenario") + private CurrentScenarioDetails currentScenario; + + /** + * The recovery plan status. + */ + @JsonProperty(value = "currentScenarioStatus") + private String currentScenarioStatus; + + /** + * The recovery plan status description. + */ + @JsonProperty(value = "currentScenarioStatusDescription") + private String currentScenarioStatusDescription; + + /** + * The recovery plan groups. + */ + @JsonProperty(value = "groups") + private List groups; + + /** + * Get the friendly name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the friendly name. + * + * @param friendlyName the friendlyName value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the primary fabric Id. + * + * @return the primaryFabricId value + */ + public String primaryFabricId() { + return this.primaryFabricId; + } + + /** + * Set the primary fabric Id. + * + * @param primaryFabricId the primaryFabricId value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withPrimaryFabricId(String primaryFabricId) { + this.primaryFabricId = primaryFabricId; + return this; + } + + /** + * Get the primary fabric friendly name. + * + * @return the primaryFabricFriendlyName value + */ + public String primaryFabricFriendlyName() { + return this.primaryFabricFriendlyName; + } + + /** + * Set the primary fabric friendly name. + * + * @param primaryFabricFriendlyName the primaryFabricFriendlyName value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withPrimaryFabricFriendlyName(String primaryFabricFriendlyName) { + this.primaryFabricFriendlyName = primaryFabricFriendlyName; + return this; + } + + /** + * Get the recovery fabric Id. + * + * @return the recoveryFabricId value + */ + public String recoveryFabricId() { + return this.recoveryFabricId; + } + + /** + * Set the recovery fabric Id. + * + * @param recoveryFabricId the recoveryFabricId value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withRecoveryFabricId(String recoveryFabricId) { + this.recoveryFabricId = recoveryFabricId; + return this; + } + + /** + * Get the recovery fabric friendly name. + * + * @return the recoveryFabricFriendlyName value + */ + public String recoveryFabricFriendlyName() { + return this.recoveryFabricFriendlyName; + } + + /** + * Set the recovery fabric friendly name. + * + * @param recoveryFabricFriendlyName the recoveryFabricFriendlyName value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withRecoveryFabricFriendlyName(String recoveryFabricFriendlyName) { + this.recoveryFabricFriendlyName = recoveryFabricFriendlyName; + return this; + } + + /** + * Get the failover deployment model. + * + * @return the failoverDeploymentModel value + */ + public String failoverDeploymentModel() { + return this.failoverDeploymentModel; + } + + /** + * Set the failover deployment model. + * + * @param failoverDeploymentModel the failoverDeploymentModel value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withFailoverDeploymentModel(String failoverDeploymentModel) { + this.failoverDeploymentModel = failoverDeploymentModel; + return this; + } + + /** + * Get the list of replication providers. + * + * @return the replicationProviders value + */ + public List replicationProviders() { + return this.replicationProviders; + } + + /** + * Set the list of replication providers. + * + * @param replicationProviders the replicationProviders value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withReplicationProviders(List replicationProviders) { + this.replicationProviders = replicationProviders; + return this; + } + + /** + * Get the list of allowed operations. + * + * @return the allowedOperations value + */ + public List allowedOperations() { + return this.allowedOperations; + } + + /** + * Set the list of allowed operations. + * + * @param allowedOperations the allowedOperations value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withAllowedOperations(List allowedOperations) { + this.allowedOperations = allowedOperations; + return this; + } + + /** + * Get the start time of the last planned failover. + * + * @return the lastPlannedFailoverTime value + */ + public DateTime lastPlannedFailoverTime() { + return this.lastPlannedFailoverTime; + } + + /** + * Set the start time of the last planned failover. + * + * @param lastPlannedFailoverTime the lastPlannedFailoverTime value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withLastPlannedFailoverTime(DateTime lastPlannedFailoverTime) { + this.lastPlannedFailoverTime = lastPlannedFailoverTime; + return this; + } + + /** + * Get the start time of the last unplanned failover. + * + * @return the lastUnplannedFailoverTime value + */ + public DateTime lastUnplannedFailoverTime() { + return this.lastUnplannedFailoverTime; + } + + /** + * Set the start time of the last unplanned failover. + * + * @param lastUnplannedFailoverTime the lastUnplannedFailoverTime value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withLastUnplannedFailoverTime(DateTime lastUnplannedFailoverTime) { + this.lastUnplannedFailoverTime = lastUnplannedFailoverTime; + return this; + } + + /** + * Get the start time of the last test failover. + * + * @return the lastTestFailoverTime value + */ + public DateTime lastTestFailoverTime() { + return this.lastTestFailoverTime; + } + + /** + * Set the start time of the last test failover. + * + * @param lastTestFailoverTime the lastTestFailoverTime value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withLastTestFailoverTime(DateTime lastTestFailoverTime) { + this.lastTestFailoverTime = lastTestFailoverTime; + return this; + } + + /** + * Get the current scenario details. + * + * @return the currentScenario value + */ + public CurrentScenarioDetails currentScenario() { + return this.currentScenario; + } + + /** + * Set the current scenario details. + * + * @param currentScenario the currentScenario value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withCurrentScenario(CurrentScenarioDetails currentScenario) { + this.currentScenario = currentScenario; + return this; + } + + /** + * Get the recovery plan status. + * + * @return the currentScenarioStatus value + */ + public String currentScenarioStatus() { + return this.currentScenarioStatus; + } + + /** + * Set the recovery plan status. + * + * @param currentScenarioStatus the currentScenarioStatus value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withCurrentScenarioStatus(String currentScenarioStatus) { + this.currentScenarioStatus = currentScenarioStatus; + return this; + } + + /** + * Get the recovery plan status description. + * + * @return the currentScenarioStatusDescription value + */ + public String currentScenarioStatusDescription() { + return this.currentScenarioStatusDescription; + } + + /** + * Set the recovery plan status description. + * + * @param currentScenarioStatusDescription the currentScenarioStatusDescription value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withCurrentScenarioStatusDescription(String currentScenarioStatusDescription) { + this.currentScenarioStatusDescription = currentScenarioStatusDescription; + return this; + } + + /** + * Get the recovery plan groups. + * + * @return the groups value + */ + public List groups() { + return this.groups; + } + + /** + * Set the recovery plan groups. + * + * @param groups the groups value to set + * @return the RecoveryPlanProperties object itself. + */ + public RecoveryPlanProperties withGroups(List groups) { + this.groups = groups; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProtectedItem.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProtectedItem.java new file mode 100644 index 0000000000000..d06ebd618285d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProtectedItem.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan protected item. + */ +public class RecoveryPlanProtectedItem { + /** + * The ARM Id of the recovery plan protected item. + */ + @JsonProperty(value = "id") + private String id; + + /** + * The virtual machine Id. + */ + @JsonProperty(value = "virtualMachineId") + private String virtualMachineId; + + /** + * Get the ARM Id of the recovery plan protected item. + * + * @return the id value + */ + public String id() { + return this.id; + } + + /** + * Set the ARM Id of the recovery plan protected item. + * + * @param id the id value to set + * @return the RecoveryPlanProtectedItem object itself. + */ + public RecoveryPlanProtectedItem withId(String id) { + this.id = id; + return this; + } + + /** + * Get the virtual machine Id. + * + * @return the virtualMachineId value + */ + public String virtualMachineId() { + return this.virtualMachineId; + } + + /** + * Set the virtual machine Id. + * + * @param virtualMachineId the virtualMachineId value to set + * @return the RecoveryPlanProtectedItem object itself. + */ + public RecoveryPlanProtectedItem withVirtualMachineId(String virtualMachineId) { + this.virtualMachineId = virtualMachineId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProviderSpecificFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProviderSpecificFailoverInput.java new file mode 100644 index 0000000000000..2749bc35641a3 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanProviderSpecificFailoverInput.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Recovery plan provider specific failover input base class. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("RecoveryPlanProviderSpecificFailoverInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = RecoveryPlanA2AFailoverInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzureFailback", value = RecoveryPlanHyperVReplicaAzureFailbackInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = RecoveryPlanHyperVReplicaAzureFailoverInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = RecoveryPlanInMageAzureV2FailoverInput.class), + @JsonSubTypes.Type(name = "InMage", value = RecoveryPlanInMageFailoverInput.class) +}) +public class RecoveryPlanProviderSpecificFailoverInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanScriptActionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanScriptActionDetails.java new file mode 100644 index 0000000000000..1411b9bf43544 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanScriptActionDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Recovery plan script action details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ScriptActionDetails") +public class RecoveryPlanScriptActionDetails extends RecoveryPlanActionDetails { + /** + * The script path. + */ + @JsonProperty(value = "path", required = true) + private String path; + + /** + * The script timeout. + */ + @JsonProperty(value = "timeout") + private String timeout; + + /** + * The fabric location. Possible values include: 'Primary', 'Recovery'. + */ + @JsonProperty(value = "fabricLocation", required = true) + private RecoveryPlanActionLocation fabricLocation; + + /** + * Get the script path. + * + * @return the path value + */ + public String path() { + return this.path; + } + + /** + * Set the script path. + * + * @param path the path value to set + * @return the RecoveryPlanScriptActionDetails object itself. + */ + public RecoveryPlanScriptActionDetails withPath(String path) { + this.path = path; + return this; + } + + /** + * Get the script timeout. + * + * @return the timeout value + */ + public String timeout() { + return this.timeout; + } + + /** + * Set the script timeout. + * + * @param timeout the timeout value to set + * @return the RecoveryPlanScriptActionDetails object itself. + */ + public RecoveryPlanScriptActionDetails withTimeout(String timeout) { + this.timeout = timeout; + return this; + } + + /** + * Get the fabric location. Possible values include: 'Primary', 'Recovery'. + * + * @return the fabricLocation value + */ + public RecoveryPlanActionLocation fabricLocation() { + return this.fabricLocation; + } + + /** + * Set the fabric location. Possible values include: 'Primary', 'Recovery'. + * + * @param fabricLocation the fabricLocation value to set + * @return the RecoveryPlanScriptActionDetails object itself. + */ + public RecoveryPlanScriptActionDetails withFabricLocation(RecoveryPlanActionLocation fabricLocation) { + this.fabricLocation = fabricLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanShutdownGroupTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanShutdownGroupTaskDetails.java new file mode 100644 index 0000000000000..f228ef0310240 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanShutdownGroupTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the recovery plan shutdown group task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("RecoveryPlanShutdownGroupTaskDetails") +public class RecoveryPlanShutdownGroupTaskDetails extends GroupTaskDetails { + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The group identifier. + */ + @JsonProperty(value = "groupId") + private String groupId; + + /** + * The group type. + */ + @JsonProperty(value = "rpGroupType") + private String rpGroupType; + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the RecoveryPlanShutdownGroupTaskDetails object itself. + */ + public RecoveryPlanShutdownGroupTaskDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the group identifier. + * + * @return the groupId value + */ + public String groupId() { + return this.groupId; + } + + /** + * Set the group identifier. + * + * @param groupId the groupId value to set + * @return the RecoveryPlanShutdownGroupTaskDetails object itself. + */ + public RecoveryPlanShutdownGroupTaskDetails withGroupId(String groupId) { + this.groupId = groupId; + return this; + } + + /** + * Get the group type. + * + * @return the rpGroupType value + */ + public String rpGroupType() { + return this.rpGroupType; + } + + /** + * Set the group type. + * + * @param rpGroupType the rpGroupType value to set + * @return the RecoveryPlanShutdownGroupTaskDetails object itself. + */ + public RecoveryPlanShutdownGroupTaskDetails withRpGroupType(String rpGroupType) { + this.rpGroupType = rpGroupType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInput.java new file mode 100644 index 0000000000000..0ab742f56aa16 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan test failover cleanup input. + */ +public class RecoveryPlanTestFailoverCleanupInput { + /** + * The recovery plan test failover cleanup input properties. + */ + @JsonProperty(value = "properties", required = true) + private RecoveryPlanTestFailoverCleanupInputProperties properties; + + /** + * Get the recovery plan test failover cleanup input properties. + * + * @return the properties value + */ + public RecoveryPlanTestFailoverCleanupInputProperties properties() { + return this.properties; + } + + /** + * Set the recovery plan test failover cleanup input properties. + * + * @param properties the properties value to set + * @return the RecoveryPlanTestFailoverCleanupInput object itself. + */ + public RecoveryPlanTestFailoverCleanupInput withProperties(RecoveryPlanTestFailoverCleanupInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInputProperties.java new file mode 100644 index 0000000000000..52232dd0f3e7d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverCleanupInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan test failover cleanup input properties. + */ +public class RecoveryPlanTestFailoverCleanupInputProperties { + /** + * The test failover cleanup comments. + */ + @JsonProperty(value = "comments") + private String comments; + + /** + * Get the test failover cleanup comments. + * + * @return the comments value + */ + public String comments() { + return this.comments; + } + + /** + * Set the test failover cleanup comments. + * + * @param comments the comments value to set + * @return the RecoveryPlanTestFailoverCleanupInputProperties object itself. + */ + public RecoveryPlanTestFailoverCleanupInputProperties withComments(String comments) { + this.comments = comments; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInput.java new file mode 100644 index 0000000000000..806c6d1147b20 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan test failover input. + */ +public class RecoveryPlanTestFailoverInput { + /** + * The recovery plan test failover input properties. + */ + @JsonProperty(value = "properties", required = true) + private RecoveryPlanTestFailoverInputProperties properties; + + /** + * Get the recovery plan test failover input properties. + * + * @return the properties value + */ + public RecoveryPlanTestFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set the recovery plan test failover input properties. + * + * @param properties the properties value to set + * @return the RecoveryPlanTestFailoverInput object itself. + */ + public RecoveryPlanTestFailoverInput withProperties(RecoveryPlanTestFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInputProperties.java new file mode 100644 index 0000000000000..bba17f050cb5f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanTestFailoverInputProperties.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan test failover input properties. + */ +public class RecoveryPlanTestFailoverInputProperties { + /** + * The failover direction. Possible values include: 'PrimaryToRecovery', + * 'RecoveryToPrimary'. + */ + @JsonProperty(value = "failoverDirection", required = true) + private PossibleOperationsDirections failoverDirection; + + /** + * The network type to be used for test failover. + */ + @JsonProperty(value = "networkType", required = true) + private String networkType; + + /** + * The Id of the network to be used for test failover. + */ + @JsonProperty(value = "networkId") + private String networkId; + + /** + * A value indicating whether the test failover cleanup is to be skipped. + */ + @JsonProperty(value = "skipTestFailoverCleanup") + private String skipTestFailoverCleanup; + + /** + * The provider specific properties. + */ + @JsonProperty(value = "providerSpecificDetails") + private List providerSpecificDetails; + + /** + * Get the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @return the failoverDirection value + */ + public PossibleOperationsDirections failoverDirection() { + return this.failoverDirection; + } + + /** + * Set the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @param failoverDirection the failoverDirection value to set + * @return the RecoveryPlanTestFailoverInputProperties object itself. + */ + public RecoveryPlanTestFailoverInputProperties withFailoverDirection(PossibleOperationsDirections failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get the network type to be used for test failover. + * + * @return the networkType value + */ + public String networkType() { + return this.networkType; + } + + /** + * Set the network type to be used for test failover. + * + * @param networkType the networkType value to set + * @return the RecoveryPlanTestFailoverInputProperties object itself. + */ + public RecoveryPlanTestFailoverInputProperties withNetworkType(String networkType) { + this.networkType = networkType; + return this; + } + + /** + * Get the Id of the network to be used for test failover. + * + * @return the networkId value + */ + public String networkId() { + return this.networkId; + } + + /** + * Set the Id of the network to be used for test failover. + * + * @param networkId the networkId value to set + * @return the RecoveryPlanTestFailoverInputProperties object itself. + */ + public RecoveryPlanTestFailoverInputProperties withNetworkId(String networkId) { + this.networkId = networkId; + return this; + } + + /** + * Get a value indicating whether the test failover cleanup is to be skipped. + * + * @return the skipTestFailoverCleanup value + */ + public String skipTestFailoverCleanup() { + return this.skipTestFailoverCleanup; + } + + /** + * Set a value indicating whether the test failover cleanup is to be skipped. + * + * @param skipTestFailoverCleanup the skipTestFailoverCleanup value to set + * @return the RecoveryPlanTestFailoverInputProperties object itself. + */ + public RecoveryPlanTestFailoverInputProperties withSkipTestFailoverCleanup(String skipTestFailoverCleanup) { + this.skipTestFailoverCleanup = skipTestFailoverCleanup; + return this; + } + + /** + * Get the provider specific properties. + * + * @return the providerSpecificDetails value + */ + public List providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific properties. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the RecoveryPlanTestFailoverInputProperties object itself. + */ + public RecoveryPlanTestFailoverInputProperties withProviderSpecificDetails(List providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInput.java new file mode 100644 index 0000000000000..945b6b663681a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan unplanned failover input. + */ +public class RecoveryPlanUnplannedFailoverInput { + /** + * The recovery plan unplanned failover input properties. + */ + @JsonProperty(value = "properties", required = true) + private RecoveryPlanUnplannedFailoverInputProperties properties; + + /** + * Get the recovery plan unplanned failover input properties. + * + * @return the properties value + */ + public RecoveryPlanUnplannedFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set the recovery plan unplanned failover input properties. + * + * @param properties the properties value to set + * @return the RecoveryPlanUnplannedFailoverInput object itself. + */ + public RecoveryPlanUnplannedFailoverInput withProperties(RecoveryPlanUnplannedFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInputProperties.java new file mode 100644 index 0000000000000..dd11d8de3cdc5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPlanUnplannedFailoverInputProperties.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan unplanned failover input properties. + */ +public class RecoveryPlanUnplannedFailoverInputProperties { + /** + * The failover direction. Possible values include: 'PrimaryToRecovery', + * 'RecoveryToPrimary'. + */ + @JsonProperty(value = "failoverDirection", required = true) + private PossibleOperationsDirections failoverDirection; + + /** + * A value indicating whether source site operations are required. Possible + * values include: 'Required', 'NotRequired'. + */ + @JsonProperty(value = "sourceSiteOperations", required = true) + private SourceSiteOperations sourceSiteOperations; + + /** + * The provider specific properties. + */ + @JsonProperty(value = "providerSpecificDetails") + private List providerSpecificDetails; + + /** + * Get the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @return the failoverDirection value + */ + public PossibleOperationsDirections failoverDirection() { + return this.failoverDirection; + } + + /** + * Set the failover direction. Possible values include: 'PrimaryToRecovery', 'RecoveryToPrimary'. + * + * @param failoverDirection the failoverDirection value to set + * @return the RecoveryPlanUnplannedFailoverInputProperties object itself. + */ + public RecoveryPlanUnplannedFailoverInputProperties withFailoverDirection(PossibleOperationsDirections failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get a value indicating whether source site operations are required. Possible values include: 'Required', 'NotRequired'. + * + * @return the sourceSiteOperations value + */ + public SourceSiteOperations sourceSiteOperations() { + return this.sourceSiteOperations; + } + + /** + * Set a value indicating whether source site operations are required. Possible values include: 'Required', 'NotRequired'. + * + * @param sourceSiteOperations the sourceSiteOperations value to set + * @return the RecoveryPlanUnplannedFailoverInputProperties object itself. + */ + public RecoveryPlanUnplannedFailoverInputProperties withSourceSiteOperations(SourceSiteOperations sourceSiteOperations) { + this.sourceSiteOperations = sourceSiteOperations; + return this; + } + + /** + * Get the provider specific properties. + * + * @return the providerSpecificDetails value + */ + public List providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific properties. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the RecoveryPlanUnplannedFailoverInputProperties object itself. + */ + public RecoveryPlanUnplannedFailoverInputProperties withProviderSpecificDetails(List providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoint.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoint.java new file mode 100644 index 0000000000000..783c88670f532 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoint.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryPointInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing RecoveryPoint. + */ +public interface RecoveryPoint extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + RecoveryPointProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointProperties.java new file mode 100644 index 0000000000000..11206331e8d17 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointProperties.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery point properties. + */ +public class RecoveryPointProperties { + /** + * The recovery point time. + */ + @JsonProperty(value = "recoveryPointTime") + private DateTime recoveryPointTime; + + /** + * The recovery point type: ApplicationConsistent, CrashConsistent. + */ + @JsonProperty(value = "recoveryPointType") + private String recoveryPointType; + + /** + * The provider specific details for the recovery point. + */ + @JsonProperty(value = "providerSpecificDetails") + private ProviderSpecificRecoveryPointDetails providerSpecificDetails; + + /** + * Get the recovery point time. + * + * @return the recoveryPointTime value + */ + public DateTime recoveryPointTime() { + return this.recoveryPointTime; + } + + /** + * Set the recovery point time. + * + * @param recoveryPointTime the recoveryPointTime value to set + * @return the RecoveryPointProperties object itself. + */ + public RecoveryPointProperties withRecoveryPointTime(DateTime recoveryPointTime) { + this.recoveryPointTime = recoveryPointTime; + return this; + } + + /** + * Get the recovery point type: ApplicationConsistent, CrashConsistent. + * + * @return the recoveryPointType value + */ + public String recoveryPointType() { + return this.recoveryPointType; + } + + /** + * Set the recovery point type: ApplicationConsistent, CrashConsistent. + * + * @param recoveryPointType the recoveryPointType value to set + * @return the RecoveryPointProperties object itself. + */ + public RecoveryPointProperties withRecoveryPointType(String recoveryPointType) { + this.recoveryPointType = recoveryPointType; + return this; + } + + /** + * Get the provider specific details for the recovery point. + * + * @return the providerSpecificDetails value + */ + public ProviderSpecificRecoveryPointDetails providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific details for the recovery point. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the RecoveryPointProperties object itself. + */ + public RecoveryPointProperties withProviderSpecificDetails(ProviderSpecificRecoveryPointDetails providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointSyncType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointSyncType.java new file mode 100644 index 0000000000000..7f9bf26000446 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointSyncType.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for RecoveryPointSyncType. + */ +public final class RecoveryPointSyncType extends ExpandableStringEnum { + /** Static value MultiVmSyncRecoveryPoint for RecoveryPointSyncType. */ + public static final RecoveryPointSyncType MULTI_VM_SYNC_RECOVERY_POINT = fromString("MultiVmSyncRecoveryPoint"); + + /** Static value PerVmRecoveryPoint for RecoveryPointSyncType. */ + public static final RecoveryPointSyncType PER_VM_RECOVERY_POINT = fromString("PerVmRecoveryPoint"); + + /** + * Creates or finds a RecoveryPointSyncType from its string representation. + * @param name a name to look for + * @return the corresponding RecoveryPointSyncType + */ + @JsonCreator + public static RecoveryPointSyncType fromString(String name) { + return fromString(name, RecoveryPointSyncType.class); + } + + /** + * @return known RecoveryPointSyncType values + */ + public static Collection values() { + return values(RecoveryPointSyncType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointType.java new file mode 100644 index 0000000000000..b4cba1c2d0729 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPointType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for RecoveryPointType. + */ +public final class RecoveryPointType extends ExpandableStringEnum { + /** Static value LatestTime for RecoveryPointType. */ + public static final RecoveryPointType LATEST_TIME = fromString("LatestTime"); + + /** Static value LatestTag for RecoveryPointType. */ + public static final RecoveryPointType LATEST_TAG = fromString("LatestTag"); + + /** Static value Custom for RecoveryPointType. */ + public static final RecoveryPointType CUSTOM = fromString("Custom"); + + /** + * Creates or finds a RecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding RecoveryPointType + */ + @JsonCreator + public static RecoveryPointType fromString(String name) { + return fromString(name, RecoveryPointType.class); + } + + /** + * @return known RecoveryPointType values + */ + public static Collection values() { + return values(RecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoints.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoints.java new file mode 100644 index 0000000000000..5481dc2917c9c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryPoints.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryPointsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing RecoveryPoints. + */ +public interface RecoveryPoints extends HasInner { + /** + * Get a recovery point. + * Get the details of specified recovery point. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param recoveryPointName The recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName); + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProvider.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProvider.java new file mode 100644 index 0000000000000..4c9f7e47ecbf7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProvider.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesProviderInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing RecoveryServicesProvider. + */ +public interface RecoveryServicesProvider extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + RecoveryServicesProviderProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the RecoveryServicesProvider definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationFabric, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of RecoveryServicesProvider definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a RecoveryServicesProvider definition. + */ + interface Blank extends WithReplicationFabric { + } + + /** + * The stage of the recoveryservicesprovider definition allowing to specify ReplicationFabric. + */ + interface WithReplicationFabric { + /** + * Specifies fabricName. + * @param fabricName Fabric name + * @return the next definition stage + */ + WithProperties withExistingReplicationFabric(String fabricName); + } + + /** + * The stage of the recoveryservicesprovider definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The properties of an add provider request + * @return the next definition stage + */ + WithCreate withProperties(AddRecoveryServicesProviderInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a RecoveryServicesProvider update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of RecoveryServicesProvider update stages. + */ + interface UpdateStages { + /** + * The stage of the recoveryservicesprovider update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The properties of an add provider request + * @return the next update stage + */ + Update withProperties(AddRecoveryServicesProviderInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProviderProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProviderProperties.java new file mode 100644 index 0000000000000..810a65e5cdca5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RecoveryServicesProviderProperties.java @@ -0,0 +1,435 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery services provider properties. + */ +public class RecoveryServicesProviderProperties { + /** + * Type of the site. + */ + @JsonProperty(value = "fabricType") + private String fabricType; + + /** + * Friendly name of the DRA. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The provider version. + */ + @JsonProperty(value = "providerVersion") + private String providerVersion; + + /** + * The fabric provider. + */ + @JsonProperty(value = "serverVersion") + private String serverVersion; + + /** + * DRA version status. + */ + @JsonProperty(value = "providerVersionState") + private String providerVersionState; + + /** + * Expiry date of the version. + */ + @JsonProperty(value = "providerVersionExpiryDate") + private DateTime providerVersionExpiryDate; + + /** + * The fabric friendly name. + */ + @JsonProperty(value = "fabricFriendlyName") + private String fabricFriendlyName; + + /** + * Time when last heartbeat was sent by the DRA. + */ + @JsonProperty(value = "lastHeartBeat") + private DateTime lastHeartBeat; + + /** + * A value indicating whether DRA is responsive. + */ + @JsonProperty(value = "connectionStatus") + private String connectionStatus; + + /** + * Number of protected VMs currently managed by the DRA. + */ + @JsonProperty(value = "protectedItemCount") + private Integer protectedItemCount; + + /** + * The scenarios allowed on this provider. + */ + @JsonProperty(value = "allowedScenarios") + private List allowedScenarios; + + /** + * The recovery services provider health error details. + */ + @JsonProperty(value = "healthErrorDetails") + private List healthErrorDetails; + + /** + * The DRA Id. + */ + @JsonProperty(value = "draIdentifier") + private String draIdentifier; + + /** + * The authentication identity details. + */ + @JsonProperty(value = "authenticationIdentityDetails") + private IdentityProviderDetails authenticationIdentityDetails; + + /** + * The resource access identity details. + */ + @JsonProperty(value = "resourceAccessIdentityDetails") + private IdentityProviderDetails resourceAccessIdentityDetails; + + /** + * The provider version details. + */ + @JsonProperty(value = "providerVersionDetails") + private VersionDetails providerVersionDetails; + + /** + * Get type of the site. + * + * @return the fabricType value + */ + public String fabricType() { + return this.fabricType; + } + + /** + * Set type of the site. + * + * @param fabricType the fabricType value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withFabricType(String fabricType) { + this.fabricType = fabricType; + return this; + } + + /** + * Get friendly name of the DRA. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set friendly name of the DRA. + * + * @param friendlyName the friendlyName value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the provider version. + * + * @return the providerVersion value + */ + public String providerVersion() { + return this.providerVersion; + } + + /** + * Set the provider version. + * + * @param providerVersion the providerVersion value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withProviderVersion(String providerVersion) { + this.providerVersion = providerVersion; + return this; + } + + /** + * Get the fabric provider. + * + * @return the serverVersion value + */ + public String serverVersion() { + return this.serverVersion; + } + + /** + * Set the fabric provider. + * + * @param serverVersion the serverVersion value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withServerVersion(String serverVersion) { + this.serverVersion = serverVersion; + return this; + } + + /** + * Get dRA version status. + * + * @return the providerVersionState value + */ + public String providerVersionState() { + return this.providerVersionState; + } + + /** + * Set dRA version status. + * + * @param providerVersionState the providerVersionState value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withProviderVersionState(String providerVersionState) { + this.providerVersionState = providerVersionState; + return this; + } + + /** + * Get expiry date of the version. + * + * @return the providerVersionExpiryDate value + */ + public DateTime providerVersionExpiryDate() { + return this.providerVersionExpiryDate; + } + + /** + * Set expiry date of the version. + * + * @param providerVersionExpiryDate the providerVersionExpiryDate value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withProviderVersionExpiryDate(DateTime providerVersionExpiryDate) { + this.providerVersionExpiryDate = providerVersionExpiryDate; + return this; + } + + /** + * Get the fabric friendly name. + * + * @return the fabricFriendlyName value + */ + public String fabricFriendlyName() { + return this.fabricFriendlyName; + } + + /** + * Set the fabric friendly name. + * + * @param fabricFriendlyName the fabricFriendlyName value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withFabricFriendlyName(String fabricFriendlyName) { + this.fabricFriendlyName = fabricFriendlyName; + return this; + } + + /** + * Get time when last heartbeat was sent by the DRA. + * + * @return the lastHeartBeat value + */ + public DateTime lastHeartBeat() { + return this.lastHeartBeat; + } + + /** + * Set time when last heartbeat was sent by the DRA. + * + * @param lastHeartBeat the lastHeartBeat value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withLastHeartBeat(DateTime lastHeartBeat) { + this.lastHeartBeat = lastHeartBeat; + return this; + } + + /** + * Get a value indicating whether DRA is responsive. + * + * @return the connectionStatus value + */ + public String connectionStatus() { + return this.connectionStatus; + } + + /** + * Set a value indicating whether DRA is responsive. + * + * @param connectionStatus the connectionStatus value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withConnectionStatus(String connectionStatus) { + this.connectionStatus = connectionStatus; + return this; + } + + /** + * Get number of protected VMs currently managed by the DRA. + * + * @return the protectedItemCount value + */ + public Integer protectedItemCount() { + return this.protectedItemCount; + } + + /** + * Set number of protected VMs currently managed by the DRA. + * + * @param protectedItemCount the protectedItemCount value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withProtectedItemCount(Integer protectedItemCount) { + this.protectedItemCount = protectedItemCount; + return this; + } + + /** + * Get the scenarios allowed on this provider. + * + * @return the allowedScenarios value + */ + public List allowedScenarios() { + return this.allowedScenarios; + } + + /** + * Set the scenarios allowed on this provider. + * + * @param allowedScenarios the allowedScenarios value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withAllowedScenarios(List allowedScenarios) { + this.allowedScenarios = allowedScenarios; + return this; + } + + /** + * Get the recovery services provider health error details. + * + * @return the healthErrorDetails value + */ + public List healthErrorDetails() { + return this.healthErrorDetails; + } + + /** + * Set the recovery services provider health error details. + * + * @param healthErrorDetails the healthErrorDetails value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withHealthErrorDetails(List healthErrorDetails) { + this.healthErrorDetails = healthErrorDetails; + return this; + } + + /** + * Get the DRA Id. + * + * @return the draIdentifier value + */ + public String draIdentifier() { + return this.draIdentifier; + } + + /** + * Set the DRA Id. + * + * @param draIdentifier the draIdentifier value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withDraIdentifier(String draIdentifier) { + this.draIdentifier = draIdentifier; + return this; + } + + /** + * Get the authentication identity details. + * + * @return the authenticationIdentityDetails value + */ + public IdentityProviderDetails authenticationIdentityDetails() { + return this.authenticationIdentityDetails; + } + + /** + * Set the authentication identity details. + * + * @param authenticationIdentityDetails the authenticationIdentityDetails value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withAuthenticationIdentityDetails(IdentityProviderDetails authenticationIdentityDetails) { + this.authenticationIdentityDetails = authenticationIdentityDetails; + return this; + } + + /** + * Get the resource access identity details. + * + * @return the resourceAccessIdentityDetails value + */ + public IdentityProviderDetails resourceAccessIdentityDetails() { + return this.resourceAccessIdentityDetails; + } + + /** + * Set the resource access identity details. + * + * @param resourceAccessIdentityDetails the resourceAccessIdentityDetails value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withResourceAccessIdentityDetails(IdentityProviderDetails resourceAccessIdentityDetails) { + this.resourceAccessIdentityDetails = resourceAccessIdentityDetails; + return this; + } + + /** + * Get the provider version details. + * + * @return the providerVersionDetails value + */ + public VersionDetails providerVersionDetails() { + return this.providerVersionDetails; + } + + /** + * Set the provider version details. + * + * @param providerVersionDetails the providerVersionDetails value to set + * @return the RecoveryServicesProviderProperties object itself. + */ + public RecoveryServicesProviderProperties withProviderVersionDetails(VersionDetails providerVersionDetails) { + this.providerVersionDetails = providerVersionDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInput.java new file mode 100644 index 0000000000000..0862fb7676754 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Container unpairing input. + */ +public class RemoveProtectionContainerMappingInput { + /** + * Configure protection input properties. + */ + @JsonProperty(value = "properties") + private RemoveProtectionContainerMappingInputProperties properties; + + /** + * Get configure protection input properties. + * + * @return the properties value + */ + public RemoveProtectionContainerMappingInputProperties properties() { + return this.properties; + } + + /** + * Set configure protection input properties. + * + * @param properties the properties value to set + * @return the RemoveProtectionContainerMappingInput object itself. + */ + public RemoveProtectionContainerMappingInput withProperties(RemoveProtectionContainerMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInputProperties.java new file mode 100644 index 0000000000000..879dc8e70c20a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RemoveProtectionContainerMappingInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Unpairing input properties. + */ +public class RemoveProtectionContainerMappingInputProperties { + /** + * Provider specific input for unpairing. + */ + @JsonProperty(value = "providerSpecificInput") + private ReplicationProviderContainerUnmappingInput providerSpecificInput; + + /** + * Get provider specific input for unpairing. + * + * @return the providerSpecificInput value + */ + public ReplicationProviderContainerUnmappingInput providerSpecificInput() { + return this.providerSpecificInput; + } + + /** + * Set provider specific input for unpairing. + * + * @param providerSpecificInput the providerSpecificInput value to set + * @return the RemoveProtectionContainerMappingInputProperties object itself. + */ + public RemoveProtectionContainerMappingInputProperties withProviderSpecificInput(ReplicationProviderContainerUnmappingInput providerSpecificInput) { + this.providerSpecificInput = providerSpecificInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInput.java new file mode 100644 index 0000000000000..b0acae6663ec6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Certificate renewal input. + */ +public class RenewCertificateInput { + /** + * Renew certificate input properties. + */ + @JsonProperty(value = "properties") + private RenewCertificateInputProperties properties; + + /** + * Get renew certificate input properties. + * + * @return the properties value + */ + public RenewCertificateInputProperties properties() { + return this.properties; + } + + /** + * Set renew certificate input properties. + * + * @param properties the properties value to set + * @return the RenewCertificateInput object itself. + */ + public RenewCertificateInput withProperties(RenewCertificateInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInputProperties.java new file mode 100644 index 0000000000000..49d34defce8f2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RenewCertificateInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Renew Certificate input properties. + */ +public class RenewCertificateInputProperties { + /** + * Renew certificate type. + */ + @JsonProperty(value = "renewCertificateType") + private String renewCertificateType; + + /** + * Get renew certificate type. + * + * @return the renewCertificateType value + */ + public String renewCertificateType() { + return this.renewCertificateType; + } + + /** + * Set renew certificate type. + * + * @param renewCertificateType the renewCertificateType value to set + * @return the RenewCertificateInputProperties object itself. + */ + public RenewCertificateInputProperties withRenewCertificateType(String renewCertificateType) { + this.renewCertificateType = renewCertificateType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationAlertSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationAlertSettings.java new file mode 100644 index 0000000000000..dd80eb8cde2c2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationAlertSettings.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationAlertSettingsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationAlertSettings. + */ +public interface ReplicationAlertSettings extends SupportsCreating, HasInner { + /** + * Gets an email notification(alert) configuration. + * Gets the details of the specified email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String alertSettingName); + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationEvents.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationEvents.java new file mode 100644 index 0000000000000..fc4a1bd92be8f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationEvents.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationEventsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationEvents. + */ +public interface ReplicationEvents extends HasInner { + /** + * Get the details of an Azure Site recovery event. + * The operation to get the details of an Azure Site recovery event. + * + * @param eventName The name of the Azure Site Recovery event. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String eventName); + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationFabrics.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationFabrics.java new file mode 100644 index 0000000000000..ebaf6eafdd9d2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationFabrics.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationFabricsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationFabrics. + */ +public interface ReplicationFabrics extends SupportsCreating, HasInner { + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable checkConsistencyAsync(String fabricName); + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable migrateToAadAsync(String fabricName); + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable reassociateGatewayAsync(String fabricName); + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName); + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable renewCertificateAsync(String fabricName); + + /** + * Gets the details of an ASR fabric. + * Gets the details of an Azure Site Recovery fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName); + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable purgeAsync(String fabricName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationGroupDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationGroupDetails.java new file mode 100644 index 0000000000000..11df6a969490f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationGroupDetails.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Replication group details. This will be used in case of San and Wvr. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReplicationGroupDetails") +public class ReplicationGroupDetails extends ConfigurationSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationJobs.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationJobs.java new file mode 100644 index 0000000000000..f2b2bf33fca73 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationJobs.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationJobsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationJobs. + */ +public interface ReplicationJobs extends HasInner { + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable cancelAsync(String jobName); + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable restartAsync(String jobName); + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable resumeAsync(String jobName); + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable exportAsync(JobQueryParameter jobQueryParameter); + + /** + * Gets the job details. + * Get the details of an Azure Site Recovery job. + * + * @param jobName Job identifier + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String jobName); + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationLogicalNetworks.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationLogicalNetworks.java new file mode 100644 index 0000000000000..9eef22b7825ed --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationLogicalNetworks.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationLogicalNetworksInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationLogicalNetworks. + */ +public interface ReplicationLogicalNetworks extends HasInner { + /** + * Gets a logical network with specified server id and logical network name. + * Gets the details of a logical network. + * + * @param fabricName Server Id. + * @param logicalNetworkName Logical network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String logicalNetworkName); + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param fabricName Server Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationMigrationItems.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationMigrationItems.java new file mode 100644 index 0000000000000..1e10b3d7fe532 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationMigrationItems.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationMigrationItemsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationMigrationItems. + */ +public interface ReplicationMigrationItems extends SupportsCreating, HasInner { + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable migrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties); + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties); + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties); + + /** + * Gets the list of migration items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName); + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName); + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String protectionContainerName, String migrationItemName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworkMappings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworkMappings.java new file mode 100644 index 0000000000000..e809f0174af5f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworkMappings.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationNetworkMappingsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationNetworkMappings. + */ +public interface ReplicationNetworkMappings extends SupportsCreating, HasInner { + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets network mapping by name. + * Gets the details of an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String networkName, String networkMappingName); + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationNetworksAsync(final String fabricName, final String networkName); + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String networkName, String networkMappingName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworks.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworks.java new file mode 100644 index 0000000000000..58bf9870a6ee2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationNetworks.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationNetworksInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationNetworks. + */ +public interface ReplicationNetworks extends HasInner { + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets a network with specified server id and network name. + * Gets the details of a network. + * + * @param fabricName Server Id. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String networkName); + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationPolicies.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationPolicies.java new file mode 100644 index 0000000000000..8a873e219b108 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationPolicies.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationPoliciesInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationPolicies. + */ +public interface ReplicationPolicies extends SupportsCreating, HasInner { + /** + * Gets the requested policy. + * Gets the details of a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String policyName); + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String policyName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectableItems.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectableItems.java new file mode 100644 index 0000000000000..1459a713b6b0d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectableItems.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationProtectableItemsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationProtectableItems. + */ +public interface ReplicationProtectableItems extends HasInner { + /** + * Gets the details of a protectable item. + * The operation to get the details of a protectable item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param protectableItemName Protectable item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String protectableItemName); + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItem.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItem.java new file mode 100644 index 0000000000000..e86152e0c2888 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItem.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationProtectedItemInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; +import java.util.List; + +/** + * Type representing ReplicationProtectedItem. + */ +public interface ReplicationProtectedItem extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + ReplicationProtectedItemProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the ReplicationProtectedItem definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationProtectionContainer, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of ReplicationProtectedItem definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a ReplicationProtectedItem definition. + */ + interface Blank extends WithReplicationProtectionContainer { + } + + /** + * The stage of the replicationprotecteditem definition allowing to specify ReplicationProtectionContainer. + */ + interface WithReplicationProtectionContainer { + /** + * Specifies fabricName, protectionContainerName. + * @param fabricName Name of the fabric + * @param protectionContainerName Protection container name + * @return the next definition stage + */ + WithProperties withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName); + } + + /** + * The stage of the replicationprotecteditem definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Enable protection input properties + * @return the next definition stage + */ + WithCreate withProperties(EnableProtectionInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a ReplicationProtectedItem update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of ReplicationProtectedItem update stages. + */ + interface UpdateStages { + /** + * The stage of the replicationprotecteditem update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Update replication protected item properties + * @return the next update stage + */ + Update withProperties(UpdateReplicationProtectedItemInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemOperation.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemOperation.java new file mode 100644 index 0000000000000..9d03d507e3802 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemOperation.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for ReplicationProtectedItemOperation. + */ +public final class ReplicationProtectedItemOperation extends ExpandableStringEnum { + /** Static value ReverseReplicate for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation REVERSE_REPLICATE = fromString("ReverseReplicate"); + + /** Static value Commit for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation COMMIT = fromString("Commit"); + + /** Static value PlannedFailover for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation PLANNED_FAILOVER = fromString("PlannedFailover"); + + /** Static value UnplannedFailover for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation UNPLANNED_FAILOVER = fromString("UnplannedFailover"); + + /** Static value DisableProtection for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation DISABLE_PROTECTION = fromString("DisableProtection"); + + /** Static value TestFailover for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation TEST_FAILOVER = fromString("TestFailover"); + + /** Static value TestFailoverCleanup for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation TEST_FAILOVER_CLEANUP = fromString("TestFailoverCleanup"); + + /** Static value Failback for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation FAILBACK = fromString("Failback"); + + /** Static value FinalizeFailback for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation FINALIZE_FAILBACK = fromString("FinalizeFailback"); + + /** Static value ChangePit for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation CHANGE_PIT = fromString("ChangePit"); + + /** Static value RepairReplication for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation REPAIR_REPLICATION = fromString("RepairReplication"); + + /** Static value SwitchProtection for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation SWITCH_PROTECTION = fromString("SwitchProtection"); + + /** Static value CompleteMigration for ReplicationProtectedItemOperation. */ + public static final ReplicationProtectedItemOperation COMPLETE_MIGRATION = fromString("CompleteMigration"); + + /** + * Creates or finds a ReplicationProtectedItemOperation from its string representation. + * @param name a name to look for + * @return the corresponding ReplicationProtectedItemOperation + */ + @JsonCreator + public static ReplicationProtectedItemOperation fromString(String name) { + return fromString(name, ReplicationProtectedItemOperation.class); + } + + /** + * @return known ReplicationProtectedItemOperation values + */ + public static Collection values() { + return values(ReplicationProtectedItemOperation.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemProperties.java new file mode 100644 index 0000000000000..f72b769f3f8cc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItemProperties.java @@ -0,0 +1,724 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Replication protected item custom data details. + */ +public class ReplicationProtectedItemProperties { + /** + * The name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The type of protected item type. + */ + @JsonProperty(value = "protectedItemType") + private String protectedItemType; + + /** + * The protected item ARM Id. + */ + @JsonProperty(value = "protectableItemId") + private String protectableItemId; + + /** + * The recovery provider ARM Id. + */ + @JsonProperty(value = "recoveryServicesProviderId") + private String recoveryServicesProviderId; + + /** + * The friendly name of the primary fabric. + */ + @JsonProperty(value = "primaryFabricFriendlyName") + private String primaryFabricFriendlyName; + + /** + * The fabric provider of the primary fabric. + */ + @JsonProperty(value = "primaryFabricProvider") + private String primaryFabricProvider; + + /** + * The friendly name of recovery fabric. + */ + @JsonProperty(value = "recoveryFabricFriendlyName") + private String recoveryFabricFriendlyName; + + /** + * The Arm Id of recovery fabric. + */ + @JsonProperty(value = "recoveryFabricId") + private String recoveryFabricId; + + /** + * The name of primary protection container friendly name. + */ + @JsonProperty(value = "primaryProtectionContainerFriendlyName") + private String primaryProtectionContainerFriendlyName; + + /** + * The name of recovery container friendly name. + */ + @JsonProperty(value = "recoveryProtectionContainerFriendlyName") + private String recoveryProtectionContainerFriendlyName; + + /** + * The protection status. + */ + @JsonProperty(value = "protectionState") + private String protectionState; + + /** + * The protection state description. + */ + @JsonProperty(value = "protectionStateDescription") + private String protectionStateDescription; + + /** + * The Current active location of the PE. + */ + @JsonProperty(value = "activeLocation") + private String activeLocation; + + /** + * The Test failover state. + */ + @JsonProperty(value = "testFailoverState") + private String testFailoverState; + + /** + * The Test failover state description. + */ + @JsonProperty(value = "testFailoverStateDescription") + private String testFailoverStateDescription; + + /** + * The allowed operations on the Replication protected item. + */ + @JsonProperty(value = "allowedOperations") + private List allowedOperations; + + /** + * The consolidated protection health for the VM taking any issues with SRS + * as well as all the replication units associated with the VM's + * replication group into account. This is a string representation of the + * ProtectionHealth enumeration. + */ + @JsonProperty(value = "replicationHealth") + private String replicationHealth; + + /** + * The consolidated failover health for the VM. + */ + @JsonProperty(value = "failoverHealth") + private String failoverHealth; + + /** + * List of health errors. + */ + @JsonProperty(value = "healthErrors") + private List healthErrors; + + /** + * The ID of Policy governing this PE. + */ + @JsonProperty(value = "policyId") + private String policyId; + + /** + * The name of Policy governing this PE. + */ + @JsonProperty(value = "policyFriendlyName") + private String policyFriendlyName; + + /** + * The Last successful failover time. + */ + @JsonProperty(value = "lastSuccessfulFailoverTime") + private DateTime lastSuccessfulFailoverTime; + + /** + * The Last successful test failover time. + */ + @JsonProperty(value = "lastSuccessfulTestFailoverTime") + private DateTime lastSuccessfulTestFailoverTime; + + /** + * The current scenario. + */ + @JsonProperty(value = "currentScenario") + private CurrentScenarioDetails currentScenario; + + /** + * The recovery point ARM Id to which the Vm was failed over. + */ + @JsonProperty(value = "failoverRecoveryPointId") + private String failoverRecoveryPointId; + + /** + * The Replication provider custom settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private ReplicationProviderSpecificSettings providerSpecificDetails; + + /** + * The recovery container Id. + */ + @JsonProperty(value = "recoveryContainerId") + private String recoveryContainerId; + + /** + * Get the name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the name. + * + * @param friendlyName the friendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the type of protected item type. + * + * @return the protectedItemType value + */ + public String protectedItemType() { + return this.protectedItemType; + } + + /** + * Set the type of protected item type. + * + * @param protectedItemType the protectedItemType value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withProtectedItemType(String protectedItemType) { + this.protectedItemType = protectedItemType; + return this; + } + + /** + * Get the protected item ARM Id. + * + * @return the protectableItemId value + */ + public String protectableItemId() { + return this.protectableItemId; + } + + /** + * Set the protected item ARM Id. + * + * @param protectableItemId the protectableItemId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withProtectableItemId(String protectableItemId) { + this.protectableItemId = protectableItemId; + return this; + } + + /** + * Get the recovery provider ARM Id. + * + * @return the recoveryServicesProviderId value + */ + public String recoveryServicesProviderId() { + return this.recoveryServicesProviderId; + } + + /** + * Set the recovery provider ARM Id. + * + * @param recoveryServicesProviderId the recoveryServicesProviderId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withRecoveryServicesProviderId(String recoveryServicesProviderId) { + this.recoveryServicesProviderId = recoveryServicesProviderId; + return this; + } + + /** + * Get the friendly name of the primary fabric. + * + * @return the primaryFabricFriendlyName value + */ + public String primaryFabricFriendlyName() { + return this.primaryFabricFriendlyName; + } + + /** + * Set the friendly name of the primary fabric. + * + * @param primaryFabricFriendlyName the primaryFabricFriendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withPrimaryFabricFriendlyName(String primaryFabricFriendlyName) { + this.primaryFabricFriendlyName = primaryFabricFriendlyName; + return this; + } + + /** + * Get the fabric provider of the primary fabric. + * + * @return the primaryFabricProvider value + */ + public String primaryFabricProvider() { + return this.primaryFabricProvider; + } + + /** + * Set the fabric provider of the primary fabric. + * + * @param primaryFabricProvider the primaryFabricProvider value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withPrimaryFabricProvider(String primaryFabricProvider) { + this.primaryFabricProvider = primaryFabricProvider; + return this; + } + + /** + * Get the friendly name of recovery fabric. + * + * @return the recoveryFabricFriendlyName value + */ + public String recoveryFabricFriendlyName() { + return this.recoveryFabricFriendlyName; + } + + /** + * Set the friendly name of recovery fabric. + * + * @param recoveryFabricFriendlyName the recoveryFabricFriendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withRecoveryFabricFriendlyName(String recoveryFabricFriendlyName) { + this.recoveryFabricFriendlyName = recoveryFabricFriendlyName; + return this; + } + + /** + * Get the Arm Id of recovery fabric. + * + * @return the recoveryFabricId value + */ + public String recoveryFabricId() { + return this.recoveryFabricId; + } + + /** + * Set the Arm Id of recovery fabric. + * + * @param recoveryFabricId the recoveryFabricId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withRecoveryFabricId(String recoveryFabricId) { + this.recoveryFabricId = recoveryFabricId; + return this; + } + + /** + * Get the name of primary protection container friendly name. + * + * @return the primaryProtectionContainerFriendlyName value + */ + public String primaryProtectionContainerFriendlyName() { + return this.primaryProtectionContainerFriendlyName; + } + + /** + * Set the name of primary protection container friendly name. + * + * @param primaryProtectionContainerFriendlyName the primaryProtectionContainerFriendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withPrimaryProtectionContainerFriendlyName(String primaryProtectionContainerFriendlyName) { + this.primaryProtectionContainerFriendlyName = primaryProtectionContainerFriendlyName; + return this; + } + + /** + * Get the name of recovery container friendly name. + * + * @return the recoveryProtectionContainerFriendlyName value + */ + public String recoveryProtectionContainerFriendlyName() { + return this.recoveryProtectionContainerFriendlyName; + } + + /** + * Set the name of recovery container friendly name. + * + * @param recoveryProtectionContainerFriendlyName the recoveryProtectionContainerFriendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withRecoveryProtectionContainerFriendlyName(String recoveryProtectionContainerFriendlyName) { + this.recoveryProtectionContainerFriendlyName = recoveryProtectionContainerFriendlyName; + return this; + } + + /** + * Get the protection status. + * + * @return the protectionState value + */ + public String protectionState() { + return this.protectionState; + } + + /** + * Set the protection status. + * + * @param protectionState the protectionState value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withProtectionState(String protectionState) { + this.protectionState = protectionState; + return this; + } + + /** + * Get the protection state description. + * + * @return the protectionStateDescription value + */ + public String protectionStateDescription() { + return this.protectionStateDescription; + } + + /** + * Set the protection state description. + * + * @param protectionStateDescription the protectionStateDescription value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withProtectionStateDescription(String protectionStateDescription) { + this.protectionStateDescription = protectionStateDescription; + return this; + } + + /** + * Get the Current active location of the PE. + * + * @return the activeLocation value + */ + public String activeLocation() { + return this.activeLocation; + } + + /** + * Set the Current active location of the PE. + * + * @param activeLocation the activeLocation value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withActiveLocation(String activeLocation) { + this.activeLocation = activeLocation; + return this; + } + + /** + * Get the Test failover state. + * + * @return the testFailoverState value + */ + public String testFailoverState() { + return this.testFailoverState; + } + + /** + * Set the Test failover state. + * + * @param testFailoverState the testFailoverState value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withTestFailoverState(String testFailoverState) { + this.testFailoverState = testFailoverState; + return this; + } + + /** + * Get the Test failover state description. + * + * @return the testFailoverStateDescription value + */ + public String testFailoverStateDescription() { + return this.testFailoverStateDescription; + } + + /** + * Set the Test failover state description. + * + * @param testFailoverStateDescription the testFailoverStateDescription value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withTestFailoverStateDescription(String testFailoverStateDescription) { + this.testFailoverStateDescription = testFailoverStateDescription; + return this; + } + + /** + * Get the allowed operations on the Replication protected item. + * + * @return the allowedOperations value + */ + public List allowedOperations() { + return this.allowedOperations; + } + + /** + * Set the allowed operations on the Replication protected item. + * + * @param allowedOperations the allowedOperations value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withAllowedOperations(List allowedOperations) { + this.allowedOperations = allowedOperations; + return this; + } + + /** + * Get the consolidated protection health for the VM taking any issues with SRS as well as all the replication units associated with the VM's replication group into account. This is a string representation of the ProtectionHealth enumeration. + * + * @return the replicationHealth value + */ + public String replicationHealth() { + return this.replicationHealth; + } + + /** + * Set the consolidated protection health for the VM taking any issues with SRS as well as all the replication units associated with the VM's replication group into account. This is a string representation of the ProtectionHealth enumeration. + * + * @param replicationHealth the replicationHealth value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withReplicationHealth(String replicationHealth) { + this.replicationHealth = replicationHealth; + return this; + } + + /** + * Get the consolidated failover health for the VM. + * + * @return the failoverHealth value + */ + public String failoverHealth() { + return this.failoverHealth; + } + + /** + * Set the consolidated failover health for the VM. + * + * @param failoverHealth the failoverHealth value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withFailoverHealth(String failoverHealth) { + this.failoverHealth = failoverHealth; + return this; + } + + /** + * Get list of health errors. + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Set list of health errors. + * + * @param healthErrors the healthErrors value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withHealthErrors(List healthErrors) { + this.healthErrors = healthErrors; + return this; + } + + /** + * Get the ID of Policy governing this PE. + * + * @return the policyId value + */ + public String policyId() { + return this.policyId; + } + + /** + * Set the ID of Policy governing this PE. + * + * @param policyId the policyId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withPolicyId(String policyId) { + this.policyId = policyId; + return this; + } + + /** + * Get the name of Policy governing this PE. + * + * @return the policyFriendlyName value + */ + public String policyFriendlyName() { + return this.policyFriendlyName; + } + + /** + * Set the name of Policy governing this PE. + * + * @param policyFriendlyName the policyFriendlyName value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withPolicyFriendlyName(String policyFriendlyName) { + this.policyFriendlyName = policyFriendlyName; + return this; + } + + /** + * Get the Last successful failover time. + * + * @return the lastSuccessfulFailoverTime value + */ + public DateTime lastSuccessfulFailoverTime() { + return this.lastSuccessfulFailoverTime; + } + + /** + * Set the Last successful failover time. + * + * @param lastSuccessfulFailoverTime the lastSuccessfulFailoverTime value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withLastSuccessfulFailoverTime(DateTime lastSuccessfulFailoverTime) { + this.lastSuccessfulFailoverTime = lastSuccessfulFailoverTime; + return this; + } + + /** + * Get the Last successful test failover time. + * + * @return the lastSuccessfulTestFailoverTime value + */ + public DateTime lastSuccessfulTestFailoverTime() { + return this.lastSuccessfulTestFailoverTime; + } + + /** + * Set the Last successful test failover time. + * + * @param lastSuccessfulTestFailoverTime the lastSuccessfulTestFailoverTime value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withLastSuccessfulTestFailoverTime(DateTime lastSuccessfulTestFailoverTime) { + this.lastSuccessfulTestFailoverTime = lastSuccessfulTestFailoverTime; + return this; + } + + /** + * Get the current scenario. + * + * @return the currentScenario value + */ + public CurrentScenarioDetails currentScenario() { + return this.currentScenario; + } + + /** + * Set the current scenario. + * + * @param currentScenario the currentScenario value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withCurrentScenario(CurrentScenarioDetails currentScenario) { + this.currentScenario = currentScenario; + return this; + } + + /** + * Get the recovery point ARM Id to which the Vm was failed over. + * + * @return the failoverRecoveryPointId value + */ + public String failoverRecoveryPointId() { + return this.failoverRecoveryPointId; + } + + /** + * Set the recovery point ARM Id to which the Vm was failed over. + * + * @param failoverRecoveryPointId the failoverRecoveryPointId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withFailoverRecoveryPointId(String failoverRecoveryPointId) { + this.failoverRecoveryPointId = failoverRecoveryPointId; + return this; + } + + /** + * Get the Replication provider custom settings. + * + * @return the providerSpecificDetails value + */ + public ReplicationProviderSpecificSettings providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the Replication provider custom settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withProviderSpecificDetails(ReplicationProviderSpecificSettings providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + + /** + * Get the recovery container Id. + * + * @return the recoveryContainerId value + */ + public String recoveryContainerId() { + return this.recoveryContainerId; + } + + /** + * Set the recovery container Id. + * + * @param recoveryContainerId the recoveryContainerId value to set + * @return the ReplicationProtectedItemProperties object itself. + */ + public ReplicationProtectedItemProperties withRecoveryContainerId(String recoveryContainerId) { + this.recoveryContainerId = recoveryContainerId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItems.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItems.java new file mode 100644 index 0000000000000..98bf5f0e76a3a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectedItems.java @@ -0,0 +1,186 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationProtectedItemsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationProtectedItems. + */ +public interface ReplicationProtectedItems extends SupportsCreating, HasInner { + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable failoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable repairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties); + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName); + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a Replication protected item. + * Gets the details of an ASR replication protected item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName); + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable purgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainerMappings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainerMappings.java new file mode 100644 index 0000000000000..a78bd705d22d6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainerMappings.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationProtectionContainerMappingsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationProtectionContainerMappings. + */ +public interface ReplicationProtectionContainerMappings extends SupportsCreating, HasInner { + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String protectionContainerName, String mappingName); + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets a protection container mapping/. + * Gets the details of a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection Container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName, String mappingName); + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName); + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable purgeAsync(String fabricName, String protectionContainerName, String mappingName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainers.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainers.java new file mode 100644 index 0000000000000..6a9417b3a5339 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProtectionContainers.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Observable; +import rx.Completable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationProtectionContainersInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationProtectionContainers. + */ +public interface ReplicationProtectionContainers extends SupportsCreating, HasInner { + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable discoverProtectableItemAsync(String fabricName, String protectionContainerName); + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String protectionContainerName); + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable switchProtectionAsync(String fabricName, String protectionContainerName); + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the protection container details. + * Gets the details of a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String protectionContainerName); + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderContainerUnmappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderContainerUnmappingInput.java new file mode 100644 index 0000000000000..2a1d162f59a78 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderContainerUnmappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Provider specific input for unpairing operations. + */ +public class ReplicationProviderContainerUnmappingInput { + /** + * The class type. + */ + @JsonProperty(value = "instanceType") + private String instanceType; + + /** + * Get the class type. + * + * @return the instanceType value + */ + public String instanceType() { + return this.instanceType; + } + + /** + * Set the class type. + * + * @param instanceType the instanceType value to set + * @return the ReplicationProviderContainerUnmappingInput object itself. + */ + public ReplicationProviderContainerUnmappingInput withInstanceType(String instanceType) { + this.instanceType = instanceType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerCreationInput.java new file mode 100644 index 0000000000000..343b5ea9e2e42 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerCreationInput.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific input for container creation operation. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReplicationProviderSpecificContainerCreationInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AContainerCreationInput.class), + @JsonSubTypes.Type(name = "6c7da455-506f-43ff-a16a-8eb101aebb70", value = VMwareCbtContainerCreationInput.class) +}) +public class ReplicationProviderSpecificContainerCreationInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerMappingInput.java new file mode 100644 index 0000000000000..5fd36a97cade6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificContainerMappingInput.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific input for pairing operations. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReplicationProviderSpecificContainerMappingInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AContainerMappingInput.class), + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtContainerMappingInput.class) +}) +public class ReplicationProviderSpecificContainerMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificSettings.java new file mode 100644 index 0000000000000..eacd9bf37e5b1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificSettings.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Replication provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReplicationProviderSpecificSettings") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AReplicationDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureReplicationDetails.class), + @JsonSubTypes.Type(name = "HyperVReplicaBaseReplicationDetails", value = HyperVReplicaBaseReplicationDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012R2", value = HyperVReplicaBlueReplicationDetails.class), + @JsonSubTypes.Type(name = "HyperVReplica2012", value = HyperVReplicaReplicationDetails.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2ReplicationDetails.class), + @JsonSubTypes.Type(name = "InMage", value = InMageReplicationDetails.class) +}) +public class ReplicationProviderSpecificSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificUpdateContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificUpdateContainerMappingInput.java new file mode 100644 index 0000000000000..01b7c2dc7a2f5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationProviderSpecificUpdateContainerMappingInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific input for update pairing operations. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReplicationProviderSpecificUpdateContainerMappingInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AUpdateContainerMappingInput.class) +}) +public class ReplicationProviderSpecificUpdateContainerMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryPlans.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryPlans.java new file mode 100644 index 0000000000000..5f2de19d7865d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryPlans.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationRecoveryPlansInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationRecoveryPlans. + */ +public interface ReplicationRecoveryPlans extends SupportsCreating, HasInner { + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable failoverCommitAsync(String recoveryPlanName); + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable plannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties); + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable reprotectAsync(String recoveryPlanName); + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties); + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable testFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties); + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable unplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties); + + /** + * Gets the requested recovery plan. + * Gets the details of the recovery plan. + * + * @param recoveryPlanName Name of the recovery plan. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String recoveryPlanName); + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String recoveryPlanName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryServicesProviders.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryServicesProviders.java new file mode 100644 index 0000000000000..3472d195985ec --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationRecoveryServicesProviders.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationRecoveryServicesProvidersInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationRecoveryServicesProviders. + */ +public interface ReplicationRecoveryServicesProviders extends SupportsCreating, HasInner { + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable refreshProviderAsync(String fabricName, String providerName); + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String providerName); + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a recovery services provider. + * Gets the details of registered recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String providerName); + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable purgeAsync(String fabricName, String providerName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassificationMappings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassificationMappings.java new file mode 100644 index 0000000000000..f9db4f7ae022f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassificationMappings.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationStorageClassificationMappingsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationStorageClassificationMappings. + */ +public interface ReplicationStorageClassificationMappings extends SupportsCreating, HasInner { + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a storage classification mapping. + * Gets the details of the specified storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName); + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationStorageClassificationsAsync(final String fabricName, final String storageClassificationName); + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassifications.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassifications.java new file mode 100644 index 0000000000000..614962575b76f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationStorageClassifications.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationStorageClassificationsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationStorageClassifications. + */ +public interface ReplicationStorageClassifications extends HasInner { + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a storage classification. + * Gets the details of the specified storage classification. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String storageClassificationName); + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param fabricName Site name of interest. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationVaultHealths.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationVaultHealths.java new file mode 100644 index 0000000000000..e9e6872de7b3f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationVaultHealths.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationVaultHealthsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationVaultHealths. + */ +public interface ReplicationVaultHealths extends HasInner { + /** + * Gets the health summary for the vault. + * Gets the health details of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(); + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable refreshAsync(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationvCenters.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationvCenters.java new file mode 100644 index 0000000000000..f48dc66ac6a18 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReplicationvCenters.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.ReplicationvCentersInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing ReplicationvCenters. + */ +public interface ReplicationvCenters extends SupportsCreating, HasInner { + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + + /** + * Gets the details of a vCenter. + * Gets the details of a registered vCenter server(Add vCenter server.). + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String fabricName, String vCenterName); + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationFabricsAsync(final String fabricName); + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String fabricName, String vCenterName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResourceHealthSummary.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResourceHealthSummary.java new file mode 100644 index 0000000000000..5bb4629018d90 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResourceHealthSummary.java @@ -0,0 +1,72 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Base class to define the health summary of the resources contained under an + * Arm resource. + */ +public class ResourceHealthSummary { + /** + * The count of total resources under the container. + */ + @JsonProperty(value = "resourceCount") + private Integer resourceCount; + + /** + * The list of summary of health errors across the resources under the + * container. + */ + @JsonProperty(value = "issues") + private List issues; + + /** + * Get the count of total resources under the container. + * + * @return the resourceCount value + */ + public Integer resourceCount() { + return this.resourceCount; + } + + /** + * Set the count of total resources under the container. + * + * @param resourceCount the resourceCount value to set + * @return the ResourceHealthSummary object itself. + */ + public ResourceHealthSummary withResourceCount(Integer resourceCount) { + this.resourceCount = resourceCount; + return this; + } + + /** + * Get the list of summary of health errors across the resources under the container. + * + * @return the issues value + */ + public List issues() { + return this.issues; + } + + /** + * Set the list of summary of health errors across the resources under the container. + * + * @param issues the issues value to set + * @return the ResourceHealthSummary object itself. + */ + public ResourceHealthSummary withIssues(List issues) { + this.issues = issues; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParams.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParams.java new file mode 100644 index 0000000000000..dd9f499d73ea2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParams.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Resume job params. + */ +public class ResumeJobParams { + /** + * Resume job properties. + */ + @JsonProperty(value = "properties") + private ResumeJobParamsProperties properties; + + /** + * Get resume job properties. + * + * @return the properties value + */ + public ResumeJobParamsProperties properties() { + return this.properties; + } + + /** + * Set resume job properties. + * + * @param properties the properties value to set + * @return the ResumeJobParams object itself. + */ + public ResumeJobParams withProperties(ResumeJobParamsProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParamsProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParamsProperties.java new file mode 100644 index 0000000000000..99fbb3d6b7d12 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ResumeJobParamsProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Resume job properties. + */ +public class ResumeJobParamsProperties { + /** + * Resume job comments. + */ + @JsonProperty(value = "comments") + private String comments; + + /** + * Get resume job comments. + * + * @return the comments value + */ + public String comments() { + return this.comments; + } + + /** + * Set resume job comments. + * + * @param comments the comments value to set + * @return the ResumeJobParamsProperties object itself. + */ + public ResumeJobParamsProperties withComments(String comments) { + this.comments = comments; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RetentionVolume.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RetentionVolume.java new file mode 100644 index 0000000000000..f4f0b1e12c62e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RetentionVolume.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The retention details of the MT. + */ +public class RetentionVolume { + /** + * The volume name. + */ + @JsonProperty(value = "volumeName") + private String volumeName; + + /** + * The volume capacity. + */ + @JsonProperty(value = "capacityInBytes") + private Long capacityInBytes; + + /** + * The free space available in this volume. + */ + @JsonProperty(value = "freeSpaceInBytes") + private Long freeSpaceInBytes; + + /** + * The threshold percentage. + */ + @JsonProperty(value = "thresholdPercentage") + private Integer thresholdPercentage; + + /** + * Get the volume name. + * + * @return the volumeName value + */ + public String volumeName() { + return this.volumeName; + } + + /** + * Set the volume name. + * + * @param volumeName the volumeName value to set + * @return the RetentionVolume object itself. + */ + public RetentionVolume withVolumeName(String volumeName) { + this.volumeName = volumeName; + return this; + } + + /** + * Get the volume capacity. + * + * @return the capacityInBytes value + */ + public Long capacityInBytes() { + return this.capacityInBytes; + } + + /** + * Set the volume capacity. + * + * @param capacityInBytes the capacityInBytes value to set + * @return the RetentionVolume object itself. + */ + public RetentionVolume withCapacityInBytes(Long capacityInBytes) { + this.capacityInBytes = capacityInBytes; + return this; + } + + /** + * Get the free space available in this volume. + * + * @return the freeSpaceInBytes value + */ + public Long freeSpaceInBytes() { + return this.freeSpaceInBytes; + } + + /** + * Set the free space available in this volume. + * + * @param freeSpaceInBytes the freeSpaceInBytes value to set + * @return the RetentionVolume object itself. + */ + public RetentionVolume withFreeSpaceInBytes(Long freeSpaceInBytes) { + this.freeSpaceInBytes = freeSpaceInBytes; + return this; + } + + /** + * Get the threshold percentage. + * + * @return the thresholdPercentage value + */ + public Integer thresholdPercentage() { + return this.thresholdPercentage; + } + + /** + * Set the threshold percentage. + * + * @param thresholdPercentage the thresholdPercentage value to set + * @return the RetentionVolume object itself. + */ + public RetentionVolume withThresholdPercentage(Integer thresholdPercentage) { + this.thresholdPercentage = thresholdPercentage; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInput.java new file mode 100644 index 0000000000000..583273558e4d9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Reverse replication input. + */ +public class ReverseReplicationInput { + /** + * Reverse replication properties. + */ + @JsonProperty(value = "properties") + private ReverseReplicationInputProperties properties; + + /** + * Get reverse replication properties. + * + * @return the properties value + */ + public ReverseReplicationInputProperties properties() { + return this.properties; + } + + /** + * Set reverse replication properties. + * + * @param properties the properties value to set + * @return the ReverseReplicationInput object itself. + */ + public ReverseReplicationInput withProperties(ReverseReplicationInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInputProperties.java new file mode 100644 index 0000000000000..a754402079c02 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationInputProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Reverse replication input properties. + */ +public class ReverseReplicationInputProperties { + /** + * Failover direction. + */ + @JsonProperty(value = "failoverDirection") + private String failoverDirection; + + /** + * Provider specific reverse replication input. + */ + @JsonProperty(value = "providerSpecificDetails") + private ReverseReplicationProviderSpecificInput providerSpecificDetails; + + /** + * Get failover direction. + * + * @return the failoverDirection value + */ + public String failoverDirection() { + return this.failoverDirection; + } + + /** + * Set failover direction. + * + * @param failoverDirection the failoverDirection value to set + * @return the ReverseReplicationInputProperties object itself. + */ + public ReverseReplicationInputProperties withFailoverDirection(String failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get provider specific reverse replication input. + * + * @return the providerSpecificDetails value + */ + public ReverseReplicationProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific reverse replication input. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the ReverseReplicationInputProperties object itself. + */ + public ReverseReplicationInputProperties withProviderSpecificDetails(ReverseReplicationProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationProviderSpecificInput.java new file mode 100644 index 0000000000000..5bdc2bf385e7c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ReverseReplicationProviderSpecificInput.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific reverse replication input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ReverseReplicationProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AReprotectInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureReprotectInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2ReprotectInput.class), + @JsonSubTypes.Type(name = "InMage", value = InMageReprotectInput.class) +}) +public class ReverseReplicationProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RoleAssignment.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RoleAssignment.java new file mode 100644 index 0000000000000..f31543bb54a9f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RoleAssignment.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure role assignment details. + */ +public class RoleAssignment { + /** + * The ARM Id of the role assignment. + */ + @JsonProperty(value = "id") + private String id; + + /** + * The name of the role assignment. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Role assignment scope. + */ + @JsonProperty(value = "scope") + private String scope; + + /** + * Principal Id. + */ + @JsonProperty(value = "principalId") + private String principalId; + + /** + * Role definition id. + */ + @JsonProperty(value = "roleDefinitionId") + private String roleDefinitionId; + + /** + * Get the ARM Id of the role assignment. + * + * @return the id value + */ + public String id() { + return this.id; + } + + /** + * Set the ARM Id of the role assignment. + * + * @param id the id value to set + * @return the RoleAssignment object itself. + */ + public RoleAssignment withId(String id) { + this.id = id; + return this; + } + + /** + * Get the name of the role assignment. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name of the role assignment. + * + * @param name the name value to set + * @return the RoleAssignment object itself. + */ + public RoleAssignment withName(String name) { + this.name = name; + return this; + } + + /** + * Get role assignment scope. + * + * @return the scope value + */ + public String scope() { + return this.scope; + } + + /** + * Set role assignment scope. + * + * @param scope the scope value to set + * @return the RoleAssignment object itself. + */ + public RoleAssignment withScope(String scope) { + this.scope = scope; + return this; + } + + /** + * Get principal Id. + * + * @return the principalId value + */ + public String principalId() { + return this.principalId; + } + + /** + * Set principal Id. + * + * @param principalId the principalId value to set + * @return the RoleAssignment object itself. + */ + public RoleAssignment withPrincipalId(String principalId) { + this.principalId = principalId; + return this; + } + + /** + * Get role definition id. + * + * @return the roleDefinitionId value + */ + public String roleDefinitionId() { + return this.roleDefinitionId; + } + + /** + * Set role definition id. + * + * @param roleDefinitionId the roleDefinitionId value to set + * @return the RoleAssignment object itself. + */ + public RoleAssignment withRoleDefinitionId(String roleDefinitionId) { + this.roleDefinitionId = roleDefinitionId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RpInMageRecoveryPointType.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RpInMageRecoveryPointType.java new file mode 100644 index 0000000000000..97c1ce640e7bc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RpInMageRecoveryPointType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for RpInMageRecoveryPointType. + */ +public final class RpInMageRecoveryPointType extends ExpandableStringEnum { + /** Static value LatestTime for RpInMageRecoveryPointType. */ + public static final RpInMageRecoveryPointType LATEST_TIME = fromString("LatestTime"); + + /** Static value LatestTag for RpInMageRecoveryPointType. */ + public static final RpInMageRecoveryPointType LATEST_TAG = fromString("LatestTag"); + + /** Static value Custom for RpInMageRecoveryPointType. */ + public static final RpInMageRecoveryPointType CUSTOM = fromString("Custom"); + + /** + * Creates or finds a RpInMageRecoveryPointType from its string representation. + * @param name a name to look for + * @return the corresponding RpInMageRecoveryPointType + */ + @JsonCreator + public static RpInMageRecoveryPointType fromString(String name) { + return fromString(name, RpInMageRecoveryPointType.class); + } + + /** + * @return known RpInMageRecoveryPointType values + */ + public static Collection values() { + return values(RpInMageRecoveryPointType.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RunAsAccount.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RunAsAccount.java new file mode 100644 index 0000000000000..5734e2ebcdcdd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/RunAsAccount.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * CS Accounts Details. + */ +public class RunAsAccount { + /** + * The CS RunAs account Id. + */ + @JsonProperty(value = "accountId") + private String accountId; + + /** + * The CS RunAs account name. + */ + @JsonProperty(value = "accountName") + private String accountName; + + /** + * Get the CS RunAs account Id. + * + * @return the accountId value + */ + public String accountId() { + return this.accountId; + } + + /** + * Set the CS RunAs account Id. + * + * @param accountId the accountId value to set + * @return the RunAsAccount object itself. + */ + public RunAsAccount withAccountId(String accountId) { + this.accountId = accountId; + return this; + } + + /** + * Get the CS RunAs account name. + * + * @return the accountName value + */ + public String accountName() { + return this.accountName; + } + + /** + * Set the CS RunAs account name. + * + * @param accountName the accountName value to set + * @return the RunAsAccount object itself. + */ + public RunAsAccount withAccountName(String accountName) { + this.accountName = accountName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SanEnableProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SanEnableProtectionInput.java new file mode 100644 index 0000000000000..782be30984138 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SanEnableProtectionInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * San enable protection provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("San") +public class SanEnableProtectionInput extends EnableProtectionProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ScriptActionTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ScriptActionTaskDetails.java new file mode 100644 index 0000000000000..bd10b981e28b4 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ScriptActionTaskDetails.java @@ -0,0 +1,125 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the script action task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("ScriptActionTaskDetails") +public class ScriptActionTaskDetails extends TaskTypeDetails { + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The path. + */ + @JsonProperty(value = "path") + private String path; + + /** + * The output. + */ + @JsonProperty(value = "output") + private String output; + + /** + * A value indicating whether it is a primary side script or not. + */ + @JsonProperty(value = "isPrimarySideScript") + private Boolean isPrimarySideScript; + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the ScriptActionTaskDetails object itself. + */ + public ScriptActionTaskDetails withName(String name) { + this.name = name; + return this; + } + + /** + * Get the path. + * + * @return the path value + */ + public String path() { + return this.path; + } + + /** + * Set the path. + * + * @param path the path value to set + * @return the ScriptActionTaskDetails object itself. + */ + public ScriptActionTaskDetails withPath(String path) { + this.path = path; + return this; + } + + /** + * Get the output. + * + * @return the output value + */ + public String output() { + return this.output; + } + + /** + * Set the output. + * + * @param output the output value to set + * @return the ScriptActionTaskDetails object itself. + */ + public ScriptActionTaskDetails withOutput(String output) { + this.output = output; + return this; + } + + /** + * Get a value indicating whether it is a primary side script or not. + * + * @return the isPrimarySideScript value + */ + public Boolean isPrimarySideScript() { + return this.isPrimarySideScript; + } + + /** + * Set a value indicating whether it is a primary side script or not. + * + * @param isPrimarySideScript the isPrimarySideScript value to set + * @return the ScriptActionTaskDetails object itself. + */ + public ScriptActionTaskDetails withIsPrimarySideScript(Boolean isPrimarySideScript) { + this.isPrimarySideScript = isPrimarySideScript; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ServiceError.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ServiceError.java new file mode 100644 index 0000000000000..db4b5a732ac20 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/ServiceError.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * ASR error model. + */ +public class ServiceError { + /** + * Error code. + */ + @JsonProperty(value = "code") + private String code; + + /** + * Error message. + */ + @JsonProperty(value = "message") + private String message; + + /** + * Possible causes of error. + */ + @JsonProperty(value = "possibleCauses") + private String possibleCauses; + + /** + * Recommended action to resolve error. + */ + @JsonProperty(value = "recommendedAction") + private String recommendedAction; + + /** + * Activity Id. + */ + @JsonProperty(value = "activityId") + private String activityId; + + /** + * Get error code. + * + * @return the code value + */ + public String code() { + return this.code; + } + + /** + * Set error code. + * + * @param code the code value to set + * @return the ServiceError object itself. + */ + public ServiceError withCode(String code) { + this.code = code; + return this; + } + + /** + * Get error message. + * + * @return the message value + */ + public String message() { + return this.message; + } + + /** + * Set error message. + * + * @param message the message value to set + * @return the ServiceError object itself. + */ + public ServiceError withMessage(String message) { + this.message = message; + return this; + } + + /** + * Get possible causes of error. + * + * @return the possibleCauses value + */ + public String possibleCauses() { + return this.possibleCauses; + } + + /** + * Set possible causes of error. + * + * @param possibleCauses the possibleCauses value to set + * @return the ServiceError object itself. + */ + public ServiceError withPossibleCauses(String possibleCauses) { + this.possibleCauses = possibleCauses; + return this; + } + + /** + * Get recommended action to resolve error. + * + * @return the recommendedAction value + */ + public String recommendedAction() { + return this.recommendedAction; + } + + /** + * Set recommended action to resolve error. + * + * @param recommendedAction the recommendedAction value to set + * @return the ServiceError object itself. + */ + public ServiceError withRecommendedAction(String recommendedAction) { + this.recommendedAction = recommendedAction; + return this; + } + + /** + * Get activity Id. + * + * @return the activityId value + */ + public String activityId() { + return this.activityId; + } + + /** + * Set activity Id. + * + * @param activityId the activityId value to set + * @return the ServiceError object itself. + */ + public ServiceError withActivityId(String activityId) { + this.activityId = activityId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SetMultiVmSyncStatus.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SetMultiVmSyncStatus.java new file mode 100644 index 0000000000000..57a315be06144 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SetMultiVmSyncStatus.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SetMultiVmSyncStatus. + */ +public final class SetMultiVmSyncStatus extends ExpandableStringEnum { + /** Static value Enable for SetMultiVmSyncStatus. */ + public static final SetMultiVmSyncStatus ENABLE = fromString("Enable"); + + /** Static value Disable for SetMultiVmSyncStatus. */ + public static final SetMultiVmSyncStatus DISABLE = fromString("Disable"); + + /** + * Creates or finds a SetMultiVmSyncStatus from its string representation. + * @param name a name to look for + * @return the corresponding SetMultiVmSyncStatus + */ + @JsonCreator + public static SetMultiVmSyncStatus fromString(String name) { + return fromString(name, SetMultiVmSyncStatus.class); + } + + /** + * @return known SetMultiVmSyncStatus values + */ + public static Collection values() { + return values(SetMultiVmSyncStatus.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Severity.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Severity.java new file mode 100644 index 0000000000000..a36d0a1040d66 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Severity.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for Severity. + */ +public final class Severity extends ExpandableStringEnum { + /** Static value NONE for Severity. */ + public static final Severity NONE = fromString("NONE"); + + /** Static value Warning for Severity. */ + public static final Severity WARNING = fromString("Warning"); + + /** Static value Error for Severity. */ + public static final Severity ERROR = fromString("Error"); + + /** Static value Info for Severity. */ + public static final Severity INFO = fromString("Info"); + + /** + * Creates or finds a Severity from its string representation. + * @param name a name to look for + * @return the corresponding Severity + */ + @JsonCreator + public static Severity fromString(String name) { + return fromString(name, Severity.class); + } + + /** + * @return known Severity values + */ + public static Collection values() { + return values(Severity.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SourceSiteOperations.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SourceSiteOperations.java new file mode 100644 index 0000000000000..327651592c168 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SourceSiteOperations.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SourceSiteOperations. + */ +public final class SourceSiteOperations extends ExpandableStringEnum { + /** Static value Required for SourceSiteOperations. */ + public static final SourceSiteOperations REQUIRED = fromString("Required"); + + /** Static value NotRequired for SourceSiteOperations. */ + public static final SourceSiteOperations NOT_REQUIRED = fromString("NotRequired"); + + /** + * Creates or finds a SourceSiteOperations from its string representation. + * @param name a name to look for + * @return the corresponding SourceSiteOperations + */ + @JsonCreator + public static SourceSiteOperations fromString(String name) { + return fromString(name, SourceSiteOperations.class); + } + + /** + * @return known SourceSiteOperations values + */ + public static Collection values() { + return values(SourceSiteOperations.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassification.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassification.java new file mode 100644 index 0000000000000..503e53308161c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassification.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.StorageClassificationInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing StorageClassification. + */ +public interface StorageClassification extends HasInner, Indexable, Refreshable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + StorageClassificationProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMapping.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMapping.java new file mode 100644 index 0000000000000..3e7f612e33339 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMapping.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.StorageClassificationMappingInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing StorageClassificationMapping. + */ +public interface StorageClassificationMapping extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + StorageClassificationMappingProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the StorageClassificationMapping definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationStorageClassification, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of StorageClassificationMapping definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a StorageClassificationMapping definition. + */ + interface Blank extends WithReplicationStorageClassification { + } + + /** + * The stage of the storageclassificationmapping definition allowing to specify ReplicationStorageClassification. + */ + interface WithReplicationStorageClassification { + /** + * Specifies fabricName, storageClassificationName. + * @param fabricName Fabric name + * @param storageClassificationName Storage classification name + * @return the next definition stage + */ + WithProperties withExistingReplicationStorageClassification(String fabricName, String storageClassificationName); + } + + /** + * The stage of the storageclassificationmapping definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Storage mapping input properties + * @return the next definition stage + */ + WithCreate withProperties(StorageMappingInputProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a StorageClassificationMapping update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of StorageClassificationMapping update stages. + */ + interface UpdateStages { + /** + * The stage of the storageclassificationmapping update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties Storage mapping input properties + * @return the next update stage + */ + Update withProperties(StorageMappingInputProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingInput.java new file mode 100644 index 0000000000000..d4fbb78d88e0e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Storage mapping input. + */ +public class StorageClassificationMappingInput { + /** + * Storage mapping input properties. + */ + @JsonProperty(value = "properties") + private StorageMappingInputProperties properties; + + /** + * Get storage mapping input properties. + * + * @return the properties value + */ + public StorageMappingInputProperties properties() { + return this.properties; + } + + /** + * Set storage mapping input properties. + * + * @param properties the properties value to set + * @return the StorageClassificationMappingInput object itself. + */ + public StorageClassificationMappingInput withProperties(StorageMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingProperties.java new file mode 100644 index 0000000000000..a02465a5de5a8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationMappingProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Storage mapping properties. + */ +public class StorageClassificationMappingProperties { + /** + * Target storage object Id. + */ + @JsonProperty(value = "targetStorageClassificationId") + private String targetStorageClassificationId; + + /** + * Get target storage object Id. + * + * @return the targetStorageClassificationId value + */ + public String targetStorageClassificationId() { + return this.targetStorageClassificationId; + } + + /** + * Set target storage object Id. + * + * @param targetStorageClassificationId the targetStorageClassificationId value to set + * @return the StorageClassificationMappingProperties object itself. + */ + public StorageClassificationMappingProperties withTargetStorageClassificationId(String targetStorageClassificationId) { + this.targetStorageClassificationId = targetStorageClassificationId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationProperties.java new file mode 100644 index 0000000000000..47e6c4cdc3ba8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageClassificationProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Storage object properties. + */ +public class StorageClassificationProperties { + /** + * Friendly name of the Storage classification. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * Get friendly name of the Storage classification. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set friendly name of the Storage classification. + * + * @param friendlyName the friendlyName value to set + * @return the StorageClassificationProperties object itself. + */ + public StorageClassificationProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageMappingInputProperties.java new file mode 100644 index 0000000000000..fb2a4cbefa0ab --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/StorageMappingInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Storage mapping input properties. + */ +public class StorageMappingInputProperties { + /** + * The ID of the storage object. + */ + @JsonProperty(value = "targetStorageClassificationId") + private String targetStorageClassificationId; + + /** + * Get the ID of the storage object. + * + * @return the targetStorageClassificationId value + */ + public String targetStorageClassificationId() { + return this.targetStorageClassificationId; + } + + /** + * Set the ID of the storage object. + * + * @param targetStorageClassificationId the targetStorageClassificationId value to set + * @return the StorageMappingInputProperties object itself. + */ + public StorageMappingInputProperties withTargetStorageClassificationId(String targetStorageClassificationId) { + this.targetStorageClassificationId = targetStorageClassificationId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Subnet.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Subnet.java new file mode 100644 index 0000000000000..0ca5565a195fd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/Subnet.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Subnets of the network. + */ +public class Subnet { + /** + * The subnet name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The subnet friendly name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The list of addresses for the subnet. + */ + @JsonProperty(value = "addressList") + private List addressList; + + /** + * Get the subnet name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the subnet name. + * + * @param name the name value to set + * @return the Subnet object itself. + */ + public Subnet withName(String name) { + this.name = name; + return this; + } + + /** + * Get the subnet friendly name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the subnet friendly name. + * + * @param friendlyName the friendlyName value to set + * @return the Subnet object itself. + */ + public Subnet withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the list of addresses for the subnet. + * + * @return the addressList value + */ + public List addressList() { + return this.addressList; + } + + /** + * Set the list of addresses for the subnet. + * + * @param addressList the addressList value to set + * @return the Subnet object itself. + */ + public Subnet withAddressList(List addressList) { + this.addressList = addressList; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInput.java new file mode 100644 index 0000000000000..47f1cb85cd30a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Switch protection input. + */ +public class SwitchProtectionInput { + /** + * Switch protection properties. + */ + @JsonProperty(value = "properties") + private SwitchProtectionInputProperties properties; + + /** + * Get switch protection properties. + * + * @return the properties value + */ + public SwitchProtectionInputProperties properties() { + return this.properties; + } + + /** + * Set switch protection properties. + * + * @param properties the properties value to set + * @return the SwitchProtectionInput object itself. + */ + public SwitchProtectionInput withProperties(SwitchProtectionInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInputProperties.java new file mode 100644 index 0000000000000..de15678ef45a8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionInputProperties.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Switch protection input properties. + */ +public class SwitchProtectionInputProperties { + /** + * The unique replication protected item name. + */ + @JsonProperty(value = "replicationProtectedItemName") + private String replicationProtectedItemName; + + /** + * Provider specific switch protection input. + */ + @JsonProperty(value = "providerSpecificDetails") + private SwitchProtectionProviderSpecificInput providerSpecificDetails; + + /** + * Get the unique replication protected item name. + * + * @return the replicationProtectedItemName value + */ + public String replicationProtectedItemName() { + return this.replicationProtectedItemName; + } + + /** + * Set the unique replication protected item name. + * + * @param replicationProtectedItemName the replicationProtectedItemName value to set + * @return the SwitchProtectionInputProperties object itself. + */ + public SwitchProtectionInputProperties withReplicationProtectedItemName(String replicationProtectedItemName) { + this.replicationProtectedItemName = replicationProtectedItemName; + return this; + } + + /** + * Get provider specific switch protection input. + * + * @return the providerSpecificDetails value + */ + public SwitchProtectionProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific switch protection input. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the SwitchProtectionInputProperties object itself. + */ + public SwitchProtectionInputProperties withProviderSpecificDetails(SwitchProtectionProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionJobDetails.java new file mode 100644 index 0000000000000..ad61ceb3d2f6f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionJobDetails.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents details for switch protection job. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("SwitchProtectionJobDetails") +public class SwitchProtectionJobDetails extends JobDetails { + /** + * ARM Id of the new replication protected item. + */ + @JsonProperty(value = "newReplicationProtectedItemId") + private String newReplicationProtectedItemId; + + /** + * Get aRM Id of the new replication protected item. + * + * @return the newReplicationProtectedItemId value + */ + public String newReplicationProtectedItemId() { + return this.newReplicationProtectedItemId; + } + + /** + * Set aRM Id of the new replication protected item. + * + * @param newReplicationProtectedItemId the newReplicationProtectedItemId value to set + * @return the SwitchProtectionJobDetails object itself. + */ + public SwitchProtectionJobDetails withNewReplicationProtectedItemId(String newReplicationProtectedItemId) { + this.newReplicationProtectedItemId = newReplicationProtectedItemId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionProviderSpecificInput.java new file mode 100644 index 0000000000000..f624855a44089 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/SwitchProtectionProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Provider specific switch protection input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("SwitchProtectionProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2ASwitchProtectionInput.class) +}) +public class SwitchProtectionProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSize.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSize.java new file mode 100644 index 0000000000000..538c40a01e6ca --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSize.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.TargetComputeSizeInner; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing TargetComputeSize. + */ +public interface TargetComputeSize extends HasInner, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + TargetComputeSizeProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizeProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizeProperties.java new file mode 100644 index 0000000000000..ecca6cbd68aef --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizeProperties.java @@ -0,0 +1,227 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents applicable recovery vm sizes properties. + */ +public class TargetComputeSizeProperties { + /** + * Target compute size name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Target compute size display name. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The maximum cpu cores count supported by target compute size. + */ + @JsonProperty(value = "cpuCoresCount") + private Integer cpuCoresCount; + + /** + * The maximum memory in GB supported by target compute size. + */ + @JsonProperty(value = "memoryInGB") + private Double memoryInGB; + + /** + * The maximum data disks count supported by target compute size. + */ + @JsonProperty(value = "maxDataDiskCount") + private Integer maxDataDiskCount; + + /** + * The maximum Nics count supported by target compute size. + */ + @JsonProperty(value = "maxNicsCount") + private Integer maxNicsCount; + + /** + * The reasons why the target compute size is not applicable for the + * protected item. + */ + @JsonProperty(value = "errors") + private List errors; + + /** + * The value indicating whether the target compute size supports high Iops. + */ + @JsonProperty(value = "highIopsSupported") + private String highIopsSupported; + + /** + * Get target compute size name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set target compute size name. + * + * @param name the name value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withName(String name) { + this.name = name; + return this; + } + + /** + * Get target compute size display name. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set target compute size display name. + * + * @param friendlyName the friendlyName value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the maximum cpu cores count supported by target compute size. + * + * @return the cpuCoresCount value + */ + public Integer cpuCoresCount() { + return this.cpuCoresCount; + } + + /** + * Set the maximum cpu cores count supported by target compute size. + * + * @param cpuCoresCount the cpuCoresCount value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withCpuCoresCount(Integer cpuCoresCount) { + this.cpuCoresCount = cpuCoresCount; + return this; + } + + /** + * Get the maximum memory in GB supported by target compute size. + * + * @return the memoryInGB value + */ + public Double memoryInGB() { + return this.memoryInGB; + } + + /** + * Set the maximum memory in GB supported by target compute size. + * + * @param memoryInGB the memoryInGB value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withMemoryInGB(Double memoryInGB) { + this.memoryInGB = memoryInGB; + return this; + } + + /** + * Get the maximum data disks count supported by target compute size. + * + * @return the maxDataDiskCount value + */ + public Integer maxDataDiskCount() { + return this.maxDataDiskCount; + } + + /** + * Set the maximum data disks count supported by target compute size. + * + * @param maxDataDiskCount the maxDataDiskCount value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withMaxDataDiskCount(Integer maxDataDiskCount) { + this.maxDataDiskCount = maxDataDiskCount; + return this; + } + + /** + * Get the maximum Nics count supported by target compute size. + * + * @return the maxNicsCount value + */ + public Integer maxNicsCount() { + return this.maxNicsCount; + } + + /** + * Set the maximum Nics count supported by target compute size. + * + * @param maxNicsCount the maxNicsCount value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withMaxNicsCount(Integer maxNicsCount) { + this.maxNicsCount = maxNicsCount; + return this; + } + + /** + * Get the reasons why the target compute size is not applicable for the protected item. + * + * @return the errors value + */ + public List errors() { + return this.errors; + } + + /** + * Set the reasons why the target compute size is not applicable for the protected item. + * + * @param errors the errors value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withErrors(List errors) { + this.errors = errors; + return this; + } + + /** + * Get the value indicating whether the target compute size supports high Iops. + * + * @return the highIopsSupported value + */ + public String highIopsSupported() { + return this.highIopsSupported; + } + + /** + * Set the value indicating whether the target compute size supports high Iops. + * + * @param highIopsSupported the highIopsSupported value to set + * @return the TargetComputeSizeProperties object itself. + */ + public TargetComputeSizeProperties withHighIopsSupported(String highIopsSupported) { + this.highIopsSupported = highIopsSupported; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizes.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizes.java new file mode 100644 index 0000000000000..e28364d575779 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TargetComputeSizes.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.TargetComputeSizesInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing TargetComputeSizes. + */ +public interface TargetComputeSizes extends HasInner { + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TaskTypeDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TaskTypeDetails.java new file mode 100644 index 0000000000000..38efd8e14395b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TaskTypeDetails.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Task details based on specific task type. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("TaskTypeDetails") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "AutomationRunbookTaskDetails", value = AutomationRunbookTaskDetails.class), + @JsonSubTypes.Type(name = "ConsistencyCheckTaskDetails", value = ConsistencyCheckTaskDetails.class), + @JsonSubTypes.Type(name = "FabricReplicationGroupTaskDetails", value = FabricReplicationGroupTaskDetails.class), + @JsonSubTypes.Type(name = "JobTaskDetails", value = JobTaskDetails.class), + @JsonSubTypes.Type(name = "ManualActionTaskDetails", value = ManualActionTaskDetails.class), + @JsonSubTypes.Type(name = "ScriptActionTaskDetails", value = ScriptActionTaskDetails.class), + @JsonSubTypes.Type(name = "VirtualMachineTaskDetails", value = VirtualMachineTaskDetails.class), + @JsonSubTypes.Type(name = "VmNicUpdatesTaskDetails", value = VmNicUpdatesTaskDetails.class) +}) +public class TaskTypeDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInput.java new file mode 100644 index 0000000000000..fa0b5d80102f6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for test failover cleanup. + */ +public class TestFailoverCleanupInput { + /** + * Test failover cleanup input properties. + */ + @JsonProperty(value = "properties", required = true) + private TestFailoverCleanupInputProperties properties; + + /** + * Get test failover cleanup input properties. + * + * @return the properties value + */ + public TestFailoverCleanupInputProperties properties() { + return this.properties; + } + + /** + * Set test failover cleanup input properties. + * + * @param properties the properties value to set + * @return the TestFailoverCleanupInput object itself. + */ + public TestFailoverCleanupInput withProperties(TestFailoverCleanupInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInputProperties.java new file mode 100644 index 0000000000000..836093bdea4bb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverCleanupInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for test failover cleanup input properties. + */ +public class TestFailoverCleanupInputProperties { + /** + * Test failover cleanup comments. + */ + @JsonProperty(value = "comments") + private String comments; + + /** + * Get test failover cleanup comments. + * + * @return the comments value + */ + public String comments() { + return this.comments; + } + + /** + * Set test failover cleanup comments. + * + * @param comments the comments value to set + * @return the TestFailoverCleanupInputProperties object itself. + */ + public TestFailoverCleanupInputProperties withComments(String comments) { + this.comments = comments; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInput.java new file mode 100644 index 0000000000000..54a43100bcd7f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover. + */ +public class TestFailoverInput { + /** + * Planned failover input properties. + */ + @JsonProperty(value = "properties") + private TestFailoverInputProperties properties; + + /** + * Get planned failover input properties. + * + * @return the properties value + */ + public TestFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set planned failover input properties. + * + * @param properties the properties value to set + * @return the TestFailoverInput object itself. + */ + public TestFailoverInput withProperties(TestFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInputProperties.java new file mode 100644 index 0000000000000..a1001040c4ee7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverInputProperties.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover input properties. + */ +public class TestFailoverInputProperties { + /** + * Failover direction. + */ + @JsonProperty(value = "failoverDirection") + private String failoverDirection; + + /** + * Network type to be used for test failover. + */ + @JsonProperty(value = "networkType") + private String networkType; + + /** + * The id of the network to be used for test failover. + */ + @JsonProperty(value = "networkId") + private String networkId; + + /** + * A value indicating whether the test failover cleanup is to be skipped. + */ + @JsonProperty(value = "skipTestFailoverCleanup") + private String skipTestFailoverCleanup; + + /** + * Provider specific settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private ProviderSpecificFailoverInput providerSpecificDetails; + + /** + * Get failover direction. + * + * @return the failoverDirection value + */ + public String failoverDirection() { + return this.failoverDirection; + } + + /** + * Set failover direction. + * + * @param failoverDirection the failoverDirection value to set + * @return the TestFailoverInputProperties object itself. + */ + public TestFailoverInputProperties withFailoverDirection(String failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get network type to be used for test failover. + * + * @return the networkType value + */ + public String networkType() { + return this.networkType; + } + + /** + * Set network type to be used for test failover. + * + * @param networkType the networkType value to set + * @return the TestFailoverInputProperties object itself. + */ + public TestFailoverInputProperties withNetworkType(String networkType) { + this.networkType = networkType; + return this; + } + + /** + * Get the id of the network to be used for test failover. + * + * @return the networkId value + */ + public String networkId() { + return this.networkId; + } + + /** + * Set the id of the network to be used for test failover. + * + * @param networkId the networkId value to set + * @return the TestFailoverInputProperties object itself. + */ + public TestFailoverInputProperties withNetworkId(String networkId) { + this.networkId = networkId; + return this; + } + + /** + * Get a value indicating whether the test failover cleanup is to be skipped. + * + * @return the skipTestFailoverCleanup value + */ + public String skipTestFailoverCleanup() { + return this.skipTestFailoverCleanup; + } + + /** + * Set a value indicating whether the test failover cleanup is to be skipped. + * + * @param skipTestFailoverCleanup the skipTestFailoverCleanup value to set + * @return the TestFailoverInputProperties object itself. + */ + public TestFailoverInputProperties withSkipTestFailoverCleanup(String skipTestFailoverCleanup) { + this.skipTestFailoverCleanup = skipTestFailoverCleanup; + return this; + } + + /** + * Get provider specific settings. + * + * @return the providerSpecificDetails value + */ + public ProviderSpecificFailoverInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the TestFailoverInputProperties object itself. + */ + public TestFailoverInputProperties withProviderSpecificDetails(ProviderSpecificFailoverInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverJobDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverJobDetails.java new file mode 100644 index 0000000000000..4258ebd5c3602 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestFailoverJobDetails.java @@ -0,0 +1,178 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the details for a test failover job. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("TestFailoverJobDetails") +public class TestFailoverJobDetails extends JobDetails { + /** + * The test failover status. + */ + @JsonProperty(value = "testFailoverStatus") + private String testFailoverStatus; + + /** + * The test failover comments. + */ + @JsonProperty(value = "comments") + private String comments; + + /** + * The test network name. + */ + @JsonProperty(value = "networkName") + private String networkName; + + /** + * The test network friendly name. + */ + @JsonProperty(value = "networkFriendlyName") + private String networkFriendlyName; + + /** + * The test network type (see TestFailoverInput enum for possible values). + */ + @JsonProperty(value = "networkType") + private String networkType; + + /** + * The test VM details. + */ + @JsonProperty(value = "protectedItemDetails") + private List protectedItemDetails; + + /** + * Get the test failover status. + * + * @return the testFailoverStatus value + */ + public String testFailoverStatus() { + return this.testFailoverStatus; + } + + /** + * Set the test failover status. + * + * @param testFailoverStatus the testFailoverStatus value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withTestFailoverStatus(String testFailoverStatus) { + this.testFailoverStatus = testFailoverStatus; + return this; + } + + /** + * Get the test failover comments. + * + * @return the comments value + */ + public String comments() { + return this.comments; + } + + /** + * Set the test failover comments. + * + * @param comments the comments value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withComments(String comments) { + this.comments = comments; + return this; + } + + /** + * Get the test network name. + * + * @return the networkName value + */ + public String networkName() { + return this.networkName; + } + + /** + * Set the test network name. + * + * @param networkName the networkName value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withNetworkName(String networkName) { + this.networkName = networkName; + return this; + } + + /** + * Get the test network friendly name. + * + * @return the networkFriendlyName value + */ + public String networkFriendlyName() { + return this.networkFriendlyName; + } + + /** + * Set the test network friendly name. + * + * @param networkFriendlyName the networkFriendlyName value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withNetworkFriendlyName(String networkFriendlyName) { + this.networkFriendlyName = networkFriendlyName; + return this; + } + + /** + * Get the test network type (see TestFailoverInput enum for possible values). + * + * @return the networkType value + */ + public String networkType() { + return this.networkType; + } + + /** + * Set the test network type (see TestFailoverInput enum for possible values). + * + * @param networkType the networkType value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withNetworkType(String networkType) { + this.networkType = networkType; + return this; + } + + /** + * Get the test VM details. + * + * @return the protectedItemDetails value + */ + public List protectedItemDetails() { + return this.protectedItemDetails; + } + + /** + * Set the test VM details. + * + * @param protectedItemDetails the protectedItemDetails value to set + * @return the TestFailoverJobDetails object itself. + */ + public TestFailoverJobDetails withProtectedItemDetails(List protectedItemDetails) { + this.protectedItemDetails = protectedItemDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInput.java new file mode 100644 index 0000000000000..f19aeec944aac --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input for test migrate cleanup. + */ +public class TestMigrateCleanupInput { + /** + * Test migrate cleanup input properties. + */ + @JsonProperty(value = "properties", required = true) + private TestMigrateCleanupInputProperties properties; + + /** + * Get test migrate cleanup input properties. + * + * @return the properties value + */ + public TestMigrateCleanupInputProperties properties() { + return this.properties; + } + + /** + * Set test migrate cleanup input properties. + * + * @param properties the properties value to set + * @return the TestMigrateCleanupInput object itself. + */ + public TestMigrateCleanupInput withProperties(TestMigrateCleanupInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInputProperties.java new file mode 100644 index 0000000000000..c88b3cdd38a07 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateCleanupInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Test migrate cleanup input properties. + */ +public class TestMigrateCleanupInputProperties { + /** + * Test migrate cleanup comments. + */ + @JsonProperty(value = "comments") + private String comments; + + /** + * Get test migrate cleanup comments. + * + * @return the comments value + */ + public String comments() { + return this.comments; + } + + /** + * Set test migrate cleanup comments. + * + * @param comments the comments value to set + * @return the TestMigrateCleanupInputProperties object itself. + */ + public TestMigrateCleanupInputProperties withComments(String comments) { + this.comments = comments; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInput.java new file mode 100644 index 0000000000000..25dd86f674f11 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input for test migrate. + */ +public class TestMigrateInput { + /** + * Test migrate input properties. + */ + @JsonProperty(value = "properties", required = true) + private TestMigrateInputProperties properties; + + /** + * Get test migrate input properties. + * + * @return the properties value + */ + public TestMigrateInputProperties properties() { + return this.properties; + } + + /** + * Set test migrate input properties. + * + * @param properties the properties value to set + * @return the TestMigrateInput object itself. + */ + public TestMigrateInput withProperties(TestMigrateInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInputProperties.java new file mode 100644 index 0000000000000..20548a3fb09a0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Test migrate input properties. + */ +public class TestMigrateInputProperties { + /** + * The provider specific details. + */ + @JsonProperty(value = "providerSpecificDetails", required = true) + private TestMigrateProviderSpecificInput providerSpecificDetails; + + /** + * Get the provider specific details. + * + * @return the providerSpecificDetails value + */ + public TestMigrateProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific details. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the TestMigrateInputProperties object itself. + */ + public TestMigrateInputProperties withProviderSpecificDetails(TestMigrateProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateProviderSpecificInput.java new file mode 100644 index 0000000000000..b5148dd14523e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrateProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Test migrate provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("TestMigrateProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtTestMigrateInput.class) +}) +public class TestMigrateProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrationState.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrationState.java new file mode 100644 index 0000000000000..80549233bc5ad --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/TestMigrationState.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for TestMigrationState. + */ +public final class TestMigrationState extends ExpandableStringEnum { + /** Static value None for TestMigrationState. */ + public static final TestMigrationState NONE = fromString("None"); + + /** Static value TestMigrationInProgress for TestMigrationState. */ + public static final TestMigrationState TEST_MIGRATION_IN_PROGRESS = fromString("TestMigrationInProgress"); + + /** Static value TestMigrationSucceeded for TestMigrationState. */ + public static final TestMigrationState TEST_MIGRATION_SUCCEEDED = fromString("TestMigrationSucceeded"); + + /** Static value TestMigrationFailed for TestMigrationState. */ + public static final TestMigrationState TEST_MIGRATION_FAILED = fromString("TestMigrationFailed"); + + /** Static value TestMigrationCleanupInProgress for TestMigrationState. */ + public static final TestMigrationState TEST_MIGRATION_CLEANUP_IN_PROGRESS = fromString("TestMigrationCleanupInProgress"); + + /** + * Creates or finds a TestMigrationState from its string representation. + * @param name a name to look for + * @return the corresponding TestMigrationState + */ + @JsonCreator + public static TestMigrationState fromString(String name) { + return fromString(name, TestMigrationState.class); + } + + /** + * @return known TestMigrationState values + */ + public static Collection values() { + return values(TestMigrationState.class); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInput.java new file mode 100644 index 0000000000000..34b3ad32147ad --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover. + */ +public class UnplannedFailoverInput { + /** + * Planned failover input properties. + */ + @JsonProperty(value = "properties") + private UnplannedFailoverInputProperties properties; + + /** + * Get planned failover input properties. + * + * @return the properties value + */ + public UnplannedFailoverInputProperties properties() { + return this.properties; + } + + /** + * Set planned failover input properties. + * + * @param properties the properties value to set + * @return the UnplannedFailoverInput object itself. + */ + public UnplannedFailoverInput withProperties(UnplannedFailoverInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInputProperties.java new file mode 100644 index 0000000000000..083297936c6fe --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UnplannedFailoverInputProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input definition for planned failover input properties. + */ +public class UnplannedFailoverInputProperties { + /** + * Failover direction. + */ + @JsonProperty(value = "failoverDirection") + private String failoverDirection; + + /** + * Source site operations status. + */ + @JsonProperty(value = "sourceSiteOperations") + private String sourceSiteOperations; + + /** + * Provider specific settings. + */ + @JsonProperty(value = "providerSpecificDetails") + private ProviderSpecificFailoverInput providerSpecificDetails; + + /** + * Get failover direction. + * + * @return the failoverDirection value + */ + public String failoverDirection() { + return this.failoverDirection; + } + + /** + * Set failover direction. + * + * @param failoverDirection the failoverDirection value to set + * @return the UnplannedFailoverInputProperties object itself. + */ + public UnplannedFailoverInputProperties withFailoverDirection(String failoverDirection) { + this.failoverDirection = failoverDirection; + return this; + } + + /** + * Get source site operations status. + * + * @return the sourceSiteOperations value + */ + public String sourceSiteOperations() { + return this.sourceSiteOperations; + } + + /** + * Set source site operations status. + * + * @param sourceSiteOperations the sourceSiteOperations value to set + * @return the UnplannedFailoverInputProperties object itself. + */ + public UnplannedFailoverInputProperties withSourceSiteOperations(String sourceSiteOperations) { + this.sourceSiteOperations = sourceSiteOperations; + return this; + } + + /** + * Get provider specific settings. + * + * @return the providerSpecificDetails value + */ + public ProviderSpecificFailoverInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set provider specific settings. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the UnplannedFailoverInputProperties object itself. + */ + public UnplannedFailoverInputProperties withProviderSpecificDetails(ProviderSpecificFailoverInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInput.java new file mode 100644 index 0000000000000..cdfa467fbc02e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update migration item input. + */ +public class UpdateMigrationItemInput { + /** + * Update migration item input properties. + */ + @JsonProperty(value = "properties") + private UpdateMigrationItemInputProperties properties; + + /** + * Get update migration item input properties. + * + * @return the properties value + */ + public UpdateMigrationItemInputProperties properties() { + return this.properties; + } + + /** + * Set update migration item input properties. + * + * @param properties the properties value to set + * @return the UpdateMigrationItemInput object itself. + */ + public UpdateMigrationItemInput withProperties(UpdateMigrationItemInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInputProperties.java new file mode 100644 index 0000000000000..80ae4968b01da --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update migration item input properties. + */ +public class UpdateMigrationItemInputProperties { + /** + * The provider specific input to update migration item. + */ + @JsonProperty(value = "providerSpecificDetails", required = true) + private UpdateMigrationItemProviderSpecificInput providerSpecificDetails; + + /** + * Get the provider specific input to update migration item. + * + * @return the providerSpecificDetails value + */ + public UpdateMigrationItemProviderSpecificInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific input to update migration item. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the UpdateMigrationItemInputProperties object itself. + */ + public UpdateMigrationItemInputProperties withProviderSpecificDetails(UpdateMigrationItemProviderSpecificInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemProviderSpecificInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemProviderSpecificInput.java new file mode 100644 index 0000000000000..004d411271c1a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMigrationItemProviderSpecificInput.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Update migration item provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("UpdateMigrationItemProviderSpecificInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "VMwareCbt", value = VMwareCbtUpdateMigrationItemInput.class) +}) +public class UpdateMigrationItemProviderSpecificInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequest.java new file mode 100644 index 0000000000000..4f28e40563236 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Request to update the mobility service on a protected item. + */ +public class UpdateMobilityServiceRequest { + /** + * The properties of the update mobility service request. + */ + @JsonProperty(value = "properties") + private UpdateMobilityServiceRequestProperties properties; + + /** + * Get the properties of the update mobility service request. + * + * @return the properties value + */ + public UpdateMobilityServiceRequestProperties properties() { + return this.properties; + } + + /** + * Set the properties of the update mobility service request. + * + * @param properties the properties value to set + * @return the UpdateMobilityServiceRequest object itself. + */ + public UpdateMobilityServiceRequest withProperties(UpdateMobilityServiceRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequestProperties.java new file mode 100644 index 0000000000000..651b56b208169 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateMobilityServiceRequestProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of an update mobility service request. + */ +public class UpdateMobilityServiceRequestProperties { + /** + * The CS run as account Id. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * Get the CS run as account Id. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS run as account Id. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the UpdateMobilityServiceRequestProperties object itself. + */ + public UpdateMobilityServiceRequestProperties withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInput.java new file mode 100644 index 0000000000000..b902340f7a35b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update network mapping input. + */ +public class UpdateNetworkMappingInput { + /** + * The input properties needed to update network mapping. + */ + @JsonProperty(value = "properties") + private UpdateNetworkMappingInputProperties properties; + + /** + * Get the input properties needed to update network mapping. + * + * @return the properties value + */ + public UpdateNetworkMappingInputProperties properties() { + return this.properties; + } + + /** + * Set the input properties needed to update network mapping. + * + * @param properties the properties value to set + * @return the UpdateNetworkMappingInput object itself. + */ + public UpdateNetworkMappingInput withProperties(UpdateNetworkMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInputProperties.java new file mode 100644 index 0000000000000..609be0c965500 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateNetworkMappingInputProperties.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Common input details for network mapping operation. + */ +public class UpdateNetworkMappingInputProperties { + /** + * Recovery fabric name. + */ + @JsonProperty(value = "recoveryFabricName") + private String recoveryFabricName; + + /** + * Recovery network Id. + */ + @JsonProperty(value = "recoveryNetworkId") + private String recoveryNetworkId; + + /** + * Fabrics specific input network Id. + */ + @JsonProperty(value = "fabricSpecificDetails") + private FabricSpecificUpdateNetworkMappingInput fabricSpecificDetails; + + /** + * Get recovery fabric name. + * + * @return the recoveryFabricName value + */ + public String recoveryFabricName() { + return this.recoveryFabricName; + } + + /** + * Set recovery fabric name. + * + * @param recoveryFabricName the recoveryFabricName value to set + * @return the UpdateNetworkMappingInputProperties object itself. + */ + public UpdateNetworkMappingInputProperties withRecoveryFabricName(String recoveryFabricName) { + this.recoveryFabricName = recoveryFabricName; + return this; + } + + /** + * Get recovery network Id. + * + * @return the recoveryNetworkId value + */ + public String recoveryNetworkId() { + return this.recoveryNetworkId; + } + + /** + * Set recovery network Id. + * + * @param recoveryNetworkId the recoveryNetworkId value to set + * @return the UpdateNetworkMappingInputProperties object itself. + */ + public UpdateNetworkMappingInputProperties withRecoveryNetworkId(String recoveryNetworkId) { + this.recoveryNetworkId = recoveryNetworkId; + return this; + } + + /** + * Get fabrics specific input network Id. + * + * @return the fabricSpecificDetails value + */ + public FabricSpecificUpdateNetworkMappingInput fabricSpecificDetails() { + return this.fabricSpecificDetails; + } + + /** + * Set fabrics specific input network Id. + * + * @param fabricSpecificDetails the fabricSpecificDetails value to set + * @return the UpdateNetworkMappingInputProperties object itself. + */ + public UpdateNetworkMappingInputProperties withFabricSpecificDetails(FabricSpecificUpdateNetworkMappingInput fabricSpecificDetails) { + this.fabricSpecificDetails = fabricSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInput.java new file mode 100644 index 0000000000000..bce67c17ceb6b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update policy input. + */ +public class UpdatePolicyInput { + /** + * The ReplicationProviderSettings. + */ + @JsonProperty(value = "properties") + private UpdatePolicyInputProperties properties; + + /** + * Get the ReplicationProviderSettings. + * + * @return the properties value + */ + public UpdatePolicyInputProperties properties() { + return this.properties; + } + + /** + * Set the ReplicationProviderSettings. + * + * @param properties the properties value to set + * @return the UpdatePolicyInput object itself. + */ + public UpdatePolicyInput withProperties(UpdatePolicyInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInputProperties.java new file mode 100644 index 0000000000000..8877d402943aa --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdatePolicyInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Policy update properties. + */ +public class UpdatePolicyInputProperties { + /** + * The ReplicationProviderSettings. + */ + @JsonProperty(value = "replicationProviderSettings") + private PolicyProviderSpecificInput replicationProviderSettings; + + /** + * Get the ReplicationProviderSettings. + * + * @return the replicationProviderSettings value + */ + public PolicyProviderSpecificInput replicationProviderSettings() { + return this.replicationProviderSettings; + } + + /** + * Set the ReplicationProviderSettings. + * + * @param replicationProviderSettings the replicationProviderSettings value to set + * @return the UpdatePolicyInputProperties object itself. + */ + public UpdatePolicyInputProperties withReplicationProviderSettings(PolicyProviderSpecificInput replicationProviderSettings) { + this.replicationProviderSettings = replicationProviderSettings; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInput.java new file mode 100644 index 0000000000000..095ff6cff91e3 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Container pairing update input. + */ +public class UpdateProtectionContainerMappingInput { + /** + * Update protection container mapping input properties. + */ + @JsonProperty(value = "properties") + private UpdateProtectionContainerMappingInputProperties properties; + + /** + * Get update protection container mapping input properties. + * + * @return the properties value + */ + public UpdateProtectionContainerMappingInputProperties properties() { + return this.properties; + } + + /** + * Set update protection container mapping input properties. + * + * @param properties the properties value to set + * @return the UpdateProtectionContainerMappingInput object itself. + */ + public UpdateProtectionContainerMappingInput withProperties(UpdateProtectionContainerMappingInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInputProperties.java new file mode 100644 index 0000000000000..96cedcb25629c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateProtectionContainerMappingInputProperties.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Container pairing update input. + */ +public class UpdateProtectionContainerMappingInputProperties { + /** + * Provider specific input for updating protection container mapping. + */ + @JsonProperty(value = "providerSpecificInput") + private ReplicationProviderSpecificUpdateContainerMappingInput providerSpecificInput; + + /** + * Get provider specific input for updating protection container mapping. + * + * @return the providerSpecificInput value + */ + public ReplicationProviderSpecificUpdateContainerMappingInput providerSpecificInput() { + return this.providerSpecificInput; + } + + /** + * Set provider specific input for updating protection container mapping. + * + * @param providerSpecificInput the providerSpecificInput value to set + * @return the UpdateProtectionContainerMappingInputProperties object itself. + */ + public UpdateProtectionContainerMappingInputProperties withProviderSpecificInput(ReplicationProviderSpecificUpdateContainerMappingInput providerSpecificInput) { + this.providerSpecificInput = providerSpecificInput; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInput.java new file mode 100644 index 0000000000000..c53652bfd1648 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update recovery plan input class. + */ +public class UpdateRecoveryPlanInput { + /** + * Recovery plan update properties. + */ + @JsonProperty(value = "properties") + private UpdateRecoveryPlanInputProperties properties; + + /** + * Get recovery plan update properties. + * + * @return the properties value + */ + public UpdateRecoveryPlanInputProperties properties() { + return this.properties; + } + + /** + * Set recovery plan update properties. + * + * @param properties the properties value to set + * @return the UpdateRecoveryPlanInput object itself. + */ + public UpdateRecoveryPlanInput withProperties(UpdateRecoveryPlanInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInputProperties.java new file mode 100644 index 0000000000000..588eac2b191fa --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateRecoveryPlanInputProperties.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Recovery plan update properties. + */ +public class UpdateRecoveryPlanInputProperties { + /** + * The recovery plan groups. + */ + @JsonProperty(value = "groups") + private List groups; + + /** + * Get the recovery plan groups. + * + * @return the groups value + */ + public List groups() { + return this.groups; + } + + /** + * Set the recovery plan groups. + * + * @param groups the groups value to set + * @return the UpdateRecoveryPlanInputProperties object itself. + */ + public UpdateRecoveryPlanInputProperties withGroups(List groups) { + this.groups = groups; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInput.java new file mode 100644 index 0000000000000..37987e917a104 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInput.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update replication protected item input. + */ +public class UpdateReplicationProtectedItemInput { + /** + * Update replication protected item properties. + */ + @JsonProperty(value = "properties") + private UpdateReplicationProtectedItemInputProperties properties; + + /** + * Get update replication protected item properties. + * + * @return the properties value + */ + public UpdateReplicationProtectedItemInputProperties properties() { + return this.properties; + } + + /** + * Set update replication protected item properties. + * + * @param properties the properties value to set + * @return the UpdateReplicationProtectedItemInput object itself. + */ + public UpdateReplicationProtectedItemInput withProperties(UpdateReplicationProtectedItemInputProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInputProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInputProperties.java new file mode 100644 index 0000000000000..95ecbb8c876b8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemInputProperties.java @@ -0,0 +1,255 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Update protected item input properties. + */ +public class UpdateReplicationProtectedItemInputProperties { + /** + * Target azure VM name given by the user. + */ + @JsonProperty(value = "recoveryAzureVMName") + private String recoveryAzureVMName; + + /** + * Target Azure Vm size. + */ + @JsonProperty(value = "recoveryAzureVMSize") + private String recoveryAzureVMSize; + + /** + * Target Azure Network Id. + */ + @JsonProperty(value = "selectedRecoveryAzureNetworkId") + private String selectedRecoveryAzureNetworkId; + + /** + * The selected source nic Id which will be used as the primary nic during + * failover. + */ + @JsonProperty(value = "selectedSourceNicId") + private String selectedSourceNicId; + + /** + * The selected option to enable RDP\SSH on target vm after failover. + * String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + */ + @JsonProperty(value = "enableRdpOnTargetOption") + private String enableRdpOnTargetOption; + + /** + * The list of vm nic details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * License type. Possible values include: 'NotSpecified', 'NoLicenseType', + * 'WindowsServer'. + */ + @JsonProperty(value = "licenseType") + private LicenseType licenseType; + + /** + * The target availability set id. + */ + @JsonProperty(value = "recoveryAvailabilitySetId") + private String recoveryAvailabilitySetId; + + /** + * The provider specific input to update replication protected item. + */ + @JsonProperty(value = "providerSpecificDetails") + private UpdateReplicationProtectedItemProviderInput providerSpecificDetails; + + /** + * Get target azure VM name given by the user. + * + * @return the recoveryAzureVMName value + */ + public String recoveryAzureVMName() { + return this.recoveryAzureVMName; + } + + /** + * Set target azure VM name given by the user. + * + * @param recoveryAzureVMName the recoveryAzureVMName value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withRecoveryAzureVMName(String recoveryAzureVMName) { + this.recoveryAzureVMName = recoveryAzureVMName; + return this; + } + + /** + * Get target Azure Vm size. + * + * @return the recoveryAzureVMSize value + */ + public String recoveryAzureVMSize() { + return this.recoveryAzureVMSize; + } + + /** + * Set target Azure Vm size. + * + * @param recoveryAzureVMSize the recoveryAzureVMSize value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withRecoveryAzureVMSize(String recoveryAzureVMSize) { + this.recoveryAzureVMSize = recoveryAzureVMSize; + return this; + } + + /** + * Get target Azure Network Id. + * + * @return the selectedRecoveryAzureNetworkId value + */ + public String selectedRecoveryAzureNetworkId() { + return this.selectedRecoveryAzureNetworkId; + } + + /** + * Set target Azure Network Id. + * + * @param selectedRecoveryAzureNetworkId the selectedRecoveryAzureNetworkId value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withSelectedRecoveryAzureNetworkId(String selectedRecoveryAzureNetworkId) { + this.selectedRecoveryAzureNetworkId = selectedRecoveryAzureNetworkId; + return this; + } + + /** + * Get the selected source nic Id which will be used as the primary nic during failover. + * + * @return the selectedSourceNicId value + */ + public String selectedSourceNicId() { + return this.selectedSourceNicId; + } + + /** + * Set the selected source nic Id which will be used as the primary nic during failover. + * + * @param selectedSourceNicId the selectedSourceNicId value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withSelectedSourceNicId(String selectedSourceNicId) { + this.selectedSourceNicId = selectedSourceNicId; + return this; + } + + /** + * Get the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @return the enableRdpOnTargetOption value + */ + public String enableRdpOnTargetOption() { + return this.enableRdpOnTargetOption; + } + + /** + * Set the selected option to enable RDP\SSH on target vm after failover. String value of {SrsDataContract.EnableRDPOnTargetOption} enum. + * + * @param enableRdpOnTargetOption the enableRdpOnTargetOption value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withEnableRdpOnTargetOption(String enableRdpOnTargetOption) { + this.enableRdpOnTargetOption = enableRdpOnTargetOption; + return this; + } + + /** + * Get the list of vm nic details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the list of vm nic details. + * + * @param vmNics the vmNics value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @return the licenseType value + */ + public LicenseType licenseType() { + return this.licenseType; + } + + /** + * Set license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @param licenseType the licenseType value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + return this; + } + + /** + * Get the target availability set id. + * + * @return the recoveryAvailabilitySetId value + */ + public String recoveryAvailabilitySetId() { + return this.recoveryAvailabilitySetId; + } + + /** + * Set the target availability set id. + * + * @param recoveryAvailabilitySetId the recoveryAvailabilitySetId value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withRecoveryAvailabilitySetId(String recoveryAvailabilitySetId) { + this.recoveryAvailabilitySetId = recoveryAvailabilitySetId; + return this; + } + + /** + * Get the provider specific input to update replication protected item. + * + * @return the providerSpecificDetails value + */ + public UpdateReplicationProtectedItemProviderInput providerSpecificDetails() { + return this.providerSpecificDetails; + } + + /** + * Set the provider specific input to update replication protected item. + * + * @param providerSpecificDetails the providerSpecificDetails value to set + * @return the UpdateReplicationProtectedItemInputProperties object itself. + */ + public UpdateReplicationProtectedItemInputProperties withProviderSpecificDetails(UpdateReplicationProtectedItemProviderInput providerSpecificDetails) { + this.providerSpecificDetails = providerSpecificDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemProviderInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemProviderInput.java new file mode 100644 index 0000000000000..57fa2d093ec95 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateReplicationProtectedItemProviderInput.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; +import com.fasterxml.jackson.annotation.JsonSubTypes; + +/** + * Update replication protected item provider specific input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("UpdateReplicationProtectedItemProviderInput") +@JsonSubTypes({ + @JsonSubTypes.Type(name = "A2A", value = A2AUpdateReplicationProtectedItemInput.class), + @JsonSubTypes.Type(name = "HyperVReplicaAzure", value = HyperVReplicaAzureUpdateReplicationProtectedItemInput.class), + @JsonSubTypes.Type(name = "InMageAzureV2", value = InMageAzureV2UpdateReplicationProtectedItemInput.class) +}) +public class UpdateReplicationProtectedItemProviderInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequest.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequest.java new file mode 100644 index 0000000000000..a37b8aaba7bd2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequest.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Input required to update vCenter. + */ +public class UpdateVCenterRequest { + /** + * The update VCenter Request Properties. + */ + @JsonProperty(value = "properties") + private UpdateVCenterRequestProperties properties; + + /** + * Get the update VCenter Request Properties. + * + * @return the properties value + */ + public UpdateVCenterRequestProperties properties() { + return this.properties; + } + + /** + * Set the update VCenter Request Properties. + * + * @param properties the properties value to set + * @return the UpdateVCenterRequest object itself. + */ + public UpdateVCenterRequest withProperties(UpdateVCenterRequestProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequestProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequestProperties.java new file mode 100644 index 0000000000000..85863380c06f7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/UpdateVCenterRequestProperties.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * The properties of an update vCenter request. + */ +public class UpdateVCenterRequestProperties { + /** + * The friendly name of the vCenter. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * The IP address of the vCenter to be discovered. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The process server Id from where the update can be orchestrated. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The port number for discovery. + */ + @JsonProperty(value = "port") + private String port; + + /** + * The CS account Id which has privileges to update the vCenter. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * Get the friendly name of the vCenter. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set the friendly name of the vCenter. + * + * @param friendlyName the friendlyName value to set + * @return the UpdateVCenterRequestProperties object itself. + */ + public UpdateVCenterRequestProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get the IP address of the vCenter to be discovered. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the vCenter to be discovered. + * + * @param ipAddress the ipAddress value to set + * @return the UpdateVCenterRequestProperties object itself. + */ + public UpdateVCenterRequestProperties withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the process server Id from where the update can be orchestrated. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the process server Id from where the update can be orchestrated. + * + * @param processServerId the processServerId value to set + * @return the UpdateVCenterRequestProperties object itself. + */ + public UpdateVCenterRequestProperties withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the port number for discovery. + * + * @return the port value + */ + public String port() { + return this.port; + } + + /** + * Set the port number for discovery. + * + * @param port the port value to set + * @return the UpdateVCenterRequestProperties object itself. + */ + public UpdateVCenterRequestProperties withPort(String port) { + this.port = port; + return this; + } + + /** + * Get the CS account Id which has privileges to update the vCenter. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the CS account Id which has privileges to update the vCenter. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the UpdateVCenterRequestProperties object itself. + */ + public UpdateVCenterRequestProperties withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenter.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenter.java new file mode 100644 index 0000000000000..2adeec15dd74d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenter.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.VCenterInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; + +/** + * Type representing VCenter. + */ +public interface VCenter extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + VCenterProperties properties(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the VCenter definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithReplicationFabric, DefinitionStages.WithProperties, DefinitionStages.WithCreate { + } + + /** + * Grouping of VCenter definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a VCenter definition. + */ + interface Blank extends WithReplicationFabric { + } + + /** + * The stage of the vcenter definition allowing to specify ReplicationFabric. + */ + interface WithReplicationFabric { + /** + * Specifies fabricName. + * @param fabricName Fabric name + * @return the next definition stage + */ + WithProperties withExistingReplicationFabric(String fabricName); + } + + /** + * The stage of the vcenter definition allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The properties of an add vCenter request + * @return the next definition stage + */ + WithCreate withProperties(AddVCenterRequestProperties properties); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable { + } + } + /** + * The template for a VCenter update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithProperties { + } + + /** + * Grouping of VCenter update stages. + */ + interface UpdateStages { + /** + * The stage of the vcenter update allowing to specify Properties. + */ + interface WithProperties { + /** + * Specifies properties. + * @param properties The update VCenter Request Properties + * @return the next update stage + */ + Update withProperties(UpdateVCenterRequestProperties properties); + } + + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenterProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenterProperties.java new file mode 100644 index 0000000000000..2364244f5781b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VCenterProperties.java @@ -0,0 +1,305 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * vCenter properties. + */ +public class VCenterProperties { + /** + * Friendly name of the vCenter. + */ + @JsonProperty(value = "friendlyName") + private String friendlyName; + + /** + * VCenter internal ID. + */ + @JsonProperty(value = "internalId") + private String internalId; + + /** + * The time when the last heartbeat was received by vCenter. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * The VCenter discovery status. + */ + @JsonProperty(value = "discoveryStatus") + private String discoveryStatus; + + /** + * The process server Id. + */ + @JsonProperty(value = "processServerId") + private String processServerId; + + /** + * The IP address of the vCenter. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The infrastructure Id of vCenter. + */ + @JsonProperty(value = "infrastructureId") + private String infrastructureId; + + /** + * The port number for discovery. + */ + @JsonProperty(value = "port") + private String port; + + /** + * The account Id which has privileges to discover the vCenter. + */ + @JsonProperty(value = "runAsAccountId") + private String runAsAccountId; + + /** + * The ARM resource name of the fabric containing this VCenter. + */ + @JsonProperty(value = "fabricArmResourceName") + private String fabricArmResourceName; + + /** + * The health errors for this VCenter. + */ + @JsonProperty(value = "healthErrors") + private List healthErrors; + + /** + * Get friendly name of the vCenter. + * + * @return the friendlyName value + */ + public String friendlyName() { + return this.friendlyName; + } + + /** + * Set friendly name of the vCenter. + * + * @param friendlyName the friendlyName value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + return this; + } + + /** + * Get vCenter internal ID. + * + * @return the internalId value + */ + public String internalId() { + return this.internalId; + } + + /** + * Set vCenter internal ID. + * + * @param internalId the internalId value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withInternalId(String internalId) { + this.internalId = internalId; + return this; + } + + /** + * Get the time when the last heartbeat was received by vCenter. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the time when the last heartbeat was received by vCenter. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get the VCenter discovery status. + * + * @return the discoveryStatus value + */ + public String discoveryStatus() { + return this.discoveryStatus; + } + + /** + * Set the VCenter discovery status. + * + * @param discoveryStatus the discoveryStatus value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withDiscoveryStatus(String discoveryStatus) { + this.discoveryStatus = discoveryStatus; + return this; + } + + /** + * Get the process server Id. + * + * @return the processServerId value + */ + public String processServerId() { + return this.processServerId; + } + + /** + * Set the process server Id. + * + * @param processServerId the processServerId value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withProcessServerId(String processServerId) { + this.processServerId = processServerId; + return this; + } + + /** + * Get the IP address of the vCenter. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address of the vCenter. + * + * @param ipAddress the ipAddress value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the infrastructure Id of vCenter. + * + * @return the infrastructureId value + */ + public String infrastructureId() { + return this.infrastructureId; + } + + /** + * Set the infrastructure Id of vCenter. + * + * @param infrastructureId the infrastructureId value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withInfrastructureId(String infrastructureId) { + this.infrastructureId = infrastructureId; + return this; + } + + /** + * Get the port number for discovery. + * + * @return the port value + */ + public String port() { + return this.port; + } + + /** + * Set the port number for discovery. + * + * @param port the port value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withPort(String port) { + this.port = port; + return this; + } + + /** + * Get the account Id which has privileges to discover the vCenter. + * + * @return the runAsAccountId value + */ + public String runAsAccountId() { + return this.runAsAccountId; + } + + /** + * Set the account Id which has privileges to discover the vCenter. + * + * @param runAsAccountId the runAsAccountId value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withRunAsAccountId(String runAsAccountId) { + this.runAsAccountId = runAsAccountId; + return this; + } + + /** + * Get the ARM resource name of the fabric containing this VCenter. + * + * @return the fabricArmResourceName value + */ + public String fabricArmResourceName() { + return this.fabricArmResourceName; + } + + /** + * Set the ARM resource name of the fabric containing this VCenter. + * + * @param fabricArmResourceName the fabricArmResourceName value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withFabricArmResourceName(String fabricArmResourceName) { + this.fabricArmResourceName = fabricArmResourceName; + return this; + } + + /** + * Get the health errors for this VCenter. + * + * @return the healthErrors value + */ + public List healthErrors() { + return this.healthErrors; + } + + /** + * Set the health errors for this VCenter. + * + * @param healthErrors the healthErrors value to set + * @return the VCenterProperties object itself. + */ + public VCenterProperties withHealthErrors(List healthErrors) { + this.healthErrors = healthErrors; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicDetails.java new file mode 100644 index 0000000000000..8e6fbb4fc600b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicDetails.java @@ -0,0 +1,355 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Hyper V VM network details. + */ +public class VMNicDetails { + /** + * The nic Id. + */ + @JsonProperty(value = "nicId") + private String nicId; + + /** + * The replica nic Id. + */ + @JsonProperty(value = "replicaNicId") + private String replicaNicId; + + /** + * The source nic ARM Id. + */ + @JsonProperty(value = "sourceNicArmId") + private String sourceNicArmId; + + /** + * VM subnet name. + */ + @JsonProperty(value = "vMSubnetName") + private String vMSubnetName; + + /** + * VM network name. + */ + @JsonProperty(value = "vMNetworkName") + private String vMNetworkName; + + /** + * Recovery VM network Id. + */ + @JsonProperty(value = "recoveryVMNetworkId") + private String recoveryVMNetworkId; + + /** + * Recovery VM subnet name. + */ + @JsonProperty(value = "recoveryVMSubnetName") + private String recoveryVMSubnetName; + + /** + * Ip address type. + */ + @JsonProperty(value = "ipAddressType") + private String ipAddressType; + + /** + * Primary nic static IP address. + */ + @JsonProperty(value = "primaryNicStaticIPAddress") + private String primaryNicStaticIPAddress; + + /** + * Replica nic static IP address. + */ + @JsonProperty(value = "replicaNicStaticIPAddress") + private String replicaNicStaticIPAddress; + + /** + * Selection type for failover. + */ + @JsonProperty(value = "selectionType") + private String selectionType; + + /** + * IP allocation type for recovery VM. + */ + @JsonProperty(value = "recoveryNicIpAddressType") + private String recoveryNicIpAddressType; + + /** + * A value indicating whether the NIC has accelerated networking enabled. + */ + @JsonProperty(value = "enableAcceleratedNetworkingOnRecovery") + private Boolean enableAcceleratedNetworkingOnRecovery; + + /** + * Get the nic Id. + * + * @return the nicId value + */ + public String nicId() { + return this.nicId; + } + + /** + * Set the nic Id. + * + * @param nicId the nicId value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withNicId(String nicId) { + this.nicId = nicId; + return this; + } + + /** + * Get the replica nic Id. + * + * @return the replicaNicId value + */ + public String replicaNicId() { + return this.replicaNicId; + } + + /** + * Set the replica nic Id. + * + * @param replicaNicId the replicaNicId value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withReplicaNicId(String replicaNicId) { + this.replicaNicId = replicaNicId; + return this; + } + + /** + * Get the source nic ARM Id. + * + * @return the sourceNicArmId value + */ + public String sourceNicArmId() { + return this.sourceNicArmId; + } + + /** + * Set the source nic ARM Id. + * + * @param sourceNicArmId the sourceNicArmId value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withSourceNicArmId(String sourceNicArmId) { + this.sourceNicArmId = sourceNicArmId; + return this; + } + + /** + * Get vM subnet name. + * + * @return the vMSubnetName value + */ + public String vMSubnetName() { + return this.vMSubnetName; + } + + /** + * Set vM subnet name. + * + * @param vMSubnetName the vMSubnetName value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withVMSubnetName(String vMSubnetName) { + this.vMSubnetName = vMSubnetName; + return this; + } + + /** + * Get vM network name. + * + * @return the vMNetworkName value + */ + public String vMNetworkName() { + return this.vMNetworkName; + } + + /** + * Set vM network name. + * + * @param vMNetworkName the vMNetworkName value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withVMNetworkName(String vMNetworkName) { + this.vMNetworkName = vMNetworkName; + return this; + } + + /** + * Get recovery VM network Id. + * + * @return the recoveryVMNetworkId value + */ + public String recoveryVMNetworkId() { + return this.recoveryVMNetworkId; + } + + /** + * Set recovery VM network Id. + * + * @param recoveryVMNetworkId the recoveryVMNetworkId value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withRecoveryVMNetworkId(String recoveryVMNetworkId) { + this.recoveryVMNetworkId = recoveryVMNetworkId; + return this; + } + + /** + * Get recovery VM subnet name. + * + * @return the recoveryVMSubnetName value + */ + public String recoveryVMSubnetName() { + return this.recoveryVMSubnetName; + } + + /** + * Set recovery VM subnet name. + * + * @param recoveryVMSubnetName the recoveryVMSubnetName value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withRecoveryVMSubnetName(String recoveryVMSubnetName) { + this.recoveryVMSubnetName = recoveryVMSubnetName; + return this; + } + + /** + * Get ip address type. + * + * @return the ipAddressType value + */ + public String ipAddressType() { + return this.ipAddressType; + } + + /** + * Set ip address type. + * + * @param ipAddressType the ipAddressType value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withIpAddressType(String ipAddressType) { + this.ipAddressType = ipAddressType; + return this; + } + + /** + * Get primary nic static IP address. + * + * @return the primaryNicStaticIPAddress value + */ + public String primaryNicStaticIPAddress() { + return this.primaryNicStaticIPAddress; + } + + /** + * Set primary nic static IP address. + * + * @param primaryNicStaticIPAddress the primaryNicStaticIPAddress value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withPrimaryNicStaticIPAddress(String primaryNicStaticIPAddress) { + this.primaryNicStaticIPAddress = primaryNicStaticIPAddress; + return this; + } + + /** + * Get replica nic static IP address. + * + * @return the replicaNicStaticIPAddress value + */ + public String replicaNicStaticIPAddress() { + return this.replicaNicStaticIPAddress; + } + + /** + * Set replica nic static IP address. + * + * @param replicaNicStaticIPAddress the replicaNicStaticIPAddress value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withReplicaNicStaticIPAddress(String replicaNicStaticIPAddress) { + this.replicaNicStaticIPAddress = replicaNicStaticIPAddress; + return this; + } + + /** + * Get selection type for failover. + * + * @return the selectionType value + */ + public String selectionType() { + return this.selectionType; + } + + /** + * Set selection type for failover. + * + * @param selectionType the selectionType value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withSelectionType(String selectionType) { + this.selectionType = selectionType; + return this; + } + + /** + * Get iP allocation type for recovery VM. + * + * @return the recoveryNicIpAddressType value + */ + public String recoveryNicIpAddressType() { + return this.recoveryNicIpAddressType; + } + + /** + * Set iP allocation type for recovery VM. + * + * @param recoveryNicIpAddressType the recoveryNicIpAddressType value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withRecoveryNicIpAddressType(String recoveryNicIpAddressType) { + this.recoveryNicIpAddressType = recoveryNicIpAddressType; + return this; + } + + /** + * Get a value indicating whether the NIC has accelerated networking enabled. + * + * @return the enableAcceleratedNetworkingOnRecovery value + */ + public Boolean enableAcceleratedNetworkingOnRecovery() { + return this.enableAcceleratedNetworkingOnRecovery; + } + + /** + * Set a value indicating whether the NIC has accelerated networking enabled. + * + * @param enableAcceleratedNetworkingOnRecovery the enableAcceleratedNetworkingOnRecovery value to set + * @return the VMNicDetails object itself. + */ + public VMNicDetails withEnableAcceleratedNetworkingOnRecovery(Boolean enableAcceleratedNetworkingOnRecovery) { + this.enableAcceleratedNetworkingOnRecovery = enableAcceleratedNetworkingOnRecovery; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicInputDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicInputDetails.java new file mode 100644 index 0000000000000..73c9013db1108 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMNicInputDetails.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Hyper V VM network input details. + */ +public class VMNicInputDetails { + /** + * The nic Id. + */ + @JsonProperty(value = "nicId") + private String nicId; + + /** + * Recovery VM subnet name. + */ + @JsonProperty(value = "recoveryVMSubnetName") + private String recoveryVMSubnetName; + + /** + * Replica nic static IP address. + */ + @JsonProperty(value = "replicaNicStaticIPAddress") + private String replicaNicStaticIPAddress; + + /** + * Selection type for failover. + */ + @JsonProperty(value = "selectionType") + private String selectionType; + + /** + * Whether the NIC has accelerated networking enabled. + */ + @JsonProperty(value = "enableAcceleratedNetworkingOnRecovery") + private Boolean enableAcceleratedNetworkingOnRecovery; + + /** + * Get the nic Id. + * + * @return the nicId value + */ + public String nicId() { + return this.nicId; + } + + /** + * Set the nic Id. + * + * @param nicId the nicId value to set + * @return the VMNicInputDetails object itself. + */ + public VMNicInputDetails withNicId(String nicId) { + this.nicId = nicId; + return this; + } + + /** + * Get recovery VM subnet name. + * + * @return the recoveryVMSubnetName value + */ + public String recoveryVMSubnetName() { + return this.recoveryVMSubnetName; + } + + /** + * Set recovery VM subnet name. + * + * @param recoveryVMSubnetName the recoveryVMSubnetName value to set + * @return the VMNicInputDetails object itself. + */ + public VMNicInputDetails withRecoveryVMSubnetName(String recoveryVMSubnetName) { + this.recoveryVMSubnetName = recoveryVMSubnetName; + return this; + } + + /** + * Get replica nic static IP address. + * + * @return the replicaNicStaticIPAddress value + */ + public String replicaNicStaticIPAddress() { + return this.replicaNicStaticIPAddress; + } + + /** + * Set replica nic static IP address. + * + * @param replicaNicStaticIPAddress the replicaNicStaticIPAddress value to set + * @return the VMNicInputDetails object itself. + */ + public VMNicInputDetails withReplicaNicStaticIPAddress(String replicaNicStaticIPAddress) { + this.replicaNicStaticIPAddress = replicaNicStaticIPAddress; + return this; + } + + /** + * Get selection type for failover. + * + * @return the selectionType value + */ + public String selectionType() { + return this.selectionType; + } + + /** + * Set selection type for failover. + * + * @param selectionType the selectionType value to set + * @return the VMNicInputDetails object itself. + */ + public VMNicInputDetails withSelectionType(String selectionType) { + this.selectionType = selectionType; + return this; + } + + /** + * Get whether the NIC has accelerated networking enabled. + * + * @return the enableAcceleratedNetworkingOnRecovery value + */ + public Boolean enableAcceleratedNetworkingOnRecovery() { + return this.enableAcceleratedNetworkingOnRecovery; + } + + /** + * Set whether the NIC has accelerated networking enabled. + * + * @param enableAcceleratedNetworkingOnRecovery the enableAcceleratedNetworkingOnRecovery value to set + * @return the VMNicInputDetails object itself. + */ + public VMNicInputDetails withEnableAcceleratedNetworkingOnRecovery(Boolean enableAcceleratedNetworkingOnRecovery) { + this.enableAcceleratedNetworkingOnRecovery = enableAcceleratedNetworkingOnRecovery; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerCreationInput.java new file mode 100644 index 0000000000000..f6268b80bdb5f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerCreationInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt container creation input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("6c7da455-506f-43ff-a16a-8eb101aebb70") +public class VMwareCbtContainerCreationInput extends ReplicationProviderSpecificContainerCreationInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerMappingInput.java new file mode 100644 index 0000000000000..3ad43edf5e570 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtContainerMappingInput.java @@ -0,0 +1,177 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt container mapping input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtContainerMappingInput extends ReplicationProviderSpecificContainerMappingInput { + /** + * The target key vault ARM Id. + */ + @JsonProperty(value = "keyVaultId", required = true) + private String keyVaultId; + + /** + * The target key vault URL. + */ + @JsonProperty(value = "keyVaultUri", required = true) + private String keyVaultUri; + + /** + * The storage account ARM Id. + */ + @JsonProperty(value = "storageAccountId", required = true) + private String storageAccountId; + + /** + * The secret name of the storage account. + */ + @JsonProperty(value = "storageAccountSasSecretName", required = true) + private String storageAccountSasSecretName; + + /** + * The secret name of the service bus connection string. + */ + @JsonProperty(value = "serviceBusConnectionStringSecretName", required = true) + private String serviceBusConnectionStringSecretName; + + /** + * The target location. + */ + @JsonProperty(value = "targetLocation", required = true) + private String targetLocation; + + /** + * Get the target key vault ARM Id. + * + * @return the keyVaultId value + */ + public String keyVaultId() { + return this.keyVaultId; + } + + /** + * Set the target key vault ARM Id. + * + * @param keyVaultId the keyVaultId value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withKeyVaultId(String keyVaultId) { + this.keyVaultId = keyVaultId; + return this; + } + + /** + * Get the target key vault URL. + * + * @return the keyVaultUri value + */ + public String keyVaultUri() { + return this.keyVaultUri; + } + + /** + * Set the target key vault URL. + * + * @param keyVaultUri the keyVaultUri value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withKeyVaultUri(String keyVaultUri) { + this.keyVaultUri = keyVaultUri; + return this; + } + + /** + * Get the storage account ARM Id. + * + * @return the storageAccountId value + */ + public String storageAccountId() { + return this.storageAccountId; + } + + /** + * Set the storage account ARM Id. + * + * @param storageAccountId the storageAccountId value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withStorageAccountId(String storageAccountId) { + this.storageAccountId = storageAccountId; + return this; + } + + /** + * Get the secret name of the storage account. + * + * @return the storageAccountSasSecretName value + */ + public String storageAccountSasSecretName() { + return this.storageAccountSasSecretName; + } + + /** + * Set the secret name of the storage account. + * + * @param storageAccountSasSecretName the storageAccountSasSecretName value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withStorageAccountSasSecretName(String storageAccountSasSecretName) { + this.storageAccountSasSecretName = storageAccountSasSecretName; + return this; + } + + /** + * Get the secret name of the service bus connection string. + * + * @return the serviceBusConnectionStringSecretName value + */ + public String serviceBusConnectionStringSecretName() { + return this.serviceBusConnectionStringSecretName; + } + + /** + * Set the secret name of the service bus connection string. + * + * @param serviceBusConnectionStringSecretName the serviceBusConnectionStringSecretName value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withServiceBusConnectionStringSecretName(String serviceBusConnectionStringSecretName) { + this.serviceBusConnectionStringSecretName = serviceBusConnectionStringSecretName; + return this; + } + + /** + * Get the target location. + * + * @return the targetLocation value + */ + public String targetLocation() { + return this.targetLocation; + } + + /** + * Set the target location. + * + * @param targetLocation the targetLocation value to set + * @return the VMwareCbtContainerMappingInput object itself. + */ + public VMwareCbtContainerMappingInput withTargetLocation(String targetLocation) { + this.targetLocation = targetLocation; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtDiskInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtDiskInput.java new file mode 100644 index 0000000000000..12a0781a08fe8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtDiskInput.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * VMwareCbt disk input. + */ +public class VMwareCbtDiskInput { + /** + * The disk Id. + */ + @JsonProperty(value = "diskId", required = true) + private String diskId; + + /** + * A value indicating whether the disk is the OS disk. + */ + @JsonProperty(value = "isOSDisk", required = true) + private String isOSDisk; + + /** + * The log storage account ARM Id. + */ + @JsonProperty(value = "logStorageAccountId", required = true) + private String logStorageAccountId; + + /** + * The key vault secret name of the log storage account. + */ + @JsonProperty(value = "logStorageAccountSasSecretName", required = true) + private String logStorageAccountSasSecretName; + + /** + * The disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', + * 'StandardSSD_LRS'. + */ + @JsonProperty(value = "diskType") + private DiskAccountType diskType; + + /** + * Get the disk Id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Set the disk Id. + * + * @param diskId the diskId value to set + * @return the VMwareCbtDiskInput object itself. + */ + public VMwareCbtDiskInput withDiskId(String diskId) { + this.diskId = diskId; + return this; + } + + /** + * Get a value indicating whether the disk is the OS disk. + * + * @return the isOSDisk value + */ + public String isOSDisk() { + return this.isOSDisk; + } + + /** + * Set a value indicating whether the disk is the OS disk. + * + * @param isOSDisk the isOSDisk value to set + * @return the VMwareCbtDiskInput object itself. + */ + public VMwareCbtDiskInput withIsOSDisk(String isOSDisk) { + this.isOSDisk = isOSDisk; + return this; + } + + /** + * Get the log storage account ARM Id. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Set the log storage account ARM Id. + * + * @param logStorageAccountId the logStorageAccountId value to set + * @return the VMwareCbtDiskInput object itself. + */ + public VMwareCbtDiskInput withLogStorageAccountId(String logStorageAccountId) { + this.logStorageAccountId = logStorageAccountId; + return this; + } + + /** + * Get the key vault secret name of the log storage account. + * + * @return the logStorageAccountSasSecretName value + */ + public String logStorageAccountSasSecretName() { + return this.logStorageAccountSasSecretName; + } + + /** + * Set the key vault secret name of the log storage account. + * + * @param logStorageAccountSasSecretName the logStorageAccountSasSecretName value to set + * @return the VMwareCbtDiskInput object itself. + */ + public VMwareCbtDiskInput withLogStorageAccountSasSecretName(String logStorageAccountSasSecretName) { + this.logStorageAccountSasSecretName = logStorageAccountSasSecretName; + return this; + } + + /** + * Get the disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', 'StandardSSD_LRS'. + * + * @return the diskType value + */ + public DiskAccountType diskType() { + return this.diskType; + } + + /** + * Set the disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', 'StandardSSD_LRS'. + * + * @param diskType the diskType value to set + * @return the VMwareCbtDiskInput object itself. + */ + public VMwareCbtDiskInput withDiskType(DiskAccountType diskType) { + this.diskType = diskType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtEnableMigrationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtEnableMigrationInput.java new file mode 100644 index 0000000000000..8062e685151f2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtEnableMigrationInput.java @@ -0,0 +1,335 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt specific enable migration input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtEnableMigrationInput extends EnableMigrationProviderSpecificInput { + /** + * The ARM Id of the VM discovered in VMware. + */ + @JsonProperty(value = "vmwareMachineId", required = true) + private String vmwareMachineId; + + /** + * The disks to include list. + */ + @JsonProperty(value = "disksToInclude", required = true) + private List disksToInclude; + + /** + * License type. Possible values include: 'NotSpecified', 'NoLicenseType', + * 'WindowsServer'. + */ + @JsonProperty(value = "licenseType") + private LicenseType licenseType; + + /** + * The data mover RunAs account Id. + */ + @JsonProperty(value = "dataMoverRunAsAccountId", required = true) + private String dataMoverRunAsAccountId; + + /** + * The snapshot RunAs account Id. + */ + @JsonProperty(value = "snapshotRunAsAccountId", required = true) + private String snapshotRunAsAccountId; + + /** + * The target VM name. + */ + @JsonProperty(value = "targetVmName") + private String targetVmName; + + /** + * The target VM size. + */ + @JsonProperty(value = "targetVmSize") + private String targetVmSize; + + /** + * The target resource group ARM Id. + */ + @JsonProperty(value = "targetResourceGroupId", required = true) + private String targetResourceGroupId; + + /** + * The target network ARM Id. + */ + @JsonProperty(value = "targetNetworkId", required = true) + private String targetNetworkId; + + /** + * The target subnet name. + */ + @JsonProperty(value = "targetSubnetName") + private String targetSubnetName; + + /** + * The target availability set ARM Id. + */ + @JsonProperty(value = "targetAvailabilitySetId") + private String targetAvailabilitySetId; + + /** + * The target boot diagnostics storage account ARM Id. + */ + @JsonProperty(value = "targetBootDiagnosticsStorageAccountId") + private String targetBootDiagnosticsStorageAccountId; + + /** + * Get the ARM Id of the VM discovered in VMware. + * + * @return the vmwareMachineId value + */ + public String vmwareMachineId() { + return this.vmwareMachineId; + } + + /** + * Set the ARM Id of the VM discovered in VMware. + * + * @param vmwareMachineId the vmwareMachineId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withVmwareMachineId(String vmwareMachineId) { + this.vmwareMachineId = vmwareMachineId; + return this; + } + + /** + * Get the disks to include list. + * + * @return the disksToInclude value + */ + public List disksToInclude() { + return this.disksToInclude; + } + + /** + * Set the disks to include list. + * + * @param disksToInclude the disksToInclude value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withDisksToInclude(List disksToInclude) { + this.disksToInclude = disksToInclude; + return this; + } + + /** + * Get license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @return the licenseType value + */ + public LicenseType licenseType() { + return this.licenseType; + } + + /** + * Set license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @param licenseType the licenseType value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + return this; + } + + /** + * Get the data mover RunAs account Id. + * + * @return the dataMoverRunAsAccountId value + */ + public String dataMoverRunAsAccountId() { + return this.dataMoverRunAsAccountId; + } + + /** + * Set the data mover RunAs account Id. + * + * @param dataMoverRunAsAccountId the dataMoverRunAsAccountId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withDataMoverRunAsAccountId(String dataMoverRunAsAccountId) { + this.dataMoverRunAsAccountId = dataMoverRunAsAccountId; + return this; + } + + /** + * Get the snapshot RunAs account Id. + * + * @return the snapshotRunAsAccountId value + */ + public String snapshotRunAsAccountId() { + return this.snapshotRunAsAccountId; + } + + /** + * Set the snapshot RunAs account Id. + * + * @param snapshotRunAsAccountId the snapshotRunAsAccountId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withSnapshotRunAsAccountId(String snapshotRunAsAccountId) { + this.snapshotRunAsAccountId = snapshotRunAsAccountId; + return this; + } + + /** + * Get the target VM name. + * + * @return the targetVmName value + */ + public String targetVmName() { + return this.targetVmName; + } + + /** + * Set the target VM name. + * + * @param targetVmName the targetVmName value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetVmName(String targetVmName) { + this.targetVmName = targetVmName; + return this; + } + + /** + * Get the target VM size. + * + * @return the targetVmSize value + */ + public String targetVmSize() { + return this.targetVmSize; + } + + /** + * Set the target VM size. + * + * @param targetVmSize the targetVmSize value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetVmSize(String targetVmSize) { + this.targetVmSize = targetVmSize; + return this; + } + + /** + * Get the target resource group ARM Id. + * + * @return the targetResourceGroupId value + */ + public String targetResourceGroupId() { + return this.targetResourceGroupId; + } + + /** + * Set the target resource group ARM Id. + * + * @param targetResourceGroupId the targetResourceGroupId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetResourceGroupId(String targetResourceGroupId) { + this.targetResourceGroupId = targetResourceGroupId; + return this; + } + + /** + * Get the target network ARM Id. + * + * @return the targetNetworkId value + */ + public String targetNetworkId() { + return this.targetNetworkId; + } + + /** + * Set the target network ARM Id. + * + * @param targetNetworkId the targetNetworkId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetNetworkId(String targetNetworkId) { + this.targetNetworkId = targetNetworkId; + return this; + } + + /** + * Get the target subnet name. + * + * @return the targetSubnetName value + */ + public String targetSubnetName() { + return this.targetSubnetName; + } + + /** + * Set the target subnet name. + * + * @param targetSubnetName the targetSubnetName value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetSubnetName(String targetSubnetName) { + this.targetSubnetName = targetSubnetName; + return this; + } + + /** + * Get the target availability set ARM Id. + * + * @return the targetAvailabilitySetId value + */ + public String targetAvailabilitySetId() { + return this.targetAvailabilitySetId; + } + + /** + * Set the target availability set ARM Id. + * + * @param targetAvailabilitySetId the targetAvailabilitySetId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetAvailabilitySetId(String targetAvailabilitySetId) { + this.targetAvailabilitySetId = targetAvailabilitySetId; + return this; + } + + /** + * Get the target boot diagnostics storage account ARM Id. + * + * @return the targetBootDiagnosticsStorageAccountId value + */ + public String targetBootDiagnosticsStorageAccountId() { + return this.targetBootDiagnosticsStorageAccountId; + } + + /** + * Set the target boot diagnostics storage account ARM Id. + * + * @param targetBootDiagnosticsStorageAccountId the targetBootDiagnosticsStorageAccountId value to set + * @return the VMwareCbtEnableMigrationInput object itself. + */ + public VMwareCbtEnableMigrationInput withTargetBootDiagnosticsStorageAccountId(String targetBootDiagnosticsStorageAccountId) { + this.targetBootDiagnosticsStorageAccountId = targetBootDiagnosticsStorageAccountId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrateInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrateInput.java new file mode 100644 index 0000000000000..22292f77f166c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrateInput.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt specific migrate input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtMigrateInput extends MigrateProviderSpecificInput { + /** + * A value indicating whether VM is to be shutdown. + */ + @JsonProperty(value = "performShutdown", required = true) + private String performShutdown; + + /** + * Get a value indicating whether VM is to be shutdown. + * + * @return the performShutdown value + */ + public String performShutdown() { + return this.performShutdown; + } + + /** + * Set a value indicating whether VM is to be shutdown. + * + * @param performShutdown the performShutdown value to set + * @return the VMwareCbtMigrateInput object itself. + */ + public VMwareCbtMigrateInput withPerformShutdown(String performShutdown) { + this.performShutdown = performShutdown; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrationDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrationDetails.java new file mode 100644 index 0000000000000..49716b052645a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtMigrationDetails.java @@ -0,0 +1,362 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtMigrationDetails extends MigrationProviderSpecificSettings { + /** + * The ARM Id of the VM discovered in VMware. + */ + @JsonProperty(value = "vmwareMachineId", access = JsonProperty.Access.WRITE_ONLY) + private String vmwareMachineId; + + /** + * The type of the OS on the VM. + */ + @JsonProperty(value = "osType", access = JsonProperty.Access.WRITE_ONLY) + private String osType; + + /** + * License Type of the VM to be used. + */ + @JsonProperty(value = "licenseType") + private String licenseType; + + /** + * The data mover RunAs account Id. + */ + @JsonProperty(value = "dataMoverRunAsAccountId", access = JsonProperty.Access.WRITE_ONLY) + private String dataMoverRunAsAccountId; + + /** + * The snapshot RunAs account Id. + */ + @JsonProperty(value = "snapshotRunAsAccountId", access = JsonProperty.Access.WRITE_ONLY) + private String snapshotRunAsAccountId; + + /** + * Target VM name. + */ + @JsonProperty(value = "targetVmName") + private String targetVmName; + + /** + * The target VM size. + */ + @JsonProperty(value = "targetVmSize") + private String targetVmSize; + + /** + * The target location. + */ + @JsonProperty(value = "targetLocation", access = JsonProperty.Access.WRITE_ONLY) + private String targetLocation; + + /** + * The target resource group Id. + */ + @JsonProperty(value = "targetResourceGroupId") + private String targetResourceGroupId; + + /** + * The target availability set Id. + */ + @JsonProperty(value = "targetAvailabilitySetId") + private String targetAvailabilitySetId; + + /** + * The target boot diagnostics storage account ARM Id. + */ + @JsonProperty(value = "targetBootDiagnosticsStorageAccountId") + private String targetBootDiagnosticsStorageAccountId; + + /** + * The list of protected disks. + */ + @JsonProperty(value = "protectedDisks") + private List protectedDisks; + + /** + * The target network Id. + */ + @JsonProperty(value = "targetNetworkId") + private String targetNetworkId; + + /** + * The network details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The recovery point Id to which the VM was migrated. + */ + @JsonProperty(value = "migrationRecoveryPointId", access = JsonProperty.Access.WRITE_ONLY) + private String migrationRecoveryPointId; + + /** + * The last recovery point received time. + */ + @JsonProperty(value = "lastRecoveryPointReceived", access = JsonProperty.Access.WRITE_ONLY) + private DateTime lastRecoveryPointReceived; + + /** + * Get the ARM Id of the VM discovered in VMware. + * + * @return the vmwareMachineId value + */ + public String vmwareMachineId() { + return this.vmwareMachineId; + } + + /** + * Get the type of the OS on the VM. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Get license Type of the VM to be used. + * + * @return the licenseType value + */ + public String licenseType() { + return this.licenseType; + } + + /** + * Set license Type of the VM to be used. + * + * @param licenseType the licenseType value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withLicenseType(String licenseType) { + this.licenseType = licenseType; + return this; + } + + /** + * Get the data mover RunAs account Id. + * + * @return the dataMoverRunAsAccountId value + */ + public String dataMoverRunAsAccountId() { + return this.dataMoverRunAsAccountId; + } + + /** + * Get the snapshot RunAs account Id. + * + * @return the snapshotRunAsAccountId value + */ + public String snapshotRunAsAccountId() { + return this.snapshotRunAsAccountId; + } + + /** + * Get target VM name. + * + * @return the targetVmName value + */ + public String targetVmName() { + return this.targetVmName; + } + + /** + * Set target VM name. + * + * @param targetVmName the targetVmName value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetVmName(String targetVmName) { + this.targetVmName = targetVmName; + return this; + } + + /** + * Get the target VM size. + * + * @return the targetVmSize value + */ + public String targetVmSize() { + return this.targetVmSize; + } + + /** + * Set the target VM size. + * + * @param targetVmSize the targetVmSize value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetVmSize(String targetVmSize) { + this.targetVmSize = targetVmSize; + return this; + } + + /** + * Get the target location. + * + * @return the targetLocation value + */ + public String targetLocation() { + return this.targetLocation; + } + + /** + * Get the target resource group Id. + * + * @return the targetResourceGroupId value + */ + public String targetResourceGroupId() { + return this.targetResourceGroupId; + } + + /** + * Set the target resource group Id. + * + * @param targetResourceGroupId the targetResourceGroupId value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetResourceGroupId(String targetResourceGroupId) { + this.targetResourceGroupId = targetResourceGroupId; + return this; + } + + /** + * Get the target availability set Id. + * + * @return the targetAvailabilitySetId value + */ + public String targetAvailabilitySetId() { + return this.targetAvailabilitySetId; + } + + /** + * Set the target availability set Id. + * + * @param targetAvailabilitySetId the targetAvailabilitySetId value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetAvailabilitySetId(String targetAvailabilitySetId) { + this.targetAvailabilitySetId = targetAvailabilitySetId; + return this; + } + + /** + * Get the target boot diagnostics storage account ARM Id. + * + * @return the targetBootDiagnosticsStorageAccountId value + */ + public String targetBootDiagnosticsStorageAccountId() { + return this.targetBootDiagnosticsStorageAccountId; + } + + /** + * Set the target boot diagnostics storage account ARM Id. + * + * @param targetBootDiagnosticsStorageAccountId the targetBootDiagnosticsStorageAccountId value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetBootDiagnosticsStorageAccountId(String targetBootDiagnosticsStorageAccountId) { + this.targetBootDiagnosticsStorageAccountId = targetBootDiagnosticsStorageAccountId; + return this; + } + + /** + * Get the list of protected disks. + * + * @return the protectedDisks value + */ + public List protectedDisks() { + return this.protectedDisks; + } + + /** + * Set the list of protected disks. + * + * @param protectedDisks the protectedDisks value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withProtectedDisks(List protectedDisks) { + this.protectedDisks = protectedDisks; + return this; + } + + /** + * Get the target network Id. + * + * @return the targetNetworkId value + */ + public String targetNetworkId() { + return this.targetNetworkId; + } + + /** + * Set the target network Id. + * + * @param targetNetworkId the targetNetworkId value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withTargetNetworkId(String targetNetworkId) { + this.targetNetworkId = targetNetworkId; + return this; + } + + /** + * Get the network details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the network details. + * + * @param vmNics the vmNics value to set + * @return the VMwareCbtMigrationDetails object itself. + */ + public VMwareCbtMigrationDetails withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the recovery point Id to which the VM was migrated. + * + * @return the migrationRecoveryPointId value + */ + public String migrationRecoveryPointId() { + return this.migrationRecoveryPointId; + } + + /** + * Get the last recovery point received time. + * + * @return the lastRecoveryPointReceived value + */ + public DateTime lastRecoveryPointReceived() { + return this.lastRecoveryPointReceived; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicDetails.java new file mode 100644 index 0000000000000..4e5d16b3d453b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicDetails.java @@ -0,0 +1,209 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * VMwareCbt NIC details. + */ +public class VMwareCbtNicDetails { + /** + * The NIC Id. + */ + @JsonProperty(value = "nicId", access = JsonProperty.Access.WRITE_ONLY) + private String nicId; + + /** + * A value indicating whether this is the primary NIC. + */ + @JsonProperty(value = "isPrimaryNic") + private String isPrimaryNic; + + /** + * The source IP address. + */ + @JsonProperty(value = "sourceIPAddress", access = JsonProperty.Access.WRITE_ONLY) + private String sourceIPAddress; + + /** + * The source IP address type. Possible values include: 'Dynamic', + * 'Static'. + */ + @JsonProperty(value = "sourceIPAddressType", access = JsonProperty.Access.WRITE_ONLY) + private EthernetAddressType sourceIPAddressType; + + /** + * Source network Id. + */ + @JsonProperty(value = "sourceNetworkId", access = JsonProperty.Access.WRITE_ONLY) + private String sourceNetworkId; + + /** + * The target IP address. + */ + @JsonProperty(value = "targetIPAddress") + private String targetIPAddress; + + /** + * The target IP address type. Possible values include: 'Dynamic', + * 'Static'. + */ + @JsonProperty(value = "targetIPAddressType") + private EthernetAddressType targetIPAddressType; + + /** + * Target subnet name. + */ + @JsonProperty(value = "targetSubnetName") + private String targetSubnetName; + + /** + * A value indicating whether this NIC is selected for migration. + */ + @JsonProperty(value = "isSelectedForMigration") + private String isSelectedForMigration; + + /** + * Get the NIC Id. + * + * @return the nicId value + */ + public String nicId() { + return this.nicId; + } + + /** + * Get a value indicating whether this is the primary NIC. + * + * @return the isPrimaryNic value + */ + public String isPrimaryNic() { + return this.isPrimaryNic; + } + + /** + * Set a value indicating whether this is the primary NIC. + * + * @param isPrimaryNic the isPrimaryNic value to set + * @return the VMwareCbtNicDetails object itself. + */ + public VMwareCbtNicDetails withIsPrimaryNic(String isPrimaryNic) { + this.isPrimaryNic = isPrimaryNic; + return this; + } + + /** + * Get the source IP address. + * + * @return the sourceIPAddress value + */ + public String sourceIPAddress() { + return this.sourceIPAddress; + } + + /** + * Get the source IP address type. Possible values include: 'Dynamic', 'Static'. + * + * @return the sourceIPAddressType value + */ + public EthernetAddressType sourceIPAddressType() { + return this.sourceIPAddressType; + } + + /** + * Get source network Id. + * + * @return the sourceNetworkId value + */ + public String sourceNetworkId() { + return this.sourceNetworkId; + } + + /** + * Get the target IP address. + * + * @return the targetIPAddress value + */ + public String targetIPAddress() { + return this.targetIPAddress; + } + + /** + * Set the target IP address. + * + * @param targetIPAddress the targetIPAddress value to set + * @return the VMwareCbtNicDetails object itself. + */ + public VMwareCbtNicDetails withTargetIPAddress(String targetIPAddress) { + this.targetIPAddress = targetIPAddress; + return this; + } + + /** + * Get the target IP address type. Possible values include: 'Dynamic', 'Static'. + * + * @return the targetIPAddressType value + */ + public EthernetAddressType targetIPAddressType() { + return this.targetIPAddressType; + } + + /** + * Set the target IP address type. Possible values include: 'Dynamic', 'Static'. + * + * @param targetIPAddressType the targetIPAddressType value to set + * @return the VMwareCbtNicDetails object itself. + */ + public VMwareCbtNicDetails withTargetIPAddressType(EthernetAddressType targetIPAddressType) { + this.targetIPAddressType = targetIPAddressType; + return this; + } + + /** + * Get target subnet name. + * + * @return the targetSubnetName value + */ + public String targetSubnetName() { + return this.targetSubnetName; + } + + /** + * Set target subnet name. + * + * @param targetSubnetName the targetSubnetName value to set + * @return the VMwareCbtNicDetails object itself. + */ + public VMwareCbtNicDetails withTargetSubnetName(String targetSubnetName) { + this.targetSubnetName = targetSubnetName; + return this; + } + + /** + * Get a value indicating whether this NIC is selected for migration. + * + * @return the isSelectedForMigration value + */ + public String isSelectedForMigration() { + return this.isSelectedForMigration; + } + + /** + * Set a value indicating whether this NIC is selected for migration. + * + * @param isSelectedForMigration the isSelectedForMigration value to set + * @return the VMwareCbtNicDetails object itself. + */ + public VMwareCbtNicDetails withIsSelectedForMigration(String isSelectedForMigration) { + this.isSelectedForMigration = isSelectedForMigration; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicInput.java new file mode 100644 index 0000000000000..a5e308e81e96b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtNicInput.java @@ -0,0 +1,147 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * VMwareCbt NIC input. + */ +public class VMwareCbtNicInput { + /** + * The NIC Id. + */ + @JsonProperty(value = "nicId", required = true) + private String nicId; + + /** + * A value indicating whether this is the primary NIC. + */ + @JsonProperty(value = "isPrimaryNic", required = true) + private String isPrimaryNic; + + /** + * Target subnet name. + */ + @JsonProperty(value = "targetSubnetName") + private String targetSubnetName; + + /** + * The static IP address. + */ + @JsonProperty(value = "targetStaticIPAddress") + private String targetStaticIPAddress; + + /** + * A value indicating whether this NIC is selected for migration. + */ + @JsonProperty(value = "isSelectedForMigration") + private String isSelectedForMigration; + + /** + * Get the NIC Id. + * + * @return the nicId value + */ + public String nicId() { + return this.nicId; + } + + /** + * Set the NIC Id. + * + * @param nicId the nicId value to set + * @return the VMwareCbtNicInput object itself. + */ + public VMwareCbtNicInput withNicId(String nicId) { + this.nicId = nicId; + return this; + } + + /** + * Get a value indicating whether this is the primary NIC. + * + * @return the isPrimaryNic value + */ + public String isPrimaryNic() { + return this.isPrimaryNic; + } + + /** + * Set a value indicating whether this is the primary NIC. + * + * @param isPrimaryNic the isPrimaryNic value to set + * @return the VMwareCbtNicInput object itself. + */ + public VMwareCbtNicInput withIsPrimaryNic(String isPrimaryNic) { + this.isPrimaryNic = isPrimaryNic; + return this; + } + + /** + * Get target subnet name. + * + * @return the targetSubnetName value + */ + public String targetSubnetName() { + return this.targetSubnetName; + } + + /** + * Set target subnet name. + * + * @param targetSubnetName the targetSubnetName value to set + * @return the VMwareCbtNicInput object itself. + */ + public VMwareCbtNicInput withTargetSubnetName(String targetSubnetName) { + this.targetSubnetName = targetSubnetName; + return this; + } + + /** + * Get the static IP address. + * + * @return the targetStaticIPAddress value + */ + public String targetStaticIPAddress() { + return this.targetStaticIPAddress; + } + + /** + * Set the static IP address. + * + * @param targetStaticIPAddress the targetStaticIPAddress value to set + * @return the VMwareCbtNicInput object itself. + */ + public VMwareCbtNicInput withTargetStaticIPAddress(String targetStaticIPAddress) { + this.targetStaticIPAddress = targetStaticIPAddress; + return this; + } + + /** + * Get a value indicating whether this NIC is selected for migration. + * + * @return the isSelectedForMigration value + */ + public String isSelectedForMigration() { + return this.isSelectedForMigration; + } + + /** + * Set a value indicating whether this NIC is selected for migration. + * + * @param isSelectedForMigration the isSelectedForMigration value to set + * @return the VMwareCbtNicInput object itself. + */ + public VMwareCbtNicInput withIsSelectedForMigration(String isSelectedForMigration) { + this.isSelectedForMigration = isSelectedForMigration; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtPolicyCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtPolicyCreationInput.java new file mode 100644 index 0000000000000..1f43858e42a95 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtPolicyCreationInput.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMware Cbt policy creation input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtPolicyCreationInput extends PolicyProviderSpecificInput { + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistoryInMinutes") + private Integer recoveryPointHistoryInMinutes; + + /** + * The crash consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * The app consistent snapshot frequency (in minutes). + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistoryInMinutes value + */ + public Integer recoveryPointHistoryInMinutes() { + return this.recoveryPointHistoryInMinutes; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistoryInMinutes the recoveryPointHistoryInMinutes value to set + * @return the VMwareCbtPolicyCreationInput object itself. + */ + public VMwareCbtPolicyCreationInput withRecoveryPointHistoryInMinutes(Integer recoveryPointHistoryInMinutes) { + this.recoveryPointHistoryInMinutes = recoveryPointHistoryInMinutes; + return this; + } + + /** + * Get the crash consistent snapshot frequency (in minutes). + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency (in minutes). + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the VMwareCbtPolicyCreationInput object itself. + */ + public VMwareCbtPolicyCreationInput withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + + /** + * Get the app consistent snapshot frequency (in minutes). + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency (in minutes). + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the VMwareCbtPolicyCreationInput object itself. + */ + public VMwareCbtPolicyCreationInput withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectedDiskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectedDiskDetails.java new file mode 100644 index 0000000000000..4bff16cc327f8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectedDiskDetails.java @@ -0,0 +1,179 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * VMwareCbt protected disk details. + */ +public class VMwareCbtProtectedDiskDetails { + /** + * The disk id. + */ + @JsonProperty(value = "diskId", access = JsonProperty.Access.WRITE_ONLY) + private String diskId; + + /** + * The disk name. + */ + @JsonProperty(value = "diskName", access = JsonProperty.Access.WRITE_ONLY) + private String diskName; + + /** + * The disk path. + */ + @JsonProperty(value = "diskPath", access = JsonProperty.Access.WRITE_ONLY) + private String diskPath; + + /** + * A value indicating whether the disk is the OS disk. + */ + @JsonProperty(value = "isOSDisk", access = JsonProperty.Access.WRITE_ONLY) + private String isOSDisk; + + /** + * The disk capacity in bytes. + */ + @JsonProperty(value = "capacityInBytes", access = JsonProperty.Access.WRITE_ONLY) + private Long capacityInBytes; + + /** + * The log storage account ARM Id. + */ + @JsonProperty(value = "logStorageAccountId", access = JsonProperty.Access.WRITE_ONLY) + private String logStorageAccountId; + + /** + * The key vault secret name of the log storage account. + */ + @JsonProperty(value = "logStorageAccountSasSecretName", access = JsonProperty.Access.WRITE_ONLY) + private String logStorageAccountSasSecretName; + + /** + * The ARM Id of the seed managed disk. + */ + @JsonProperty(value = "seedManagedDiskId", access = JsonProperty.Access.WRITE_ONLY) + private String seedManagedDiskId; + + /** + * The ARM Id of the target managed disk. + */ + @JsonProperty(value = "targetManagedDiskId", access = JsonProperty.Access.WRITE_ONLY) + private String targetManagedDiskId; + + /** + * The disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', + * 'StandardSSD_LRS'. + */ + @JsonProperty(value = "diskType") + private DiskType diskType; + + /** + * Get the disk id. + * + * @return the diskId value + */ + public String diskId() { + return this.diskId; + } + + /** + * Get the disk name. + * + * @return the diskName value + */ + public String diskName() { + return this.diskName; + } + + /** + * Get the disk path. + * + * @return the diskPath value + */ + public String diskPath() { + return this.diskPath; + } + + /** + * Get a value indicating whether the disk is the OS disk. + * + * @return the isOSDisk value + */ + public String isOSDisk() { + return this.isOSDisk; + } + + /** + * Get the disk capacity in bytes. + * + * @return the capacityInBytes value + */ + public Long capacityInBytes() { + return this.capacityInBytes; + } + + /** + * Get the log storage account ARM Id. + * + * @return the logStorageAccountId value + */ + public String logStorageAccountId() { + return this.logStorageAccountId; + } + + /** + * Get the key vault secret name of the log storage account. + * + * @return the logStorageAccountSasSecretName value + */ + public String logStorageAccountSasSecretName() { + return this.logStorageAccountSasSecretName; + } + + /** + * Get the ARM Id of the seed managed disk. + * + * @return the seedManagedDiskId value + */ + public String seedManagedDiskId() { + return this.seedManagedDiskId; + } + + /** + * Get the ARM Id of the target managed disk. + * + * @return the targetManagedDiskId value + */ + public String targetManagedDiskId() { + return this.targetManagedDiskId; + } + + /** + * Get the disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', 'StandardSSD_LRS'. + * + * @return the diskType value + */ + public DiskType diskType() { + return this.diskType; + } + + /** + * Set the disk type. Possible values include: 'Standard_LRS', 'Premium_LRS', 'StandardSSD_LRS'. + * + * @param diskType the diskType value to set + * @return the VMwareCbtProtectedDiskDetails object itself. + */ + public VMwareCbtProtectedDiskDetails withDiskType(DiskType diskType) { + this.diskType = diskType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectionContainerMappingDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectionContainerMappingDetails.java new file mode 100644 index 0000000000000..fac5b44aec52a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtProtectionContainerMappingDetails.java @@ -0,0 +1,111 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt provider specific container mapping details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtProtectionContainerMappingDetails extends ProtectionContainerMappingProviderSpecificDetails { + /** + * The target key vault ARM Id. + */ + @JsonProperty(value = "keyVaultId", access = JsonProperty.Access.WRITE_ONLY) + private String keyVaultId; + + /** + * The target key vault URI. + */ + @JsonProperty(value = "keyVaultUri", access = JsonProperty.Access.WRITE_ONLY) + private String keyVaultUri; + + /** + * The storage account ARM Id. + */ + @JsonProperty(value = "storageAccountId", access = JsonProperty.Access.WRITE_ONLY) + private String storageAccountId; + + /** + * The secret name of the storage account. + */ + @JsonProperty(value = "storageAccountSasSecretName", access = JsonProperty.Access.WRITE_ONLY) + private String storageAccountSasSecretName; + + /** + * The secret name of the service bus connection string. + */ + @JsonProperty(value = "serviceBusConnectionStringSecretName", access = JsonProperty.Access.WRITE_ONLY) + private String serviceBusConnectionStringSecretName; + + /** + * The target location. + */ + @JsonProperty(value = "targetLocation", access = JsonProperty.Access.WRITE_ONLY) + private String targetLocation; + + /** + * Get the target key vault ARM Id. + * + * @return the keyVaultId value + */ + public String keyVaultId() { + return this.keyVaultId; + } + + /** + * Get the target key vault URI. + * + * @return the keyVaultUri value + */ + public String keyVaultUri() { + return this.keyVaultUri; + } + + /** + * Get the storage account ARM Id. + * + * @return the storageAccountId value + */ + public String storageAccountId() { + return this.storageAccountId; + } + + /** + * Get the secret name of the storage account. + * + * @return the storageAccountSasSecretName value + */ + public String storageAccountSasSecretName() { + return this.storageAccountSasSecretName; + } + + /** + * Get the secret name of the service bus connection string. + * + * @return the serviceBusConnectionStringSecretName value + */ + public String serviceBusConnectionStringSecretName() { + return this.serviceBusConnectionStringSecretName; + } + + /** + * Get the target location. + * + * @return the targetLocation value + */ + public String targetLocation() { + return this.targetLocation; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtTestMigrateInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtTestMigrateInput.java new file mode 100644 index 0000000000000..a641490968881 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtTestMigrateInput.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt specific test migrate input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtTestMigrateInput extends TestMigrateProviderSpecificInput { + /** + * The recovery point Id. + */ + @JsonProperty(value = "recoveryPointId", required = true) + private String recoveryPointId; + + /** + * The test network Id. + */ + @JsonProperty(value = "networkId", required = true) + private String networkId; + + /** + * Get the recovery point Id. + * + * @return the recoveryPointId value + */ + public String recoveryPointId() { + return this.recoveryPointId; + } + + /** + * Set the recovery point Id. + * + * @param recoveryPointId the recoveryPointId value to set + * @return the VMwareCbtTestMigrateInput object itself. + */ + public VMwareCbtTestMigrateInput withRecoveryPointId(String recoveryPointId) { + this.recoveryPointId = recoveryPointId; + return this; + } + + /** + * Get the test network Id. + * + * @return the networkId value + */ + public String networkId() { + return this.networkId; + } + + /** + * Set the test network Id. + * + * @param networkId the networkId value to set + * @return the VMwareCbtTestMigrateInput object itself. + */ + public VMwareCbtTestMigrateInput withNetworkId(String networkId) { + this.networkId = networkId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtUpdateMigrationItemInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtUpdateMigrationItemInput.java new file mode 100644 index 0000000000000..7d62abc3e8ed7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareCbtUpdateMigrationItemInput.java @@ -0,0 +1,231 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareCbt specific update migration item input. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VMwareCbtUpdateMigrationItemInput extends UpdateMigrationItemProviderSpecificInput { + /** + * The target VM name. + */ + @JsonProperty(value = "targetVmName") + private String targetVmName; + + /** + * The target VM size. + */ + @JsonProperty(value = "targetVmSize") + private String targetVmSize; + + /** + * The target resource group ARM Id. + */ + @JsonProperty(value = "targetResourceGroupId") + private String targetResourceGroupId; + + /** + * The target availability set ARM Id. + */ + @JsonProperty(value = "targetAvailabilitySetId") + private String targetAvailabilitySetId; + + /** + * The target boot diagnostics storage account ARM Id. + */ + @JsonProperty(value = "targetBootDiagnosticsStorageAccountId") + private String targetBootDiagnosticsStorageAccountId; + + /** + * The target network ARM Id. + */ + @JsonProperty(value = "targetNetworkId") + private String targetNetworkId; + + /** + * The list of NIC details. + */ + @JsonProperty(value = "vmNics") + private List vmNics; + + /** + * The license type. Possible values include: 'NotSpecified', + * 'NoLicenseType', 'WindowsServer'. + */ + @JsonProperty(value = "licenseType") + private LicenseType licenseType; + + /** + * Get the target VM name. + * + * @return the targetVmName value + */ + public String targetVmName() { + return this.targetVmName; + } + + /** + * Set the target VM name. + * + * @param targetVmName the targetVmName value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetVmName(String targetVmName) { + this.targetVmName = targetVmName; + return this; + } + + /** + * Get the target VM size. + * + * @return the targetVmSize value + */ + public String targetVmSize() { + return this.targetVmSize; + } + + /** + * Set the target VM size. + * + * @param targetVmSize the targetVmSize value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetVmSize(String targetVmSize) { + this.targetVmSize = targetVmSize; + return this; + } + + /** + * Get the target resource group ARM Id. + * + * @return the targetResourceGroupId value + */ + public String targetResourceGroupId() { + return this.targetResourceGroupId; + } + + /** + * Set the target resource group ARM Id. + * + * @param targetResourceGroupId the targetResourceGroupId value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetResourceGroupId(String targetResourceGroupId) { + this.targetResourceGroupId = targetResourceGroupId; + return this; + } + + /** + * Get the target availability set ARM Id. + * + * @return the targetAvailabilitySetId value + */ + public String targetAvailabilitySetId() { + return this.targetAvailabilitySetId; + } + + /** + * Set the target availability set ARM Id. + * + * @param targetAvailabilitySetId the targetAvailabilitySetId value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetAvailabilitySetId(String targetAvailabilitySetId) { + this.targetAvailabilitySetId = targetAvailabilitySetId; + return this; + } + + /** + * Get the target boot diagnostics storage account ARM Id. + * + * @return the targetBootDiagnosticsStorageAccountId value + */ + public String targetBootDiagnosticsStorageAccountId() { + return this.targetBootDiagnosticsStorageAccountId; + } + + /** + * Set the target boot diagnostics storage account ARM Id. + * + * @param targetBootDiagnosticsStorageAccountId the targetBootDiagnosticsStorageAccountId value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetBootDiagnosticsStorageAccountId(String targetBootDiagnosticsStorageAccountId) { + this.targetBootDiagnosticsStorageAccountId = targetBootDiagnosticsStorageAccountId; + return this; + } + + /** + * Get the target network ARM Id. + * + * @return the targetNetworkId value + */ + public String targetNetworkId() { + return this.targetNetworkId; + } + + /** + * Set the target network ARM Id. + * + * @param targetNetworkId the targetNetworkId value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withTargetNetworkId(String targetNetworkId) { + this.targetNetworkId = targetNetworkId; + return this; + } + + /** + * Get the list of NIC details. + * + * @return the vmNics value + */ + public List vmNics() { + return this.vmNics; + } + + /** + * Set the list of NIC details. + * + * @param vmNics the vmNics value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withVmNics(List vmNics) { + this.vmNics = vmNics; + return this; + } + + /** + * Get the license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @return the licenseType value + */ + public LicenseType licenseType() { + return this.licenseType; + } + + /** + * Set the license type. Possible values include: 'NotSpecified', 'NoLicenseType', 'WindowsServer'. + * + * @param licenseType the licenseType value to set + * @return the VMwareCbtUpdateMigrationItemInput object itself. + */ + public VMwareCbtUpdateMigrationItemInput withLicenseType(LicenseType licenseType) { + this.licenseType = licenseType; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareDetails.java new file mode 100644 index 0000000000000..546d8830b749b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareDetails.java @@ -0,0 +1,855 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Store the fabric details specific to the VMware fabric. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMware") +public class VMwareDetails extends FabricSpecificDetails { + /** + * The list of Process Servers associated with the fabric. + */ + @JsonProperty(value = "processServers") + private List processServers; + + /** + * The list of Master Target servers associated with the fabric. + */ + @JsonProperty(value = "masterTargetServers") + private List masterTargetServers; + + /** + * The list of run as accounts created on the server. + */ + @JsonProperty(value = "runAsAccounts") + private List runAsAccounts; + + /** + * The number of replication pairs configured in this CS. + */ + @JsonProperty(value = "replicationPairCount") + private String replicationPairCount; + + /** + * The number of process servers. + */ + @JsonProperty(value = "processServerCount") + private String processServerCount; + + /** + * The number of source and target servers configured to talk to this CS. + */ + @JsonProperty(value = "agentCount") + private String agentCount; + + /** + * The number of protected servers. + */ + @JsonProperty(value = "protectedServers") + private String protectedServers; + + /** + * The percentage of the system load. + */ + @JsonProperty(value = "systemLoad") + private String systemLoad; + + /** + * The system load status. + */ + @JsonProperty(value = "systemLoadStatus") + private String systemLoadStatus; + + /** + * The percentage of the CPU load. + */ + @JsonProperty(value = "cpuLoad") + private String cpuLoad; + + /** + * The CPU load status. + */ + @JsonProperty(value = "cpuLoadStatus") + private String cpuLoadStatus; + + /** + * The total memory. + */ + @JsonProperty(value = "totalMemoryInBytes") + private Long totalMemoryInBytes; + + /** + * The available memory. + */ + @JsonProperty(value = "availableMemoryInBytes") + private Long availableMemoryInBytes; + + /** + * The memory usage status. + */ + @JsonProperty(value = "memoryUsageStatus") + private String memoryUsageStatus; + + /** + * The total space. + */ + @JsonProperty(value = "totalSpaceInBytes") + private Long totalSpaceInBytes; + + /** + * The available space. + */ + @JsonProperty(value = "availableSpaceInBytes") + private Long availableSpaceInBytes; + + /** + * The space usage status. + */ + @JsonProperty(value = "spaceUsageStatus") + private String spaceUsageStatus; + + /** + * The web load. + */ + @JsonProperty(value = "webLoad") + private String webLoad; + + /** + * The web load status. + */ + @JsonProperty(value = "webLoadStatus") + private String webLoadStatus; + + /** + * The database server load. + */ + @JsonProperty(value = "databaseServerLoad") + private String databaseServerLoad; + + /** + * The database server load status. + */ + @JsonProperty(value = "databaseServerLoadStatus") + private String databaseServerLoadStatus; + + /** + * The CS service status. + */ + @JsonProperty(value = "csServiceStatus") + private String csServiceStatus; + + /** + * The IP address. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The agent Version. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * The host name. + */ + @JsonProperty(value = "hostName") + private String hostName; + + /** + * The last heartbeat received from CS server. + */ + @JsonProperty(value = "lastHeartbeat") + private DateTime lastHeartbeat; + + /** + * Version status. + */ + @JsonProperty(value = "versionStatus") + private String versionStatus; + + /** + * CS SSL cert expiry date. + */ + @JsonProperty(value = "sslCertExpiryDate") + private DateTime sslCertExpiryDate; + + /** + * CS SSL cert expiry date. + */ + @JsonProperty(value = "sslCertExpiryRemainingDays") + private Integer sslCertExpiryRemainingDays; + + /** + * PS template version. + */ + @JsonProperty(value = "psTemplateVersion") + private String psTemplateVersion; + + /** + * Agent expiry date. + */ + @JsonProperty(value = "agentExpiryDate") + private DateTime agentExpiryDate; + + /** + * The agent version details. + */ + @JsonProperty(value = "agentVersionDetails") + private VersionDetails agentVersionDetails; + + /** + * Get the list of Process Servers associated with the fabric. + * + * @return the processServers value + */ + public List processServers() { + return this.processServers; + } + + /** + * Set the list of Process Servers associated with the fabric. + * + * @param processServers the processServers value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withProcessServers(List processServers) { + this.processServers = processServers; + return this; + } + + /** + * Get the list of Master Target servers associated with the fabric. + * + * @return the masterTargetServers value + */ + public List masterTargetServers() { + return this.masterTargetServers; + } + + /** + * Set the list of Master Target servers associated with the fabric. + * + * @param masterTargetServers the masterTargetServers value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withMasterTargetServers(List masterTargetServers) { + this.masterTargetServers = masterTargetServers; + return this; + } + + /** + * Get the list of run as accounts created on the server. + * + * @return the runAsAccounts value + */ + public List runAsAccounts() { + return this.runAsAccounts; + } + + /** + * Set the list of run as accounts created on the server. + * + * @param runAsAccounts the runAsAccounts value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withRunAsAccounts(List runAsAccounts) { + this.runAsAccounts = runAsAccounts; + return this; + } + + /** + * Get the number of replication pairs configured in this CS. + * + * @return the replicationPairCount value + */ + public String replicationPairCount() { + return this.replicationPairCount; + } + + /** + * Set the number of replication pairs configured in this CS. + * + * @param replicationPairCount the replicationPairCount value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withReplicationPairCount(String replicationPairCount) { + this.replicationPairCount = replicationPairCount; + return this; + } + + /** + * Get the number of process servers. + * + * @return the processServerCount value + */ + public String processServerCount() { + return this.processServerCount; + } + + /** + * Set the number of process servers. + * + * @param processServerCount the processServerCount value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withProcessServerCount(String processServerCount) { + this.processServerCount = processServerCount; + return this; + } + + /** + * Get the number of source and target servers configured to talk to this CS. + * + * @return the agentCount value + */ + public String agentCount() { + return this.agentCount; + } + + /** + * Set the number of source and target servers configured to talk to this CS. + * + * @param agentCount the agentCount value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAgentCount(String agentCount) { + this.agentCount = agentCount; + return this; + } + + /** + * Get the number of protected servers. + * + * @return the protectedServers value + */ + public String protectedServers() { + return this.protectedServers; + } + + /** + * Set the number of protected servers. + * + * @param protectedServers the protectedServers value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withProtectedServers(String protectedServers) { + this.protectedServers = protectedServers; + return this; + } + + /** + * Get the percentage of the system load. + * + * @return the systemLoad value + */ + public String systemLoad() { + return this.systemLoad; + } + + /** + * Set the percentage of the system load. + * + * @param systemLoad the systemLoad value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withSystemLoad(String systemLoad) { + this.systemLoad = systemLoad; + return this; + } + + /** + * Get the system load status. + * + * @return the systemLoadStatus value + */ + public String systemLoadStatus() { + return this.systemLoadStatus; + } + + /** + * Set the system load status. + * + * @param systemLoadStatus the systemLoadStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withSystemLoadStatus(String systemLoadStatus) { + this.systemLoadStatus = systemLoadStatus; + return this; + } + + /** + * Get the percentage of the CPU load. + * + * @return the cpuLoad value + */ + public String cpuLoad() { + return this.cpuLoad; + } + + /** + * Set the percentage of the CPU load. + * + * @param cpuLoad the cpuLoad value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withCpuLoad(String cpuLoad) { + this.cpuLoad = cpuLoad; + return this; + } + + /** + * Get the CPU load status. + * + * @return the cpuLoadStatus value + */ + public String cpuLoadStatus() { + return this.cpuLoadStatus; + } + + /** + * Set the CPU load status. + * + * @param cpuLoadStatus the cpuLoadStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withCpuLoadStatus(String cpuLoadStatus) { + this.cpuLoadStatus = cpuLoadStatus; + return this; + } + + /** + * Get the total memory. + * + * @return the totalMemoryInBytes value + */ + public Long totalMemoryInBytes() { + return this.totalMemoryInBytes; + } + + /** + * Set the total memory. + * + * @param totalMemoryInBytes the totalMemoryInBytes value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withTotalMemoryInBytes(Long totalMemoryInBytes) { + this.totalMemoryInBytes = totalMemoryInBytes; + return this; + } + + /** + * Get the available memory. + * + * @return the availableMemoryInBytes value + */ + public Long availableMemoryInBytes() { + return this.availableMemoryInBytes; + } + + /** + * Set the available memory. + * + * @param availableMemoryInBytes the availableMemoryInBytes value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAvailableMemoryInBytes(Long availableMemoryInBytes) { + this.availableMemoryInBytes = availableMemoryInBytes; + return this; + } + + /** + * Get the memory usage status. + * + * @return the memoryUsageStatus value + */ + public String memoryUsageStatus() { + return this.memoryUsageStatus; + } + + /** + * Set the memory usage status. + * + * @param memoryUsageStatus the memoryUsageStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withMemoryUsageStatus(String memoryUsageStatus) { + this.memoryUsageStatus = memoryUsageStatus; + return this; + } + + /** + * Get the total space. + * + * @return the totalSpaceInBytes value + */ + public Long totalSpaceInBytes() { + return this.totalSpaceInBytes; + } + + /** + * Set the total space. + * + * @param totalSpaceInBytes the totalSpaceInBytes value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withTotalSpaceInBytes(Long totalSpaceInBytes) { + this.totalSpaceInBytes = totalSpaceInBytes; + return this; + } + + /** + * Get the available space. + * + * @return the availableSpaceInBytes value + */ + public Long availableSpaceInBytes() { + return this.availableSpaceInBytes; + } + + /** + * Set the available space. + * + * @param availableSpaceInBytes the availableSpaceInBytes value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAvailableSpaceInBytes(Long availableSpaceInBytes) { + this.availableSpaceInBytes = availableSpaceInBytes; + return this; + } + + /** + * Get the space usage status. + * + * @return the spaceUsageStatus value + */ + public String spaceUsageStatus() { + return this.spaceUsageStatus; + } + + /** + * Set the space usage status. + * + * @param spaceUsageStatus the spaceUsageStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withSpaceUsageStatus(String spaceUsageStatus) { + this.spaceUsageStatus = spaceUsageStatus; + return this; + } + + /** + * Get the web load. + * + * @return the webLoad value + */ + public String webLoad() { + return this.webLoad; + } + + /** + * Set the web load. + * + * @param webLoad the webLoad value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withWebLoad(String webLoad) { + this.webLoad = webLoad; + return this; + } + + /** + * Get the web load status. + * + * @return the webLoadStatus value + */ + public String webLoadStatus() { + return this.webLoadStatus; + } + + /** + * Set the web load status. + * + * @param webLoadStatus the webLoadStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withWebLoadStatus(String webLoadStatus) { + this.webLoadStatus = webLoadStatus; + return this; + } + + /** + * Get the database server load. + * + * @return the databaseServerLoad value + */ + public String databaseServerLoad() { + return this.databaseServerLoad; + } + + /** + * Set the database server load. + * + * @param databaseServerLoad the databaseServerLoad value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withDatabaseServerLoad(String databaseServerLoad) { + this.databaseServerLoad = databaseServerLoad; + return this; + } + + /** + * Get the database server load status. + * + * @return the databaseServerLoadStatus value + */ + public String databaseServerLoadStatus() { + return this.databaseServerLoadStatus; + } + + /** + * Set the database server load status. + * + * @param databaseServerLoadStatus the databaseServerLoadStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withDatabaseServerLoadStatus(String databaseServerLoadStatus) { + this.databaseServerLoadStatus = databaseServerLoadStatus; + return this; + } + + /** + * Get the CS service status. + * + * @return the csServiceStatus value + */ + public String csServiceStatus() { + return this.csServiceStatus; + } + + /** + * Set the CS service status. + * + * @param csServiceStatus the csServiceStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withCsServiceStatus(String csServiceStatus) { + this.csServiceStatus = csServiceStatus; + return this; + } + + /** + * Get the IP address. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address. + * + * @param ipAddress the ipAddress value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the agent Version. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the agent Version. + * + * @param agentVersion the agentVersion value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get the host name. + * + * @return the hostName value + */ + public String hostName() { + return this.hostName; + } + + /** + * Set the host name. + * + * @param hostName the hostName value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + /** + * Get the last heartbeat received from CS server. + * + * @return the lastHeartbeat value + */ + public DateTime lastHeartbeat() { + return this.lastHeartbeat; + } + + /** + * Set the last heartbeat received from CS server. + * + * @param lastHeartbeat the lastHeartbeat value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withLastHeartbeat(DateTime lastHeartbeat) { + this.lastHeartbeat = lastHeartbeat; + return this; + } + + /** + * Get version status. + * + * @return the versionStatus value + */ + public String versionStatus() { + return this.versionStatus; + } + + /** + * Set version status. + * + * @param versionStatus the versionStatus value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withVersionStatus(String versionStatus) { + this.versionStatus = versionStatus; + return this; + } + + /** + * Get cS SSL cert expiry date. + * + * @return the sslCertExpiryDate value + */ + public DateTime sslCertExpiryDate() { + return this.sslCertExpiryDate; + } + + /** + * Set cS SSL cert expiry date. + * + * @param sslCertExpiryDate the sslCertExpiryDate value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withSslCertExpiryDate(DateTime sslCertExpiryDate) { + this.sslCertExpiryDate = sslCertExpiryDate; + return this; + } + + /** + * Get cS SSL cert expiry date. + * + * @return the sslCertExpiryRemainingDays value + */ + public Integer sslCertExpiryRemainingDays() { + return this.sslCertExpiryRemainingDays; + } + + /** + * Set cS SSL cert expiry date. + * + * @param sslCertExpiryRemainingDays the sslCertExpiryRemainingDays value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withSslCertExpiryRemainingDays(Integer sslCertExpiryRemainingDays) { + this.sslCertExpiryRemainingDays = sslCertExpiryRemainingDays; + return this; + } + + /** + * Get pS template version. + * + * @return the psTemplateVersion value + */ + public String psTemplateVersion() { + return this.psTemplateVersion; + } + + /** + * Set pS template version. + * + * @param psTemplateVersion the psTemplateVersion value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withPsTemplateVersion(String psTemplateVersion) { + this.psTemplateVersion = psTemplateVersion; + return this; + } + + /** + * Get agent expiry date. + * + * @return the agentExpiryDate value + */ + public DateTime agentExpiryDate() { + return this.agentExpiryDate; + } + + /** + * Set agent expiry date. + * + * @param agentExpiryDate the agentExpiryDate value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAgentExpiryDate(DateTime agentExpiryDate) { + this.agentExpiryDate = agentExpiryDate; + return this; + } + + /** + * Get the agent version details. + * + * @return the agentVersionDetails value + */ + public VersionDetails agentVersionDetails() { + return this.agentVersionDetails; + } + + /** + * Set the agent version details. + * + * @param agentVersionDetails the agentVersionDetails value to set + * @return the VMwareDetails object itself. + */ + public VMwareDetails withAgentVersionDetails(VersionDetails agentVersionDetails) { + this.agentVersionDetails = agentVersionDetails; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricCreationInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricCreationInput.java new file mode 100644 index 0000000000000..a6c2028382abe --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricCreationInput.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareV2 fabric provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareV2") +public class VMwareV2FabricCreationInput extends FabricSpecificCreationInput { + /** + * The ARM Id of the VMware site. + */ + @JsonProperty(value = "vmwareSiteId", required = true) + private String vmwareSiteId; + + /** + * The ARM Id of the migration solution. + */ + @JsonProperty(value = "migrationSolutionId", required = true) + private String migrationSolutionId; + + /** + * Get the ARM Id of the VMware site. + * + * @return the vmwareSiteId value + */ + public String vmwareSiteId() { + return this.vmwareSiteId; + } + + /** + * Set the ARM Id of the VMware site. + * + * @param vmwareSiteId the vmwareSiteId value to set + * @return the VMwareV2FabricCreationInput object itself. + */ + public VMwareV2FabricCreationInput withVmwareSiteId(String vmwareSiteId) { + this.vmwareSiteId = vmwareSiteId; + return this; + } + + /** + * Get the ARM Id of the migration solution. + * + * @return the migrationSolutionId value + */ + public String migrationSolutionId() { + return this.migrationSolutionId; + } + + /** + * Set the ARM Id of the migration solution. + * + * @param migrationSolutionId the migrationSolutionId value to set + * @return the VMwareV2FabricCreationInput object itself. + */ + public VMwareV2FabricCreationInput withMigrationSolutionId(String migrationSolutionId) { + this.migrationSolutionId = migrationSolutionId; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricSpecificDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricSpecificDetails.java new file mode 100644 index 0000000000000..1ea4cfb47fc79 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareV2FabricSpecificDetails.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMwareV2 fabric specific details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareV2") +public class VMwareV2FabricSpecificDetails extends FabricSpecificDetails { + /** + * The ARM Id of the VMware site. + */ + @JsonProperty(value = "vmwareSiteId", access = JsonProperty.Access.WRITE_ONLY) + private String vmwareSiteId; + + /** + * The Migration solution ARM Id. + */ + @JsonProperty(value = "migrationSolutionId", access = JsonProperty.Access.WRITE_ONLY) + private String migrationSolutionId; + + /** + * The service endpoint. + */ + @JsonProperty(value = "serviceEndpoint", access = JsonProperty.Access.WRITE_ONLY) + private String serviceEndpoint; + + /** + * Get the ARM Id of the VMware site. + * + * @return the vmwareSiteId value + */ + public String vmwareSiteId() { + return this.vmwareSiteId; + } + + /** + * Get the Migration solution ARM Id. + * + * @return the migrationSolutionId value + */ + public String migrationSolutionId() { + return this.migrationSolutionId; + } + + /** + * Get the service endpoint. + * + * @return the serviceEndpoint value + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareVirtualMachineDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareVirtualMachineDetails.java new file mode 100644 index 0000000000000..34c91b10656b7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VMwareVirtualMachineDetails.java @@ -0,0 +1,284 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMware provider specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareVirtualMachine") +public class VMwareVirtualMachineDetails extends ConfigurationSettings { + /** + * The ID generated by the InMage agent after it gets installed on guest. + * This is the ID to be used during InMage CreateProtection. + */ + @JsonProperty(value = "agentGeneratedId") + private String agentGeneratedId; + + /** + * The value indicating if InMage scout agent is installed on guest. + */ + @JsonProperty(value = "agentInstalled") + private String agentInstalled; + + /** + * The OsType installed on VM. + */ + @JsonProperty(value = "osType") + private String osType; + + /** + * The agent version. + */ + @JsonProperty(value = "agentVersion") + private String agentVersion; + + /** + * The IP address. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * The value indicating whether VM is powered on. + */ + @JsonProperty(value = "poweredOn") + private String poweredOn; + + /** + * The VCenter infrastructure Id. + */ + @JsonProperty(value = "vCenterInfrastructureId") + private String vCenterInfrastructureId; + + /** + * A value indicating the discovery type of the machine. Value can be + * vCenter or physical. + */ + @JsonProperty(value = "discoveryType") + private String discoveryType; + + /** + * The disk details. + */ + @JsonProperty(value = "diskDetails") + private List diskDetails; + + /** + * The validation errors. + */ + @JsonProperty(value = "validationErrors") + private List validationErrors; + + /** + * Get the ID generated by the InMage agent after it gets installed on guest. This is the ID to be used during InMage CreateProtection. + * + * @return the agentGeneratedId value + */ + public String agentGeneratedId() { + return this.agentGeneratedId; + } + + /** + * Set the ID generated by the InMage agent after it gets installed on guest. This is the ID to be used during InMage CreateProtection. + * + * @param agentGeneratedId the agentGeneratedId value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withAgentGeneratedId(String agentGeneratedId) { + this.agentGeneratedId = agentGeneratedId; + return this; + } + + /** + * Get the value indicating if InMage scout agent is installed on guest. + * + * @return the agentInstalled value + */ + public String agentInstalled() { + return this.agentInstalled; + } + + /** + * Set the value indicating if InMage scout agent is installed on guest. + * + * @param agentInstalled the agentInstalled value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withAgentInstalled(String agentInstalled) { + this.agentInstalled = agentInstalled; + return this; + } + + /** + * Get the OsType installed on VM. + * + * @return the osType value + */ + public String osType() { + return this.osType; + } + + /** + * Set the OsType installed on VM. + * + * @param osType the osType value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withOsType(String osType) { + this.osType = osType; + return this; + } + + /** + * Get the agent version. + * + * @return the agentVersion value + */ + public String agentVersion() { + return this.agentVersion; + } + + /** + * Set the agent version. + * + * @param agentVersion the agentVersion value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withAgentVersion(String agentVersion) { + this.agentVersion = agentVersion; + return this; + } + + /** + * Get the IP address. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set the IP address. + * + * @param ipAddress the ipAddress value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get the value indicating whether VM is powered on. + * + * @return the poweredOn value + */ + public String poweredOn() { + return this.poweredOn; + } + + /** + * Set the value indicating whether VM is powered on. + * + * @param poweredOn the poweredOn value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withPoweredOn(String poweredOn) { + this.poweredOn = poweredOn; + return this; + } + + /** + * Get the VCenter infrastructure Id. + * + * @return the vCenterInfrastructureId value + */ + public String vCenterInfrastructureId() { + return this.vCenterInfrastructureId; + } + + /** + * Set the VCenter infrastructure Id. + * + * @param vCenterInfrastructureId the vCenterInfrastructureId value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withVCenterInfrastructureId(String vCenterInfrastructureId) { + this.vCenterInfrastructureId = vCenterInfrastructureId; + return this; + } + + /** + * Get a value indicating the discovery type of the machine. Value can be vCenter or physical. + * + * @return the discoveryType value + */ + public String discoveryType() { + return this.discoveryType; + } + + /** + * Set a value indicating the discovery type of the machine. Value can be vCenter or physical. + * + * @param discoveryType the discoveryType value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withDiscoveryType(String discoveryType) { + this.discoveryType = discoveryType; + return this; + } + + /** + * Get the disk details. + * + * @return the diskDetails value + */ + public List diskDetails() { + return this.diskDetails; + } + + /** + * Set the disk details. + * + * @param diskDetails the diskDetails value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withDiskDetails(List diskDetails) { + this.diskDetails = diskDetails; + return this; + } + + /** + * Get the validation errors. + * + * @return the validationErrors value + */ + public List validationErrors() { + return this.validationErrors; + } + + /** + * Set the validation errors. + * + * @param validationErrors the validationErrors value to set + * @return the VMwareVirtualMachineDetails object itself. + */ + public VMwareVirtualMachineDetails withValidationErrors(List validationErrors) { + this.validationErrors = validationErrors; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthDetails.java new file mode 100644 index 0000000000000..c880cb3f7fcc7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthDetails.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.RecoveryServicesManager; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation.VaultHealthDetailsInner; + +/** + * Type representing VaultHealthDetails. + */ +public interface VaultHealthDetails extends HasInner, HasManager { + /** + * @return the id value. + */ + String id(); + + /** + * @return the location value. + */ + String location(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the properties value. + */ + VaultHealthProperties properties(); + + /** + * @return the type value. + */ + String type(); + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthProperties.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthProperties.java new file mode 100644 index 0000000000000..3506b388fef15 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VaultHealthProperties.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * class to define the health summary of the Vault. + */ +public class VaultHealthProperties { + /** + * The list of errors on the vault. + */ + @JsonProperty(value = "vaultErrors") + private List vaultErrors; + + /** + * The list of the health detail of the protected items in the vault. + */ + @JsonProperty(value = "protectedItemsHealth") + private ResourceHealthSummary protectedItemsHealth; + + /** + * The list of the health detail of the fabrics in the vault. + */ + @JsonProperty(value = "fabricsHealth") + private ResourceHealthSummary fabricsHealth; + + /** + * The list of the health detail of the containers in the vault. + */ + @JsonProperty(value = "containersHealth") + private ResourceHealthSummary containersHealth; + + /** + * Get the list of errors on the vault. + * + * @return the vaultErrors value + */ + public List vaultErrors() { + return this.vaultErrors; + } + + /** + * Set the list of errors on the vault. + * + * @param vaultErrors the vaultErrors value to set + * @return the VaultHealthProperties object itself. + */ + public VaultHealthProperties withVaultErrors(List vaultErrors) { + this.vaultErrors = vaultErrors; + return this; + } + + /** + * Get the list of the health detail of the protected items in the vault. + * + * @return the protectedItemsHealth value + */ + public ResourceHealthSummary protectedItemsHealth() { + return this.protectedItemsHealth; + } + + /** + * Set the list of the health detail of the protected items in the vault. + * + * @param protectedItemsHealth the protectedItemsHealth value to set + * @return the VaultHealthProperties object itself. + */ + public VaultHealthProperties withProtectedItemsHealth(ResourceHealthSummary protectedItemsHealth) { + this.protectedItemsHealth = protectedItemsHealth; + return this; + } + + /** + * Get the list of the health detail of the fabrics in the vault. + * + * @return the fabricsHealth value + */ + public ResourceHealthSummary fabricsHealth() { + return this.fabricsHealth; + } + + /** + * Set the list of the health detail of the fabrics in the vault. + * + * @param fabricsHealth the fabricsHealth value to set + * @return the VaultHealthProperties object itself. + */ + public VaultHealthProperties withFabricsHealth(ResourceHealthSummary fabricsHealth) { + this.fabricsHealth = fabricsHealth; + return this; + } + + /** + * Get the list of the health detail of the containers in the vault. + * + * @return the containersHealth value + */ + public ResourceHealthSummary containersHealth() { + return this.containersHealth; + } + + /** + * Set the list of the health detail of the containers in the vault. + * + * @param containersHealth the containersHealth value to set + * @return the VaultHealthProperties object itself. + */ + public VaultHealthProperties withContainersHealth(ResourceHealthSummary containersHealth) { + this.containersHealth = containersHealth; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VersionDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VersionDetails.java new file mode 100644 index 0000000000000..be02b05097da0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VersionDetails.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import org.joda.time.DateTime; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Version related details. + */ +public class VersionDetails { + /** + * The agent version. + */ + @JsonProperty(value = "version") + private String version; + + /** + * Version expiry date. + */ + @JsonProperty(value = "expiryDate") + private DateTime expiryDate; + + /** + * A value indicating whether security update required. Possible values + * include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', + * 'SecurityUpdateRequired'. + */ + @JsonProperty(value = "status") + private AgentVersionStatus status; + + /** + * Get the agent version. + * + * @return the version value + */ + public String version() { + return this.version; + } + + /** + * Set the agent version. + * + * @param version the version value to set + * @return the VersionDetails object itself. + */ + public VersionDetails withVersion(String version) { + this.version = version; + return this; + } + + /** + * Get version expiry date. + * + * @return the expiryDate value + */ + public DateTime expiryDate() { + return this.expiryDate; + } + + /** + * Set version expiry date. + * + * @param expiryDate the expiryDate value to set + * @return the VersionDetails object itself. + */ + public VersionDetails withExpiryDate(DateTime expiryDate) { + this.expiryDate = expiryDate; + return this; + } + + /** + * Get a value indicating whether security update required. Possible values include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', 'SecurityUpdateRequired'. + * + * @return the status value + */ + public AgentVersionStatus status() { + return this.status; + } + + /** + * Set a value indicating whether security update required. Possible values include: 'Supported', 'NotSupported', 'Deprecated', 'UpdateRequired', 'SecurityUpdateRequired'. + * + * @param status the status value to set + * @return the VersionDetails object itself. + */ + public VersionDetails withStatus(AgentVersionStatus status) { + this.status = status; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VirtualMachineTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VirtualMachineTaskDetails.java new file mode 100644 index 0000000000000..b1ebf0ad5649c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VirtualMachineTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the virtual machine task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VirtualMachineTaskDetails") +public class VirtualMachineTaskDetails extends TaskTypeDetails { + /** + * The skipped reason. + */ + @JsonProperty(value = "skippedReason") + private String skippedReason; + + /** + * The skipped reason string. + */ + @JsonProperty(value = "skippedReasonString") + private String skippedReasonString; + + /** + * The job entity. + */ + @JsonProperty(value = "jobTask") + private JobEntity jobTask; + + /** + * Get the skipped reason. + * + * @return the skippedReason value + */ + public String skippedReason() { + return this.skippedReason; + } + + /** + * Set the skipped reason. + * + * @param skippedReason the skippedReason value to set + * @return the VirtualMachineTaskDetails object itself. + */ + public VirtualMachineTaskDetails withSkippedReason(String skippedReason) { + this.skippedReason = skippedReason; + return this; + } + + /** + * Get the skipped reason string. + * + * @return the skippedReasonString value + */ + public String skippedReasonString() { + return this.skippedReasonString; + } + + /** + * Set the skipped reason string. + * + * @param skippedReasonString the skippedReasonString value to set + * @return the VirtualMachineTaskDetails object itself. + */ + public VirtualMachineTaskDetails withSkippedReasonString(String skippedReasonString) { + this.skippedReasonString = skippedReasonString; + return this; + } + + /** + * Get the job entity. + * + * @return the jobTask value + */ + public JobEntity jobTask() { + return this.jobTask; + } + + /** + * Set the job entity. + * + * @param jobTask the jobTask value to set + * @return the VirtualMachineTaskDetails object itself. + */ + public VirtualMachineTaskDetails withJobTask(JobEntity jobTask) { + this.jobTask = jobTask; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmNicUpdatesTaskDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmNicUpdatesTaskDetails.java new file mode 100644 index 0000000000000..479345a71dcbc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmNicUpdatesTaskDetails.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * This class represents the vm NicUpdates task details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmNicUpdatesTaskDetails") +public class VmNicUpdatesTaskDetails extends TaskTypeDetails { + /** + * Virtual machine Id. + */ + @JsonProperty(value = "vmId") + private String vmId; + + /** + * Nic Id. + */ + @JsonProperty(value = "nicId") + private String nicId; + + /** + * Name of the Nic. + */ + @JsonProperty(value = "name") + private String name; + + /** + * Get virtual machine Id. + * + * @return the vmId value + */ + public String vmId() { + return this.vmId; + } + + /** + * Set virtual machine Id. + * + * @param vmId the vmId value to set + * @return the VmNicUpdatesTaskDetails object itself. + */ + public VmNicUpdatesTaskDetails withVmId(String vmId) { + this.vmId = vmId; + return this; + } + + /** + * Get nic Id. + * + * @return the nicId value + */ + public String nicId() { + return this.nicId; + } + + /** + * Set nic Id. + * + * @param nicId the nicId value to set + * @return the VmNicUpdatesTaskDetails object itself. + */ + public VmNicUpdatesTaskDetails withNicId(String nicId) { + this.nicId = nicId; + return this; + } + + /** + * Get name of the Nic. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set name of the Nic. + * + * @param name the name value to set + * @return the VmNicUpdatesTaskDetails object itself. + */ + public VmNicUpdatesTaskDetails withName(String name) { + this.name = name; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmDetails.java new file mode 100644 index 0000000000000..68a533bdaeddd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmDetails.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMM fabric specific details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMM") +public class VmmDetails extends FabricSpecificDetails { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureCreateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureCreateNetworkMappingInput.java new file mode 100644 index 0000000000000..a056a3d5a8d97 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureCreateNetworkMappingInput.java @@ -0,0 +1,21 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Create network mappings input properties/behavior specific to Vmm to Azure + * Network mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToAzure") +public class VmmToAzureCreateNetworkMappingInput extends FabricSpecificCreateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureNetworkMappingSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureNetworkMappingSettings.java new file mode 100644 index 0000000000000..f29358d714040 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureNetworkMappingSettings.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * E2A Network Mapping fabric specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToAzure") +public class VmmToAzureNetworkMappingSettings extends NetworkMappingFabricSpecificSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureUpdateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureUpdateNetworkMappingInput.java new file mode 100644 index 0000000000000..0e42ac5ef8675 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToAzureUpdateNetworkMappingInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Update network mappings input properties/behavior specific to vmm to azure. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToAzure") +public class VmmToAzureUpdateNetworkMappingInput extends FabricSpecificUpdateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmCreateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmCreateNetworkMappingInput.java new file mode 100644 index 0000000000000..0431eb03b2e37 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmCreateNetworkMappingInput.java @@ -0,0 +1,21 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Create network mappings input properties/behavior specific to vmm to vmm + * Network mapping. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToVmm") +public class VmmToVmmCreateNetworkMappingInput extends FabricSpecificCreateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmNetworkMappingSettings.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmNetworkMappingSettings.java new file mode 100644 index 0000000000000..5ac13a94e9dd2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmNetworkMappingSettings.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * E2E Network Mapping fabric specific settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToVmm") +public class VmmToVmmNetworkMappingSettings extends NetworkMappingFabricSpecificSettings { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmUpdateNetworkMappingInput.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmUpdateNetworkMappingInput.java new file mode 100644 index 0000000000000..c3e17206ae570 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmToVmmUpdateNetworkMappingInput.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * Update network mappings input properties/behavior specific to vmm to vmm. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmToVmm") +public class VmmToVmmUpdateNetworkMappingInput extends FabricSpecificUpdateNetworkMappingInput { +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmVirtualMachineDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmVirtualMachineDetails.java new file mode 100644 index 0000000000000..f8fbb9eb1ba11 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmmVirtualMachineDetails.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMM fabric provider specific VM settings. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VmmVirtualMachine") +public class VmmVirtualMachineDetails extends ConfigurationSettings { + /** + * The source id of the object. + */ + @JsonProperty(value = "sourceItemId") + private String sourceItemId; + + /** + * The id of the object in fabric. + */ + @JsonProperty(value = "generation") + private String generation; + + /** + * The Last replication time. + */ + @JsonProperty(value = "osDetails") + private OSDetails osDetails; + + /** + * The Last successful failover time. + */ + @JsonProperty(value = "diskDetails") + private List diskDetails; + + /** + * A value indicating whether the VM has a physical disk attached. String + * value of {SrsDataContract.PresenceStatus} enum. Possible values include: + * 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasPhysicalDisk") + private PresenceStatus hasPhysicalDisk; + + /** + * A value indicating whether the VM has a fibre channel adapter attached. + * String value of {SrsDataContract.PresenceStatus} enum. Possible values + * include: 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasFibreChannelAdapter") + private PresenceStatus hasFibreChannelAdapter; + + /** + * A value indicating whether the VM has a shared VHD attached. String + * value of {SrsDataContract.PresenceStatus} enum. Possible values include: + * 'Unknown', 'Present', 'NotPresent'. + */ + @JsonProperty(value = "hasSharedVhd") + private PresenceStatus hasSharedVhd; + + /** + * Get the source id of the object. + * + * @return the sourceItemId value + */ + public String sourceItemId() { + return this.sourceItemId; + } + + /** + * Set the source id of the object. + * + * @param sourceItemId the sourceItemId value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withSourceItemId(String sourceItemId) { + this.sourceItemId = sourceItemId; + return this; + } + + /** + * Get the id of the object in fabric. + * + * @return the generation value + */ + public String generation() { + return this.generation; + } + + /** + * Set the id of the object in fabric. + * + * @param generation the generation value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withGeneration(String generation) { + this.generation = generation; + return this; + } + + /** + * Get the Last replication time. + * + * @return the osDetails value + */ + public OSDetails osDetails() { + return this.osDetails; + } + + /** + * Set the Last replication time. + * + * @param osDetails the osDetails value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withOsDetails(OSDetails osDetails) { + this.osDetails = osDetails; + return this; + } + + /** + * Get the Last successful failover time. + * + * @return the diskDetails value + */ + public List diskDetails() { + return this.diskDetails; + } + + /** + * Set the Last successful failover time. + * + * @param diskDetails the diskDetails value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withDiskDetails(List diskDetails) { + this.diskDetails = diskDetails; + return this; + } + + /** + * Get a value indicating whether the VM has a physical disk attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasPhysicalDisk value + */ + public PresenceStatus hasPhysicalDisk() { + return this.hasPhysicalDisk; + } + + /** + * Set a value indicating whether the VM has a physical disk attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasPhysicalDisk the hasPhysicalDisk value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withHasPhysicalDisk(PresenceStatus hasPhysicalDisk) { + this.hasPhysicalDisk = hasPhysicalDisk; + return this; + } + + /** + * Get a value indicating whether the VM has a fibre channel adapter attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasFibreChannelAdapter value + */ + public PresenceStatus hasFibreChannelAdapter() { + return this.hasFibreChannelAdapter; + } + + /** + * Set a value indicating whether the VM has a fibre channel adapter attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasFibreChannelAdapter the hasFibreChannelAdapter value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withHasFibreChannelAdapter(PresenceStatus hasFibreChannelAdapter) { + this.hasFibreChannelAdapter = hasFibreChannelAdapter; + return this; + } + + /** + * Get a value indicating whether the VM has a shared VHD attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @return the hasSharedVhd value + */ + public PresenceStatus hasSharedVhd() { + return this.hasSharedVhd; + } + + /** + * Set a value indicating whether the VM has a shared VHD attached. String value of {SrsDataContract.PresenceStatus} enum. Possible values include: 'Unknown', 'Present', 'NotPresent'. + * + * @param hasSharedVhd the hasSharedVhd value to set + * @return the VmmVirtualMachineDetails object itself. + */ + public VmmVirtualMachineDetails withHasSharedVhd(PresenceStatus hasSharedVhd) { + this.hasSharedVhd = hasSharedVhd; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmwareCbtPolicyDetails.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmwareCbtPolicyDetails.java new file mode 100644 index 0000000000000..81bf2c5d6821c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/VmwareCbtPolicyDetails.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeName; + +/** + * VMware Cbt specific policy details. + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "instanceType") +@JsonTypeName("VMwareCbt") +public class VmwareCbtPolicyDetails extends PolicyProviderSpecificDetails { + /** + * The duration in minutes until which the recovery points need to be + * stored. + */ + @JsonProperty(value = "recoveryPointHistoryInMinutes") + private Integer recoveryPointHistoryInMinutes; + + /** + * The app consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "appConsistentFrequencyInMinutes") + private Integer appConsistentFrequencyInMinutes; + + /** + * The crash consistent snapshot frequency in minutes. + */ + @JsonProperty(value = "crashConsistentFrequencyInMinutes") + private Integer crashConsistentFrequencyInMinutes; + + /** + * Get the duration in minutes until which the recovery points need to be stored. + * + * @return the recoveryPointHistoryInMinutes value + */ + public Integer recoveryPointHistoryInMinutes() { + return this.recoveryPointHistoryInMinutes; + } + + /** + * Set the duration in minutes until which the recovery points need to be stored. + * + * @param recoveryPointHistoryInMinutes the recoveryPointHistoryInMinutes value to set + * @return the VmwareCbtPolicyDetails object itself. + */ + public VmwareCbtPolicyDetails withRecoveryPointHistoryInMinutes(Integer recoveryPointHistoryInMinutes) { + this.recoveryPointHistoryInMinutes = recoveryPointHistoryInMinutes; + return this; + } + + /** + * Get the app consistent snapshot frequency in minutes. + * + * @return the appConsistentFrequencyInMinutes value + */ + public Integer appConsistentFrequencyInMinutes() { + return this.appConsistentFrequencyInMinutes; + } + + /** + * Set the app consistent snapshot frequency in minutes. + * + * @param appConsistentFrequencyInMinutes the appConsistentFrequencyInMinutes value to set + * @return the VmwareCbtPolicyDetails object itself. + */ + public VmwareCbtPolicyDetails withAppConsistentFrequencyInMinutes(Integer appConsistentFrequencyInMinutes) { + this.appConsistentFrequencyInMinutes = appConsistentFrequencyInMinutes; + return this; + } + + /** + * Get the crash consistent snapshot frequency in minutes. + * + * @return the crashConsistentFrequencyInMinutes value + */ + public Integer crashConsistentFrequencyInMinutes() { + return this.crashConsistentFrequencyInMinutes; + } + + /** + * Set the crash consistent snapshot frequency in minutes. + * + * @param crashConsistentFrequencyInMinutes the crashConsistentFrequencyInMinutes value to set + * @return the VmwareCbtPolicyDetails object itself. + */ + public VmwareCbtPolicyDetails withCrashConsistentFrequencyInMinutes(Integer crashConsistentFrequencyInMinutes) { + this.crashConsistentFrequencyInMinutes = crashConsistentFrequencyInMinutes; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertImpl.java new file mode 100644 index 0000000000000..dba9cd944aacc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertImpl.java @@ -0,0 +1,136 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Alert; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ConfigureAlertRequestProperties; +import java.util.List; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AlertProperties; +import rx.functions.Func1; + +class AlertImpl extends CreatableUpdatableImpl implements Alert, Alert.Definition, Alert.Update { + private final RecoveryServicesManager manager; + private String alertSettingName; + private ConfigureAlertRequestProperties cproperties; + private ConfigureAlertRequestProperties uproperties; + + AlertImpl(String name, RecoveryServicesManager manager) { + super(name, new AlertInner()); + this.manager = manager; + // Set resource name + this.alertSettingName = name; + // + this.cproperties = new ConfigureAlertRequestProperties(); + this.uproperties = new ConfigureAlertRequestProperties(); + } + + AlertImpl(AlertInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.alertSettingName = inner.name(); + // set resource ancestor and positional variables + this.alertSettingName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationAlertSettings"); + // + this.cproperties = new ConfigureAlertRequestProperties(); + this.uproperties = new ConfigureAlertRequestProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationAlertSettingsInner client = this.manager().inner().replicationAlertSettings(); + return client.createAsync(this.alertSettingName, this.cproperties) + .map(new Func1() { + @Override + public AlertInner call(AlertInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationAlertSettingsInner client = this.manager().inner().replicationAlertSettings(); + return client.createAsync(this.alertSettingName, this.uproperties) + .map(new Func1() { + @Override + public AlertInner call(AlertInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationAlertSettingsInner client = this.manager().inner().replicationAlertSettings(); + return client.getAsync(this.alertSettingName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new ConfigureAlertRequestProperties(); + this.uproperties = new ConfigureAlertRequestProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public AlertProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public AlertImpl withExistingVault() { + return this; + } + + @Override + public AlertImpl withProperties(ConfigureAlertRequestProperties properties) { + if (isInCreateMode()) { + this.cproperties = properties; + } else { + this.uproperties = properties; + } + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertInner.java new file mode 100644 index 0000000000000..d52c77c558e27 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/AlertInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AlertProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Implements the Alert class. + */ +public class AlertInner extends ProxyResource { + /** + * Alert related data. + */ + @JsonProperty(value = "properties") + private AlertProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get alert related data. + * + * @return the properties value + */ + public AlertProperties properties() { + return this.properties; + } + + /** + * Set alert related data. + * + * @param properties the properties value to set + * @return the AlertInner object itself. + */ + public AlertInner withProperties(AlertProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the AlertInner object itself. + */ + public AlertInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventImpl.java new file mode 100644 index 0000000000000..41cbe111e7fb8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Event; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EventProperties; + +class EventImpl extends IndexableRefreshableWrapperImpl implements Event { + private final RecoveryServicesManager manager; + private String eventName; + + EventImpl(EventInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.eventName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationEvents"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationEventsInner client = this.manager().inner().replicationEvents(); + return client.getAsync(this.eventName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public EventProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventInner.java new file mode 100644 index 0000000000000..562e27d7980fd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/EventInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EventProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Implements the Event class. + */ +public class EventInner extends ProxyResource { + /** + * Event related data. + */ + @JsonProperty(value = "properties") + private EventProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get event related data. + * + * @return the properties value + */ + public EventProperties properties() { + return this.properties; + } + + /** + * Set event related data. + * + * @param properties the properties value to set + * @return the EventInner object itself. + */ + public EventInner withProperties(EventProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the EventInner object itself. + */ + public EventInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricImpl.java new file mode 100644 index 0000000000000..9009f3b3ca29b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricImpl.java @@ -0,0 +1,135 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Fabric; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FabricCreationInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FabricProperties; +import rx.functions.Func1; + +class FabricImpl extends CreatableUpdatableImpl implements Fabric, Fabric.Definition, Fabric.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private FabricCreationInputProperties cproperties; + private FabricCreationInputProperties uproperties; + + FabricImpl(String name, RecoveryServicesManager manager) { + super(name, new FabricInner()); + this.manager = manager; + // Set resource name + this.fabricName = name; + // + this.cproperties = new FabricCreationInputProperties(); + this.uproperties = new FabricCreationInputProperties(); + } + + FabricImpl(FabricInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.fabricName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + // + this.cproperties = new FabricCreationInputProperties(); + this.uproperties = new FabricCreationInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationFabricsInner client = this.manager().inner().replicationFabrics(); + return client.createAsync(this.fabricName, this.cproperties) + .map(new Func1() { + @Override + public FabricInner call(FabricInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationFabricsInner client = this.manager().inner().replicationFabrics(); + return client.createAsync(this.fabricName, this.uproperties) + .map(new Func1() { + @Override + public FabricInner call(FabricInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationFabricsInner client = this.manager().inner().replicationFabrics(); + return client.getAsync(this.fabricName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new FabricCreationInputProperties(); + this.uproperties = new FabricCreationInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public FabricProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public FabricImpl withExistingVault() { + return this; + } + + @Override + public FabricImpl withProperties(FabricCreationInputProperties properties) { + if (isInCreateMode()) { + this.cproperties = properties; + } else { + this.uproperties = properties; + } + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricInner.java new file mode 100644 index 0000000000000..b208ad785dd12 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/FabricInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FabricProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Fabric definition. + */ +public class FabricInner extends ProxyResource { + /** + * Fabric related data. + */ + @JsonProperty(value = "properties") + private FabricProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get fabric related data. + * + * @return the properties value + */ + public FabricProperties properties() { + return this.properties; + } + + /** + * Set fabric related data. + * + * @param properties the properties value to set + * @return the FabricInner object itself. + */ + public FabricInner withProperties(FabricProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the FabricInner object itself. + */ + public FabricInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/IdParsingUtils.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/IdParsingUtils.java new file mode 100644 index 0000000000000..c798f6ed7cf8f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/IdParsingUtils.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; +import java.util.Arrays; +import java.util.Iterator; + +class IdParsingUtils { + public static String getValueFromIdByName(String id, String name) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (part.equalsIgnoreCase(name)) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + } + return null; + } + + public static String getValueFromIdByPosition(String id, int pos) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + int index = 0; + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (index == pos) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + index++; + } + return null; + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobImpl.java new file mode 100644 index 0000000000000..76cf9d8a81892 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Job; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.JobProperties; + +class JobImpl extends IndexableRefreshableWrapperImpl implements Job { + private final RecoveryServicesManager manager; + private String jobName; + + JobImpl(JobInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.jobName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationJobs"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationJobsInner client = this.manager().inner().replicationJobs(); + return client.getAsync(this.jobName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public JobProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobInner.java new file mode 100644 index 0000000000000..a1f0f86a452e9 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/JobInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.JobProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Job details. + */ +public class JobInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private JobProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public JobProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the JobInner object itself. + */ + public JobInner withProperties(JobProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the JobInner object itself. + */ + public JobInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkImpl.java new file mode 100644 index 0000000000000..adcf7cd24c884 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkImpl.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.LogicalNetwork; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.LogicalNetworkProperties; + +class LogicalNetworkImpl extends IndexableRefreshableWrapperImpl implements LogicalNetwork { + private final RecoveryServicesManager manager; + private String fabricName; + private String logicalNetworkName; + + LogicalNetworkImpl(LogicalNetworkInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.logicalNetworkName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationLogicalNetworks"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationLogicalNetworksInner client = this.manager().inner().replicationLogicalNetworks(); + return client.getAsync(this.fabricName, this.logicalNetworkName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public LogicalNetworkProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkInner.java new file mode 100644 index 0000000000000..3f0dcf2ff35fb --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/LogicalNetworkInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.LogicalNetworkProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Logical network data model. + */ +public class LogicalNetworkInner extends ProxyResource { + /** + * The Logical Network Properties. + */ + @JsonProperty(value = "properties") + private LogicalNetworkProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the Logical Network Properties. + * + * @return the properties value + */ + public LogicalNetworkProperties properties() { + return this.properties; + } + + /** + * Set the Logical Network Properties. + * + * @param properties the properties value to set + * @return the LogicalNetworkInner object itself. + */ + public LogicalNetworkInner withProperties(LogicalNetworkProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the LogicalNetworkInner object itself. + */ + public LogicalNetworkInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemImpl.java new file mode 100644 index 0000000000000..4fc088d9cd667 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemImpl.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationItem; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateMigrationItemInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableMigrationInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationItemProperties; +import rx.functions.Func1; + +class MigrationItemImpl extends CreatableUpdatableImpl implements MigrationItem, MigrationItem.Definition, MigrationItem.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String migrationItemName; + private EnableMigrationInputProperties cproperties; + private UpdateMigrationItemInputProperties uproperties; + + MigrationItemImpl(String name, RecoveryServicesManager manager) { + super(name, new MigrationItemInner()); + this.manager = manager; + // Set resource name + this.migrationItemName = name; + // + this.cproperties = new EnableMigrationInputProperties(); + this.uproperties = new UpdateMigrationItemInputProperties(); + } + + MigrationItemImpl(MigrationItemInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.migrationItemName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.migrationItemName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationMigrationItems"); + // + this.cproperties = new EnableMigrationInputProperties(); + this.uproperties = new UpdateMigrationItemInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationMigrationItemsInner client = this.manager().inner().replicationMigrationItems(); + return client.createAsync(this.fabricName, this.protectionContainerName, this.migrationItemName, this.cproperties) + .map(new Func1() { + @Override + public MigrationItemInner call(MigrationItemInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationMigrationItemsInner client = this.manager().inner().replicationMigrationItems(); + return client.updateAsync(this.fabricName, this.protectionContainerName, this.migrationItemName, this.uproperties) + .map(new Func1() { + @Override + public MigrationItemInner call(MigrationItemInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationMigrationItemsInner client = this.manager().inner().replicationMigrationItems(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.migrationItemName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new EnableMigrationInputProperties(); + this.uproperties = new UpdateMigrationItemInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public MigrationItemProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public MigrationItemImpl withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName) { + this.fabricName = fabricName; + this.protectionContainerName = protectionContainerName; + return this; + } + + @Override + public MigrationItemImpl withProperties(EnableMigrationInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public MigrationItemImpl withProperties(UpdateMigrationItemInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemInner.java new file mode 100644 index 0000000000000..69a38011f0fc7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationItemInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationItemProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Migration item. + */ +public class MigrationItemInner extends ProxyResource { + /** + * The migration item properties. + */ + @JsonProperty(value = "properties") + private MigrationItemProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the migration item properties. + * + * @return the properties value + */ + public MigrationItemProperties properties() { + return this.properties; + } + + /** + * Set the migration item properties. + * + * @param properties the properties value to set + * @return the MigrationItemInner object itself. + */ + public MigrationItemInner withProperties(MigrationItemProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the MigrationItemInner object itself. + */ + public MigrationItemInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointImpl.java new file mode 100644 index 0000000000000..ef23a4e1a5698 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoint; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPointProperties; + +class MigrationRecoveryPointImpl extends IndexableRefreshableWrapperImpl implements MigrationRecoveryPoint { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String migrationItemName; + private String migrationRecoveryPointName; + + MigrationRecoveryPointImpl(MigrationRecoveryPointInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.migrationItemName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationMigrationItems"); + this.migrationRecoveryPointName = IdParsingUtils.getValueFromIdByName(inner.id(), "migrationRecoveryPoints"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + MigrationRecoveryPointsInner client = this.manager().inner().migrationRecoveryPoints(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.migrationItemName, this.migrationRecoveryPointName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public MigrationRecoveryPointProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointInner.java new file mode 100644 index 0000000000000..17f454c9b90b5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPointProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Recovery point for a migration item. + */ +public class MigrationRecoveryPointInner extends ProxyResource { + /** + * Recovery point properties. + */ + @JsonProperty(value = "properties") + private MigrationRecoveryPointProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get recovery point properties. + * + * @return the properties value + */ + public MigrationRecoveryPointProperties properties() { + return this.properties; + } + + /** + * Set recovery point properties. + * + * @param properties the properties value to set + * @return the MigrationRecoveryPointInner object itself. + */ + public MigrationRecoveryPointInner withProperties(MigrationRecoveryPointProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the MigrationRecoveryPointInner object itself. + */ + public MigrationRecoveryPointInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsImpl.java new file mode 100644 index 0000000000000..bea06f712436d --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoints; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoint; + +class MigrationRecoveryPointsImpl extends WrapperImpl implements MigrationRecoveryPoints { + private final RecoveryServicesManager manager; + + MigrationRecoveryPointsImpl(RecoveryServicesManager manager) { + super(manager.inner().migrationRecoveryPoints()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private MigrationRecoveryPointImpl wrapModel(MigrationRecoveryPointInner inner) { + return new MigrationRecoveryPointImpl(inner, manager()); + } + + @Override + public Observable listByReplicationMigrationItemsAsync(final String fabricName, final String protectionContainerName, final String migrationItemName) { + MigrationRecoveryPointsInner client = this.inner(); + return client.listByReplicationMigrationItemsAsync(fabricName, protectionContainerName, migrationItemName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public MigrationRecoveryPoint call(MigrationRecoveryPointInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName) { + MigrationRecoveryPointsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, migrationItemName, migrationRecoveryPointName) + .map(new Func1() { + @Override + public MigrationRecoveryPoint call(MigrationRecoveryPointInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsInner.java new file mode 100644 index 0000000000000..8a85397331728 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/MigrationRecoveryPointsInner.java @@ -0,0 +1,428 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in MigrationRecoveryPoints. + */ +public class MigrationRecoveryPointsInner { + /** The Retrofit service to perform REST calls. */ + private MigrationRecoveryPointsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of MigrationRecoveryPointsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public MigrationRecoveryPointsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(MigrationRecoveryPointsService.class); + this.client = client; + } + + /** + * The interface defining all the services for MigrationRecoveryPoints to be + * used by Retrofit to perform actually REST calls. + */ + interface MigrationRecoveryPointsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoints listByReplicationMigrationItems" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/migrationRecoveryPoints") + Observable> listByReplicationMigrationItems(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoints get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/migrationRecoveryPoints/{migrationRecoveryPointName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Path("migrationRecoveryPointName") String migrationRecoveryPointName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoints listByReplicationMigrationItemsNext" }) + @GET + Observable> listByReplicationMigrationItemsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the recovery points for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationRecoveryPointInner> object if successful. + */ + public PagedList listByReplicationMigrationItems(final String fabricName, final String protectionContainerName, final String migrationItemName) { + ServiceResponse> response = listByReplicationMigrationItemsSinglePageAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the recovery points for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationMigrationItemsAsync(final String fabricName, final String protectionContainerName, final String migrationItemName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationMigrationItemsSinglePageAsync(fabricName, protectionContainerName, migrationItemName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the recovery points for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationRecoveryPointInner> object + */ + public Observable> listByReplicationMigrationItemsAsync(final String fabricName, final String protectionContainerName, final String migrationItemName) { + return listByReplicationMigrationItemsWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the recovery points for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationRecoveryPointInner> object + */ + public Observable>> listByReplicationMigrationItemsWithServiceResponseAsync(final String fabricName, final String protectionContainerName, final String migrationItemName) { + return listByReplicationMigrationItemsSinglePageAsync(fabricName, protectionContainerName, migrationItemName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationMigrationItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the recovery points for a migration item. + * + ServiceResponse> * @param fabricName Fabric unique name. + ServiceResponse> * @param protectionContainerName Protection container name. + ServiceResponse> * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationRecoveryPointInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationMigrationItemsSinglePageAsync(final String fabricName, final String protectionContainerName, final String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationMigrationItems(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationMigrationItemsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationMigrationItemsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets a recovery point for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param migrationRecoveryPointName The migration recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationRecoveryPointInner object if successful. + */ + public MigrationRecoveryPointInner get(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, migrationRecoveryPointName).toBlocking().single().body(); + } + + /** + * Gets a recovery point for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param migrationRecoveryPointName The migration recovery point name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, migrationRecoveryPointName), serviceCallback); + } + + /** + * Gets a recovery point for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param migrationRecoveryPointName The migration recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationRecoveryPointInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, migrationRecoveryPointName).map(new Func1, MigrationRecoveryPointInner>() { + @Override + public MigrationRecoveryPointInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a recovery point for a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param migrationRecoveryPointName The migration recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationRecoveryPointInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, String migrationRecoveryPointName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (migrationRecoveryPointName == null) { + throw new IllegalArgumentException("Parameter migrationRecoveryPointName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, migrationRecoveryPointName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the recovery points for a migration item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationRecoveryPointInner> object if successful. + */ + public PagedList listByReplicationMigrationItemsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the recovery points for a migration item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationMigrationItemsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the recovery points for a migration item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationRecoveryPointInner> object + */ + public Observable> listByReplicationMigrationItemsNextAsync(final String nextPageLink) { + return listByReplicationMigrationItemsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the recovery points for a migration item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationRecoveryPointInner> object + */ + public Observable>> listByReplicationMigrationItemsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationMigrationItemsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationMigrationItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the recovery points for a migration item. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationRecoveryPointInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationMigrationItemsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationMigrationItemsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationMigrationItemsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationMigrationItemsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkImpl.java new file mode 100644 index 0000000000000..06f310b487e71 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkImpl.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Network; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkProperties; + +class NetworkImpl extends IndexableRefreshableWrapperImpl implements Network { + private final RecoveryServicesManager manager; + private String fabricName; + private String networkName; + + NetworkImpl(NetworkInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.networkName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationNetworks"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationNetworksInner client = this.manager().inner().replicationNetworks(); + return client.getAsync(this.fabricName, this.networkName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public NetworkProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkInner.java new file mode 100644 index 0000000000000..645e8393f0e62 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Network model. + */ +public class NetworkInner extends ProxyResource { + /** + * The Network Properties. + */ + @JsonProperty(value = "properties") + private NetworkProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the Network Properties. + * + * @return the properties value + */ + public NetworkProperties properties() { + return this.properties; + } + + /** + * Set the Network Properties. + * + * @param properties the properties value to set + * @return the NetworkInner object itself. + */ + public NetworkInner withProperties(NetworkProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the NetworkInner object itself. + */ + public NetworkInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingImpl.java new file mode 100644 index 0000000000000..55cff81329b85 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingImpl.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkMapping; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateNetworkMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateNetworkMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkMappingProperties; +import rx.functions.Func1; + +class NetworkMappingImpl extends CreatableUpdatableImpl implements NetworkMapping, NetworkMapping.Definition, NetworkMapping.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String networkName; + private String networkMappingName; + private CreateNetworkMappingInputProperties cproperties; + private UpdateNetworkMappingInputProperties uproperties; + + NetworkMappingImpl(String name, RecoveryServicesManager manager) { + super(name, new NetworkMappingInner()); + this.manager = manager; + // Set resource name + this.networkMappingName = name; + // + this.cproperties = new CreateNetworkMappingInputProperties(); + this.uproperties = new UpdateNetworkMappingInputProperties(); + } + + NetworkMappingImpl(NetworkMappingInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.networkMappingName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.networkName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationNetworks"); + this.networkMappingName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationNetworkMappings"); + // + this.cproperties = new CreateNetworkMappingInputProperties(); + this.uproperties = new UpdateNetworkMappingInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationNetworkMappingsInner client = this.manager().inner().replicationNetworkMappings(); + return client.createAsync(this.fabricName, this.networkName, this.networkMappingName, this.cproperties) + .map(new Func1() { + @Override + public NetworkMappingInner call(NetworkMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationNetworkMappingsInner client = this.manager().inner().replicationNetworkMappings(); + return client.updateAsync(this.fabricName, this.networkName, this.networkMappingName, this.uproperties) + .map(new Func1() { + @Override + public NetworkMappingInner call(NetworkMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationNetworkMappingsInner client = this.manager().inner().replicationNetworkMappings(); + return client.getAsync(this.fabricName, this.networkName, this.networkMappingName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new CreateNetworkMappingInputProperties(); + this.uproperties = new UpdateNetworkMappingInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public NetworkMappingProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public NetworkMappingImpl withExistingReplicationNetwork(String fabricName, String networkName) { + this.fabricName = fabricName; + this.networkName = networkName; + return this; + } + + @Override + public NetworkMappingImpl withProperties(CreateNetworkMappingInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public NetworkMappingImpl withProperties(UpdateNetworkMappingInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingInner.java new file mode 100644 index 0000000000000..39f0716eafb1c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/NetworkMappingInner.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkMappingProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Network Mapping model. Ideally it should have been possible to inherit this + * class from prev version in InheritedModels as long as there is no difference + * in structure or method signature. Since there were no base Models for + * certain fields and methods viz NetworkMappingProperties and Load with + * required return type, the class has been introduced in its entirety with + * references to base models to facilitate extensions in subsequent versions. + */ +public class NetworkMappingInner extends ProxyResource { + /** + * The Network Mapping Properties. + */ + @JsonProperty(value = "properties") + private NetworkMappingProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the Network Mapping Properties. + * + * @return the properties value + */ + public NetworkMappingProperties properties() { + return this.properties; + } + + /** + * Set the Network Mapping Properties. + * + * @param properties the properties value to set + * @return the NetworkMappingInner object itself. + */ + public NetworkMappingInner withProperties(NetworkMappingProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the NetworkMappingInner object itself. + */ + public NetworkMappingInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryImpl.java new file mode 100644 index 0000000000000..10f203c7666cd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryImpl.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.OperationsDiscovery; +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Display; + +class OperationsDiscoveryImpl extends WrapperImpl implements OperationsDiscovery { + private final RecoveryServicesManager manager; + + OperationsDiscoveryImpl(OperationsDiscoveryInner inner, RecoveryServicesManager manager) { + super(inner); + this.manager = manager; + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + + + @Override + public Display display() { + return this.inner().display(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public String origin() { + return this.inner().origin(); + } + + @Override + public Object properties() { + return this.inner().properties(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryInner.java new file mode 100644 index 0000000000000..5434c860a3bac --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsDiscoveryInner.java @@ -0,0 +1,142 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Display; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Operations discovery class. + */ +public class OperationsDiscoveryInner { + /** + * Name of the API. The name of the operation being performed on this + * particular object. It should match the action name that appears in RBAC + * / the event service. Examples of operations include: * + * Microsoft.Compute/virtualMachine/capture/action * + * Microsoft.Compute/virtualMachine/restart/action * + * Microsoft.Compute/virtualMachine/write * + * Microsoft.Compute/virtualMachine/read * + * Microsoft.Compute/virtualMachine/delete Each action should include, in + * order: (1) Resource Provider Namespace (2) Type hierarchy for which the + * action applies (e.g. server/databases for a SQL Azure database) (3) + * Read, Write, Action or Delete indicating which type applies. If it is a + * PUT/PATCH on a collection or named value, Write should be used. If it is + * a GET, Read should be used. If it is a DELETE, Delete should be used. If + * it is a POST, Action should be used. As a note: all resource providers + * would need to include the "{Resource Provider + * Namespace}/register/action" operation in their response. This API is + * used to register for their service, and should include details about the + * operation (e.g. a localized name for the resource provider + any special + * considerations like PII release). + */ + @JsonProperty(value = "name") + private String name; + + /** + * Object type. + */ + @JsonProperty(value = "display") + private Display display; + + /** + * Origin. The intended executor of the operation; governs the display of + * the operation in the RBAC UX and the audit logs UX. Default value is + * "user,system". + */ + @JsonProperty(value = "origin") + private String origin; + + /** + * Properties. Reserved for future use. + */ + @JsonProperty(value = "properties") + private Object properties; + + /** + * Get name of the API. The name of the operation being performed on this particular object. It should match the action name that appears in RBAC / the event service. Examples of operations include: * Microsoft.Compute/virtualMachine/capture/action * Microsoft.Compute/virtualMachine/restart/action * Microsoft.Compute/virtualMachine/write * Microsoft.Compute/virtualMachine/read * Microsoft.Compute/virtualMachine/delete Each action should include, in order: (1) Resource Provider Namespace (2) Type hierarchy for which the action applies (e.g. server/databases for a SQL Azure database) (3) Read, Write, Action or Delete indicating which type applies. If it is a PUT/PATCH on a collection or named value, Write should be used. If it is a GET, Read should be used. If it is a DELETE, Delete should be used. If it is a POST, Action should be used. As a note: all resource providers would need to include the "{Resource Provider Namespace}/register/action" operation in their response. This API is used to register for their service, and should include details about the operation (e.g. a localized name for the resource provider + any special considerations like PII release). + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set name of the API. The name of the operation being performed on this particular object. It should match the action name that appears in RBAC / the event service. Examples of operations include: * Microsoft.Compute/virtualMachine/capture/action * Microsoft.Compute/virtualMachine/restart/action * Microsoft.Compute/virtualMachine/write * Microsoft.Compute/virtualMachine/read * Microsoft.Compute/virtualMachine/delete Each action should include, in order: (1) Resource Provider Namespace (2) Type hierarchy for which the action applies (e.g. server/databases for a SQL Azure database) (3) Read, Write, Action or Delete indicating which type applies. If it is a PUT/PATCH on a collection or named value, Write should be used. If it is a GET, Read should be used. If it is a DELETE, Delete should be used. If it is a POST, Action should be used. As a note: all resource providers would need to include the "{Resource Provider Namespace}/register/action" operation in their response. This API is used to register for their service, and should include details about the operation (e.g. a localized name for the resource provider + any special considerations like PII release). + * + * @param name the name value to set + * @return the OperationsDiscoveryInner object itself. + */ + public OperationsDiscoveryInner withName(String name) { + this.name = name; + return this; + } + + /** + * Get object type. + * + * @return the display value + */ + public Display display() { + return this.display; + } + + /** + * Set object type. + * + * @param display the display value to set + * @return the OperationsDiscoveryInner object itself. + */ + public OperationsDiscoveryInner withDisplay(Display display) { + this.display = display; + return this; + } + + /** + * Get origin. The intended executor of the operation; governs the display of the operation in the RBAC UX and the audit logs UX. Default value is "user,system". + * + * @return the origin value + */ + public String origin() { + return this.origin; + } + + /** + * Set origin. The intended executor of the operation; governs the display of the operation in the RBAC UX and the audit logs UX. Default value is "user,system". + * + * @param origin the origin value to set + * @return the OperationsDiscoveryInner object itself. + */ + public OperationsDiscoveryInner withOrigin(String origin) { + this.origin = origin; + return this; + } + + /** + * Get properties. Reserved for future use. + * + * @return the properties value + */ + public Object properties() { + return this.properties; + } + + /** + * Set properties. Reserved for future use. + * + * @param properties the properties value to set + * @return the OperationsDiscoveryInner object itself. + */ + public OperationsDiscoveryInner withProperties(Object properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsImpl.java new file mode 100644 index 0000000000000..1942f1cfdfc9b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsImpl.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * jkl + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Operations; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.PagedList; +import com.microsoft.azure.Page; +import com.microsoft.azure.arm.utils.PagedListConverter; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.OperationsDiscovery; + +class OperationsImpl extends WrapperImpl implements Operations { + private PagedListConverter converter; + private final RecoveryServicesManager manager; + + OperationsImpl(RecoveryServicesManager manager) { + super(manager.inner().operations()); + this.manager = manager; + this.converter = new PagedListConverter() { + @Override + public Observable typeConvertAsync(OperationsDiscoveryInner inner) { + return Observable.just((OperationsDiscovery) wrapModel(inner)); + } + }; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private OperationsDiscoveryImpl wrapModel(OperationsDiscoveryInner inner) { + return new OperationsDiscoveryImpl(inner, manager()); + } + + @Override + public PagedList list() { + OperationsInner client = this.inner(); + return converter.convert(client.listByResourceGroup()); + } + + @Override + public Observable listAsync() { + OperationsInner client = this.inner(); + return client.listByResourceGroupAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public OperationsDiscovery call(OperationsDiscoveryInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsInner.java new file mode 100644 index 0000000000000..3e8a6d39b8a66 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/OperationsInner.java @@ -0,0 +1,300 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in Operations. + */ +public class OperationsInner { + /** The Retrofit service to perform REST calls. */ + private OperationsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of OperationsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public OperationsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(OperationsService.class); + this.client = client; + } + + /** + * The interface defining all the services for Operations to be + * used by Retrofit to perform actually REST calls. + */ + interface OperationsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Operations listByResourceGroup" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/operations") + Observable> listByResourceGroup(@Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Operations listByResourceGroupNext" }) + @GET + Observable> listByResourceGroupNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<OperationsDiscoveryInner> object if successful. + */ + public PagedList listByResourceGroup() { + ServiceResponse> response = listByResourceGroupSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationsDiscoveryInner> object + */ + public Observable> listByResourceGroupAsync() { + return listByResourceGroupWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationsDiscoveryInner> object + */ + public Observable>> listByResourceGroupWithServiceResponseAsync() { + return listByResourceGroupSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<OperationsDiscoveryInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupSinglePageAsync() { + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByResourceGroup(this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<OperationsDiscoveryInner> object if successful. + */ + public PagedList listByResourceGroupNext(final String nextPageLink) { + ServiceResponse> response = listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationsDiscoveryInner> object + */ + public Observable> listByResourceGroupNextAsync(final String nextPageLink) { + return listByResourceGroupNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationsDiscoveryInner> object + */ + public Observable>> listByResourceGroupNextWithServiceResponseAsync(final String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Returns the list of available operations. + * Operation to return the list of available operations. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<OperationsDiscoveryInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByResourceGroupNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PageImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PageImpl.java new file mode 100644 index 0000000000000..c8a0578db774b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PageImpl.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.Page; +import java.util.List; + +/** + * An instance of this class defines a page of Azure resources and a link to + * get the next page of resources, if any. + * + * @param type of Azure resource + */ +public class PageImpl implements Page { + /** + * The link to the next page. + */ + @JsonProperty("nextLink") + private String nextPageLink; + + /** + * The list of items. + */ + @JsonProperty("value") + private List items; + + /** + * Gets the link to the next page. + * + * @return the link to the next page. + */ + @Override + public String nextPageLink() { + return this.nextPageLink; + } + + /** + * Gets the list of items. + * + * @return the list of items in {@link List}. + */ + @Override + public List items() { + return items; + } + + /** + * Sets the link to the next page. + * + * @param nextPageLink the link to the next page. + * @return this Page object itself. + */ + public PageImpl setNextPageLink(String nextPageLink) { + this.nextPageLink = nextPageLink; + return this; + } + + /** + * Sets the list of items. + * + * @param items the list of items in {@link List}. + * @return this Page object itself. + */ + public PageImpl setItems(List items) { + this.items = items; + return this; + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyImpl.java new file mode 100644 index 0000000000000..08dd10b9f6d54 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyImpl.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Policy; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdatePolicyInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreatePolicyInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.PolicyProperties; +import rx.functions.Func1; + +class PolicyImpl extends CreatableUpdatableImpl implements Policy, Policy.Definition, Policy.Update { + private final RecoveryServicesManager manager; + private String policyName; + private CreatePolicyInputProperties cproperties; + private UpdatePolicyInputProperties uproperties; + + PolicyImpl(String name, RecoveryServicesManager manager) { + super(name, new PolicyInner()); + this.manager = manager; + // Set resource name + this.policyName = name; + // + this.cproperties = new CreatePolicyInputProperties(); + this.uproperties = new UpdatePolicyInputProperties(); + } + + PolicyImpl(PolicyInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.policyName = inner.name(); + // set resource ancestor and positional variables + this.policyName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationPolicies"); + // + this.cproperties = new CreatePolicyInputProperties(); + this.uproperties = new UpdatePolicyInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationPoliciesInner client = this.manager().inner().replicationPolicies(); + return client.createAsync(this.policyName, this.cproperties) + .map(new Func1() { + @Override + public PolicyInner call(PolicyInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationPoliciesInner client = this.manager().inner().replicationPolicies(); + return client.updateAsync(this.policyName, this.uproperties) + .map(new Func1() { + @Override + public PolicyInner call(PolicyInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationPoliciesInner client = this.manager().inner().replicationPolicies(); + return client.getAsync(this.policyName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new CreatePolicyInputProperties(); + this.uproperties = new UpdatePolicyInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public PolicyProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public PolicyImpl withExistingVault() { + return this; + } + + @Override + public PolicyImpl withProperties(CreatePolicyInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public PolicyImpl withProperties(UpdatePolicyInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyInner.java new file mode 100644 index 0000000000000..668c6dc9be053 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/PolicyInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.PolicyProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Protection profile details. + */ +public class PolicyInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private PolicyProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public PolicyProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the PolicyInner object itself. + */ + public PolicyInner withProperties(PolicyProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the PolicyInner object itself. + */ + public PolicyInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemImpl.java new file mode 100644 index 0000000000000..faae0de8a0aec --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemImpl.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectableItem; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectableItemProperties; + +class ProtectableItemImpl extends IndexableRefreshableWrapperImpl implements ProtectableItem { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String protectableItemName; + + ProtectableItemImpl(ProtectableItemInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.protectableItemName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectableItems"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationProtectableItemsInner client = this.manager().inner().replicationProtectableItems(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.protectableItemName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public ProtectableItemProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemInner.java new file mode 100644 index 0000000000000..72bd6ffc91512 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectableItemInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectableItemProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Replication protected item. + */ +public class ProtectableItemInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private ProtectableItemProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public ProtectableItemProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the ProtectableItemInner object itself. + */ + public ProtectableItemInner withProperties(ProtectableItemProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the ProtectableItemInner object itself. + */ + public ProtectableItemInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerImpl.java new file mode 100644 index 0000000000000..f129ea450d7d4 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerImpl.java @@ -0,0 +1,139 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainer; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerInputProperties; +import java.util.List; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerProperties; +import rx.functions.Func1; + +class ProtectionContainerImpl extends CreatableUpdatableImpl implements ProtectionContainer, ProtectionContainer.Definition, ProtectionContainer.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private CreateProtectionContainerInputProperties cproperties; + private CreateProtectionContainerInputProperties uproperties; + + ProtectionContainerImpl(String name, RecoveryServicesManager manager) { + super(name, new ProtectionContainerInner()); + this.manager = manager; + // Set resource name + this.protectionContainerName = name; + // + this.cproperties = new CreateProtectionContainerInputProperties(); + this.uproperties = new CreateProtectionContainerInputProperties(); + } + + ProtectionContainerImpl(ProtectionContainerInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.protectionContainerName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + // + this.cproperties = new CreateProtectionContainerInputProperties(); + this.uproperties = new CreateProtectionContainerInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationProtectionContainersInner client = this.manager().inner().replicationProtectionContainers(); + return client.createAsync(this.fabricName, this.protectionContainerName, this.cproperties) + .map(new Func1() { + @Override + public ProtectionContainerInner call(ProtectionContainerInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationProtectionContainersInner client = this.manager().inner().replicationProtectionContainers(); + return client.createAsync(this.fabricName, this.protectionContainerName, this.uproperties) + .map(new Func1() { + @Override + public ProtectionContainerInner call(ProtectionContainerInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationProtectionContainersInner client = this.manager().inner().replicationProtectionContainers(); + return client.getAsync(this.fabricName, this.protectionContainerName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new CreateProtectionContainerInputProperties(); + this.uproperties = new CreateProtectionContainerInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public ProtectionContainerProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public ProtectionContainerImpl withExistingReplicationFabric(String fabricName) { + this.fabricName = fabricName; + return this; + } + + @Override + public ProtectionContainerImpl withProperties(CreateProtectionContainerInputProperties properties) { + if (isInCreateMode()) { + this.cproperties = properties; + } else { + this.uproperties = properties; + } + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerInner.java new file mode 100644 index 0000000000000..f5d5a85790b38 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Protection container details. + */ +public class ProtectionContainerInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private ProtectionContainerProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public ProtectionContainerProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the ProtectionContainerInner object itself. + */ + public ProtectionContainerInner withProperties(ProtectionContainerProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the ProtectionContainerInner object itself. + */ + public ProtectionContainerInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingImpl.java new file mode 100644 index 0000000000000..af475718e55dd --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingImpl.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerMapping; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateProtectionContainerMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerMappingProperties; +import rx.functions.Func1; + +class ProtectionContainerMappingImpl extends CreatableUpdatableImpl implements ProtectionContainerMapping, ProtectionContainerMapping.Definition, ProtectionContainerMapping.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String mappingName; + private CreateProtectionContainerMappingInputProperties cproperties; + private UpdateProtectionContainerMappingInputProperties uproperties; + + ProtectionContainerMappingImpl(String name, RecoveryServicesManager manager) { + super(name, new ProtectionContainerMappingInner()); + this.manager = manager; + // Set resource name + this.mappingName = name; + // + this.cproperties = new CreateProtectionContainerMappingInputProperties(); + this.uproperties = new UpdateProtectionContainerMappingInputProperties(); + } + + ProtectionContainerMappingImpl(ProtectionContainerMappingInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.mappingName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.mappingName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainerMappings"); + // + this.cproperties = new CreateProtectionContainerMappingInputProperties(); + this.uproperties = new UpdateProtectionContainerMappingInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationProtectionContainerMappingsInner client = this.manager().inner().replicationProtectionContainerMappings(); + return client.createAsync(this.fabricName, this.protectionContainerName, this.mappingName, this.cproperties) + .map(new Func1() { + @Override + public ProtectionContainerMappingInner call(ProtectionContainerMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationProtectionContainerMappingsInner client = this.manager().inner().replicationProtectionContainerMappings(); + return client.updateAsync(this.fabricName, this.protectionContainerName, this.mappingName, this.uproperties) + .map(new Func1() { + @Override + public ProtectionContainerMappingInner call(ProtectionContainerMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationProtectionContainerMappingsInner client = this.manager().inner().replicationProtectionContainerMappings(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.mappingName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new CreateProtectionContainerMappingInputProperties(); + this.uproperties = new UpdateProtectionContainerMappingInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public ProtectionContainerMappingProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public ProtectionContainerMappingImpl withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName) { + this.fabricName = fabricName; + this.protectionContainerName = protectionContainerName; + return this; + } + + @Override + public ProtectionContainerMappingImpl withProperties(CreateProtectionContainerMappingInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public ProtectionContainerMappingImpl withProperties(UpdateProtectionContainerMappingInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingInner.java new file mode 100644 index 0000000000000..81889e4215aac --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ProtectionContainerMappingInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerMappingProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Protection container mapping object. + */ +public class ProtectionContainerMappingInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private ProtectionContainerMappingProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public ProtectionContainerMappingProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the ProtectionContainerMappingInner object itself. + */ + public ProtectionContainerMappingInner withProperties(ProtectionContainerMappingProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the ProtectionContainerMappingInner object itself. + */ + public ProtectionContainerMappingInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanImpl.java new file mode 100644 index 0000000000000..1a3994aca4946 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanImpl.java @@ -0,0 +1,139 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlan; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateRecoveryPlanInputProperties; +import java.util.List; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateRecoveryPlanInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanProperties; +import rx.functions.Func1; + +class RecoveryPlanImpl extends CreatableUpdatableImpl implements RecoveryPlan, RecoveryPlan.Definition, RecoveryPlan.Update { + private final RecoveryServicesManager manager; + private String recoveryPlanName; + private CreateRecoveryPlanInputProperties cproperties; + private UpdateRecoveryPlanInputProperties uproperties; + + RecoveryPlanImpl(String name, RecoveryServicesManager manager) { + super(name, new RecoveryPlanInner()); + this.manager = manager; + // Set resource name + this.recoveryPlanName = name; + // + this.cproperties = new CreateRecoveryPlanInputProperties(); + this.uproperties = new UpdateRecoveryPlanInputProperties(); + } + + RecoveryPlanImpl(RecoveryPlanInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.recoveryPlanName = inner.name(); + // set resource ancestor and positional variables + this.recoveryPlanName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationRecoveryPlans"); + // + this.cproperties = new CreateRecoveryPlanInputProperties(); + this.uproperties = new UpdateRecoveryPlanInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationRecoveryPlansInner client = this.manager().inner().replicationRecoveryPlans(); + return client.createAsync(this.recoveryPlanName, this.cproperties) + .map(new Func1() { + @Override + public RecoveryPlanInner call(RecoveryPlanInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationRecoveryPlansInner client = this.manager().inner().replicationRecoveryPlans(); + return client.updateAsync(this.recoveryPlanName, this.uproperties) + .map(new Func1() { + @Override + public RecoveryPlanInner call(RecoveryPlanInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationRecoveryPlansInner client = this.manager().inner().replicationRecoveryPlans(); + return client.getAsync(this.recoveryPlanName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new CreateRecoveryPlanInputProperties(); + this.uproperties = new UpdateRecoveryPlanInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public RecoveryPlanProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public RecoveryPlanImpl withExistingVault() { + return this; + } + + @Override + public RecoveryPlanImpl withProperties(CreateRecoveryPlanInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public RecoveryPlanImpl withProperties(UpdateRecoveryPlanInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanInner.java new file mode 100644 index 0000000000000..0b92b6419cdfc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPlanInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Recovery plan details. + */ +public class RecoveryPlanInner extends ProxyResource { + /** + * The custom details. + */ + @JsonProperty(value = "properties") + private RecoveryPlanProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom details. + * + * @return the properties value + */ + public RecoveryPlanProperties properties() { + return this.properties; + } + + /** + * Set the custom details. + * + * @param properties the properties value to set + * @return the RecoveryPlanInner object itself. + */ + public RecoveryPlanInner withProperties(RecoveryPlanProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the RecoveryPlanInner object itself. + */ + public RecoveryPlanInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointImpl.java new file mode 100644 index 0000000000000..523b1d1122d1b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointImpl.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoint; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPointProperties; + +class RecoveryPointImpl extends IndexableRefreshableWrapperImpl implements RecoveryPoint { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String replicatedProtectedItemName; + private String recoveryPointName; + + RecoveryPointImpl(RecoveryPointInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.replicatedProtectedItemName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectedItems"); + this.recoveryPointName = IdParsingUtils.getValueFromIdByName(inner.id(), "recoveryPoints"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + RecoveryPointsInner client = this.manager().inner().recoveryPoints(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.replicatedProtectedItemName, this.recoveryPointName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public RecoveryPointProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointInner.java new file mode 100644 index 0000000000000..223908daf8121 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPointProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Base class representing a recovery point. + */ +public class RecoveryPointInner extends ProxyResource { + /** + * Recovery point related data. + */ + @JsonProperty(value = "properties") + private RecoveryPointProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get recovery point related data. + * + * @return the properties value + */ + public RecoveryPointProperties properties() { + return this.properties; + } + + /** + * Set recovery point related data. + * + * @param properties the properties value to set + * @return the RecoveryPointInner object itself. + */ + public RecoveryPointInner withProperties(RecoveryPointProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the RecoveryPointInner object itself. + */ + public RecoveryPointInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsImpl.java new file mode 100644 index 0000000000000..8b4a8fc8a660c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoints; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoint; + +class RecoveryPointsImpl extends WrapperImpl implements RecoveryPoints { + private final RecoveryServicesManager manager; + + RecoveryPointsImpl(RecoveryServicesManager manager) { + super(manager.inner().recoveryPoints()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private RecoveryPointImpl wrapModel(RecoveryPointInner inner) { + return new RecoveryPointImpl(inner, manager()); + } + + @Override + public Observable listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + RecoveryPointsInner client = this.inner(); + return client.listByReplicationProtectedItemsAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public RecoveryPoint call(RecoveryPointInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName) { + RecoveryPointsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, replicatedProtectedItemName, recoveryPointName) + .map(new Func1() { + @Override + public RecoveryPoint call(RecoveryPointInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsInner.java new file mode 100644 index 0000000000000..b8d951cf0a49c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryPointsInner.java @@ -0,0 +1,442 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in RecoveryPoints. + */ +public class RecoveryPointsInner { + /** The Retrofit service to perform REST calls. */ + private RecoveryPointsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of RecoveryPointsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public RecoveryPointsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(RecoveryPointsService.class); + this.client = client; + } + + /** + * The interface defining all the services for RecoveryPoints to be + * used by Retrofit to perform actually REST calls. + */ + interface RecoveryPointsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoints listByReplicationProtectedItems" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/recoveryPoints") + Observable> listByReplicationProtectedItems(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoints get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/recoveryPoints/{recoveryPointName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Path("recoveryPointName") String recoveryPointName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoints listByReplicationProtectedItemsNext" }) + @GET + Observable> listByReplicationProtectedItemsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryPointInner> object if successful. + */ + public PagedList listByReplicationProtectedItems(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + ServiceResponse> response = listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPointInner> object + */ + public Observable> listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + return listByReplicationProtectedItemsWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPointInner> object + */ + public Observable>> listByReplicationProtectedItemsWithServiceResponseAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + return listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + ServiceResponse> * @param fabricName The fabric name. + ServiceResponse> * @param protectionContainerName The protection container name. + ServiceResponse> * @param replicatedProtectedItemName The replication protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryPointInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectedItemsSinglePageAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectedItems(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectedItemsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectedItemsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Get a recovery point. + * Get the details of specified recovery point. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param recoveryPointName The recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPointInner object if successful. + */ + public RecoveryPointInner get(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, recoveryPointName).toBlocking().single().body(); + } + + /** + * Get a recovery point. + * Get the details of specified recovery point. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param recoveryPointName The recovery point name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, recoveryPointName), serviceCallback); + } + + /** + * Get a recovery point. + * Get the details of specified recovery point. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param recoveryPointName The recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPointInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, recoveryPointName).map(new Func1, RecoveryPointInner>() { + @Override + public RecoveryPointInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Get a recovery point. + * Get the details of specified recovery point. + * + * @param fabricName The fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replication protected item's name. + * @param recoveryPointName The recovery point name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPointInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, String recoveryPointName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (recoveryPointName == null) { + throw new IllegalArgumentException("Parameter recoveryPointName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, recoveryPointName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryPointInner> object if successful. + */ + public PagedList listByReplicationProtectedItemsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectedItemsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPointInner> object + */ + public Observable> listByReplicationProtectedItemsNextAsync(final String nextPageLink) { + return listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPointInner> object + */ + public Observable>> listByReplicationProtectedItemsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Get recovery points for a replication protected item. + * Lists the available recovery points for a replication protected item. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryPointInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectedItemsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectedItemsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectedItemsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectedItemsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesManager.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesManager.java new file mode 100644 index 0000000000000..c3c43fa6f1952 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesManager.java @@ -0,0 +1,363 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.AzureEnvironment; +import com.microsoft.azure.AzureResponseBuilder; +import com.microsoft.azure.credentials.AzureTokenCredentials; +import com.microsoft.azure.management.apigeneration.Beta; +import com.microsoft.azure.management.apigeneration.Beta.SinceVersion; +import com.microsoft.azure.arm.resources.AzureConfigurable; +import com.microsoft.azure.serializer.AzureJacksonAdapter; +import com.microsoft.rest.RestClient; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Operations; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationEvents; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationLogicalNetworks; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationRecoveryPoints; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectableItems; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPoints; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizes; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationVaultHealths; +import com.microsoft.azure.arm.resources.implementation.AzureConfigurableCoreImpl; +import com.microsoft.azure.arm.resources.implementation.ManagerCore; + +/** + * Entry point to Azure RecoveryServices resource management. + */ +public final class RecoveryServicesManager extends ManagerCore { + private Operations operations; + private ReplicationAlertSettings replicationAlertSettings; + private ReplicationEvents replicationEvents; + private ReplicationFabrics replicationFabrics; + private ReplicationLogicalNetworks replicationLogicalNetworks; + private ReplicationNetworks replicationNetworks; + private ReplicationNetworkMappings replicationNetworkMappings; + private ReplicationProtectionContainers replicationProtectionContainers; + private ReplicationMigrationItems replicationMigrationItems; + private MigrationRecoveryPoints migrationRecoveryPoints; + private ReplicationProtectableItems replicationProtectableItems; + private ReplicationProtectedItems replicationProtectedItems; + private RecoveryPoints recoveryPoints; + private TargetComputeSizes targetComputeSizes; + private ReplicationProtectionContainerMappings replicationProtectionContainerMappings; + private ReplicationRecoveryServicesProviders replicationRecoveryServicesProviders; + private ReplicationStorageClassifications replicationStorageClassifications; + private ReplicationStorageClassificationMappings replicationStorageClassificationMappings; + private ReplicationvCenters replicationvCenters; + private ReplicationJobs replicationJobs; + private ReplicationPolicies replicationPolicies; + private ReplicationRecoveryPlans replicationRecoveryPlans; + private ReplicationVaultHealths replicationVaultHealths; + /** + * Get a Configurable instance that can be used to create RecoveryServicesManager with optional configuration. + * + * @return the instance allowing configurations + */ + public static Configurable configure() { + return new RecoveryServicesManager.ConfigurableImpl(); + } + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices resource management API entry points. + * + * @param credentials the credentials to use + * @param subscriptionId the subscription UUID + * @return the RecoveryServicesManager + */ + public static RecoveryServicesManager authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return new RecoveryServicesManager(new RestClient.Builder() + .withBaseUrl(credentials.environment(), AzureEnvironment.Endpoint.RESOURCE_MANAGER) + .withCredentials(credentials) + .withSerializerAdapter(new AzureJacksonAdapter()) + .withResponseBuilderFactory(new AzureResponseBuilder.Factory()) + .build(), subscriptionId); + } + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices resource management API entry points. + * + * @param restClient the RestClient to be used for API calls. + * @param subscriptionId the subscription UUID + * @return the RecoveryServicesManager + */ + public static RecoveryServicesManager authenticate(RestClient restClient, String subscriptionId) { + return new RecoveryServicesManager(restClient, subscriptionId); + } + /** + * The interface allowing configurations to be set. + */ + public interface Configurable extends AzureConfigurable { + /** + * Creates an instance of RecoveryServicesManager that exposes RecoveryServices management API entry points. + * + * @param credentials the credentials to use + * @param subscriptionId the subscription UUID + * @return the interface exposing RecoveryServices management API entry points that work across subscriptions + */ + RecoveryServicesManager authenticate(AzureTokenCredentials credentials, String subscriptionId); + } + + /** + * @return Entry point to manage Operations. + */ + public Operations operations() { + if (this.operations == null) { + this.operations = new OperationsImpl(this); + } + return this.operations; + } + + /** + * @return Entry point to manage ReplicationAlertSettings. + */ + public ReplicationAlertSettings replicationAlertSettings() { + if (this.replicationAlertSettings == null) { + this.replicationAlertSettings = new ReplicationAlertSettingsImpl(this); + } + return this.replicationAlertSettings; + } + + /** + * @return Entry point to manage ReplicationEvents. + */ + public ReplicationEvents replicationEvents() { + if (this.replicationEvents == null) { + this.replicationEvents = new ReplicationEventsImpl(this); + } + return this.replicationEvents; + } + + /** + * @return Entry point to manage ReplicationFabrics. + */ + public ReplicationFabrics replicationFabrics() { + if (this.replicationFabrics == null) { + this.replicationFabrics = new ReplicationFabricsImpl(this); + } + return this.replicationFabrics; + } + + /** + * @return Entry point to manage ReplicationLogicalNetworks. + */ + public ReplicationLogicalNetworks replicationLogicalNetworks() { + if (this.replicationLogicalNetworks == null) { + this.replicationLogicalNetworks = new ReplicationLogicalNetworksImpl(this); + } + return this.replicationLogicalNetworks; + } + + /** + * @return Entry point to manage ReplicationNetworks. + */ + public ReplicationNetworks replicationNetworks() { + if (this.replicationNetworks == null) { + this.replicationNetworks = new ReplicationNetworksImpl(this); + } + return this.replicationNetworks; + } + + /** + * @return Entry point to manage ReplicationNetworkMappings. + */ + public ReplicationNetworkMappings replicationNetworkMappings() { + if (this.replicationNetworkMappings == null) { + this.replicationNetworkMappings = new ReplicationNetworkMappingsImpl(this); + } + return this.replicationNetworkMappings; + } + + /** + * @return Entry point to manage ReplicationProtectionContainers. + */ + public ReplicationProtectionContainers replicationProtectionContainers() { + if (this.replicationProtectionContainers == null) { + this.replicationProtectionContainers = new ReplicationProtectionContainersImpl(this); + } + return this.replicationProtectionContainers; + } + + /** + * @return Entry point to manage ReplicationMigrationItems. + */ + public ReplicationMigrationItems replicationMigrationItems() { + if (this.replicationMigrationItems == null) { + this.replicationMigrationItems = new ReplicationMigrationItemsImpl(this); + } + return this.replicationMigrationItems; + } + + /** + * @return Entry point to manage MigrationRecoveryPoints. + */ + public MigrationRecoveryPoints migrationRecoveryPoints() { + if (this.migrationRecoveryPoints == null) { + this.migrationRecoveryPoints = new MigrationRecoveryPointsImpl(this); + } + return this.migrationRecoveryPoints; + } + + /** + * @return Entry point to manage ReplicationProtectableItems. + */ + public ReplicationProtectableItems replicationProtectableItems() { + if (this.replicationProtectableItems == null) { + this.replicationProtectableItems = new ReplicationProtectableItemsImpl(this); + } + return this.replicationProtectableItems; + } + + /** + * @return Entry point to manage ReplicationProtectedItems. + */ + public ReplicationProtectedItems replicationProtectedItems() { + if (this.replicationProtectedItems == null) { + this.replicationProtectedItems = new ReplicationProtectedItemsImpl(this); + } + return this.replicationProtectedItems; + } + + /** + * @return Entry point to manage RecoveryPoints. + */ + public RecoveryPoints recoveryPoints() { + if (this.recoveryPoints == null) { + this.recoveryPoints = new RecoveryPointsImpl(this); + } + return this.recoveryPoints; + } + + /** + * @return Entry point to manage TargetComputeSizes. + */ + public TargetComputeSizes targetComputeSizes() { + if (this.targetComputeSizes == null) { + this.targetComputeSizes = new TargetComputeSizesImpl(this); + } + return this.targetComputeSizes; + } + + /** + * @return Entry point to manage ReplicationProtectionContainerMappings. + */ + public ReplicationProtectionContainerMappings replicationProtectionContainerMappings() { + if (this.replicationProtectionContainerMappings == null) { + this.replicationProtectionContainerMappings = new ReplicationProtectionContainerMappingsImpl(this); + } + return this.replicationProtectionContainerMappings; + } + + /** + * @return Entry point to manage ReplicationRecoveryServicesProviders. + */ + public ReplicationRecoveryServicesProviders replicationRecoveryServicesProviders() { + if (this.replicationRecoveryServicesProviders == null) { + this.replicationRecoveryServicesProviders = new ReplicationRecoveryServicesProvidersImpl(this); + } + return this.replicationRecoveryServicesProviders; + } + + /** + * @return Entry point to manage ReplicationStorageClassifications. + */ + public ReplicationStorageClassifications replicationStorageClassifications() { + if (this.replicationStorageClassifications == null) { + this.replicationStorageClassifications = new ReplicationStorageClassificationsImpl(this); + } + return this.replicationStorageClassifications; + } + + /** + * @return Entry point to manage ReplicationStorageClassificationMappings. + */ + public ReplicationStorageClassificationMappings replicationStorageClassificationMappings() { + if (this.replicationStorageClassificationMappings == null) { + this.replicationStorageClassificationMappings = new ReplicationStorageClassificationMappingsImpl(this); + } + return this.replicationStorageClassificationMappings; + } + + /** + * @return Entry point to manage ReplicationvCenters. + */ + public ReplicationvCenters replicationvCenters() { + if (this.replicationvCenters == null) { + this.replicationvCenters = new ReplicationvCentersImpl(this); + } + return this.replicationvCenters; + } + + /** + * @return Entry point to manage ReplicationJobs. + */ + public ReplicationJobs replicationJobs() { + if (this.replicationJobs == null) { + this.replicationJobs = new ReplicationJobsImpl(this); + } + return this.replicationJobs; + } + + /** + * @return Entry point to manage ReplicationPolicies. + */ + public ReplicationPolicies replicationPolicies() { + if (this.replicationPolicies == null) { + this.replicationPolicies = new ReplicationPoliciesImpl(this); + } + return this.replicationPolicies; + } + + /** + * @return Entry point to manage ReplicationRecoveryPlans. + */ + public ReplicationRecoveryPlans replicationRecoveryPlans() { + if (this.replicationRecoveryPlans == null) { + this.replicationRecoveryPlans = new ReplicationRecoveryPlansImpl(this); + } + return this.replicationRecoveryPlans; + } + + /** + * @return Entry point to manage ReplicationVaultHealths. + */ + public ReplicationVaultHealths replicationVaultHealths() { + if (this.replicationVaultHealths == null) { + this.replicationVaultHealths = new ReplicationVaultHealthsImpl(this); + } + return this.replicationVaultHealths; + } + + /** + * The implementation for Configurable interface. + */ + private static final class ConfigurableImpl extends AzureConfigurableCoreImpl implements Configurable { + public RecoveryServicesManager authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return RecoveryServicesManager.authenticate(buildRestClient(credentials), subscriptionId); + } + } + private RecoveryServicesManager(RestClient restClient, String subscriptionId) { + super( + restClient, + subscriptionId, + new SiteRecoveryManagementClientImpl(restClient).withSubscriptionId(subscriptionId)); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderImpl.java new file mode 100644 index 0000000000000..1982a185bdf7b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderImpl.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryServicesProvider; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddRecoveryServicesProviderInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryServicesProviderProperties; +import rx.functions.Func1; + +class RecoveryServicesProviderImpl extends CreatableUpdatableImpl implements RecoveryServicesProvider, RecoveryServicesProvider.Definition, RecoveryServicesProvider.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String providerName; + private AddRecoveryServicesProviderInputProperties cproperties; + private AddRecoveryServicesProviderInputProperties uproperties; + + RecoveryServicesProviderImpl(String name, RecoveryServicesManager manager) { + super(name, new RecoveryServicesProviderInner()); + this.manager = manager; + // Set resource name + this.providerName = name; + // + this.cproperties = new AddRecoveryServicesProviderInputProperties(); + this.uproperties = new AddRecoveryServicesProviderInputProperties(); + } + + RecoveryServicesProviderImpl(RecoveryServicesProviderInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.providerName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.providerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationRecoveryServicesProviders"); + // + this.cproperties = new AddRecoveryServicesProviderInputProperties(); + this.uproperties = new AddRecoveryServicesProviderInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationRecoveryServicesProvidersInner client = this.manager().inner().replicationRecoveryServicesProviders(); + return client.createAsync(this.fabricName, this.providerName, this.cproperties) + .map(new Func1() { + @Override + public RecoveryServicesProviderInner call(RecoveryServicesProviderInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationRecoveryServicesProvidersInner client = this.manager().inner().replicationRecoveryServicesProviders(); + return client.createAsync(this.fabricName, this.providerName, this.uproperties) + .map(new Func1() { + @Override + public RecoveryServicesProviderInner call(RecoveryServicesProviderInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationRecoveryServicesProvidersInner client = this.manager().inner().replicationRecoveryServicesProviders(); + return client.getAsync(this.fabricName, this.providerName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new AddRecoveryServicesProviderInputProperties(); + this.uproperties = new AddRecoveryServicesProviderInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public RecoveryServicesProviderProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public RecoveryServicesProviderImpl withExistingReplicationFabric(String fabricName) { + this.fabricName = fabricName; + return this; + } + + @Override + public RecoveryServicesProviderImpl withProperties(AddRecoveryServicesProviderInputProperties properties) { + if (isInCreateMode()) { + this.cproperties = properties; + } else { + this.uproperties = properties; + } + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderInner.java new file mode 100644 index 0000000000000..7936ad21ce4a5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/RecoveryServicesProviderInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryServicesProviderProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Provider details. + */ +public class RecoveryServicesProviderInner extends ProxyResource { + /** + * Provider properties. + */ + @JsonProperty(value = "properties") + private RecoveryServicesProviderProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get provider properties. + * + * @return the properties value + */ + public RecoveryServicesProviderProperties properties() { + return this.properties; + } + + /** + * Set provider properties. + * + * @param properties the properties value to set + * @return the RecoveryServicesProviderInner object itself. + */ + public RecoveryServicesProviderInner withProperties(RecoveryServicesProviderProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the RecoveryServicesProviderInner object itself. + */ + public RecoveryServicesProviderInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsImpl.java new file mode 100644 index 0000000000000..48820c65d3f7c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsImpl.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Alert; + +class ReplicationAlertSettingsImpl extends WrapperImpl implements ReplicationAlertSettings { + private final RecoveryServicesManager manager; + + ReplicationAlertSettingsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationAlertSettings()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public AlertImpl define(String name) { + return wrapModel(name); + } + + private AlertImpl wrapModel(AlertInner inner) { + return new AlertImpl(inner, manager()); + } + + private AlertImpl wrapModel(String name) { + return new AlertImpl(name, this.manager()); + } + + @Override + public Observable listAsync() { + ReplicationAlertSettingsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Alert call(AlertInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String alertSettingName) { + ReplicationAlertSettingsInner client = this.inner(); + return client.getAsync(alertSettingName) + .map(new Func1() { + @Override + public Alert call(AlertInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsInner.java new file mode 100644 index 0000000000000..b143d88c076be --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationAlertSettingsInner.java @@ -0,0 +1,587 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ConfigureAlertRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ConfigureAlertRequestProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationAlertSettings. + */ +public class ReplicationAlertSettingsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationAlertSettingsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationAlertSettingsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationAlertSettingsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationAlertSettingsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationAlertSettings to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationAlertSettingsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationAlertSettings") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationAlertSettings/{alertSettingName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("alertSettingName") String alertSettingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationAlertSettings/{alertSettingName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("alertSettingName") String alertSettingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ConfigureAlertRequest request, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationAlertSettings listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<AlertInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AlertInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AlertInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<AlertInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets an email notification(alert) configuration. + * Gets the details of the specified email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AlertInner object if successful. + */ + public AlertInner get(String alertSettingName) { + return getWithServiceResponseAsync(alertSettingName).toBlocking().single().body(); + } + + /** + * Gets an email notification(alert) configuration. + * Gets the details of the specified email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification configuration. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String alertSettingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(alertSettingName), serviceCallback); + } + + /** + * Gets an email notification(alert) configuration. + * Gets the details of the specified email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable getAsync(String alertSettingName) { + return getWithServiceResponseAsync(alertSettingName).map(new Func1, AlertInner>() { + @Override + public AlertInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets an email notification(alert) configuration. + * Gets the details of the specified email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable> getWithServiceResponseAsync(String alertSettingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (alertSettingName == null) { + throw new IllegalArgumentException("Parameter alertSettingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), alertSettingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AlertInner object if successful. + */ + public AlertInner create(String alertSettingName) { + return createWithServiceResponseAsync(alertSettingName).toBlocking().single().body(); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String alertSettingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(alertSettingName), serviceCallback); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable createAsync(String alertSettingName) { + return createWithServiceResponseAsync(alertSettingName).map(new Func1, AlertInner>() { + @Override + public AlertInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable> createWithServiceResponseAsync(String alertSettingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (alertSettingName == null) { + throw new IllegalArgumentException("Parameter alertSettingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ConfigureAlertRequestProperties properties = null; + ConfigureAlertRequest request = new ConfigureAlertRequest(); + request.withProperties(null); + return service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), alertSettingName, this.client.apiVersion(), this.client.acceptLanguage(), request, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = createDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @param properties The properties of a configure alert request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AlertInner object if successful. + */ + public AlertInner create(String alertSettingName, ConfigureAlertRequestProperties properties) { + return createWithServiceResponseAsync(alertSettingName, properties).toBlocking().single().body(); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @param properties The properties of a configure alert request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String alertSettingName, ConfigureAlertRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(alertSettingName, properties), serviceCallback); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @param properties The properties of a configure alert request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable createAsync(String alertSettingName, ConfigureAlertRequestProperties properties) { + return createWithServiceResponseAsync(alertSettingName, properties).map(new Func1, AlertInner>() { + @Override + public AlertInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Configures email notifications for this vault. + * Create or update an email notification(alert) configuration. + * + * @param alertSettingName The name of the email notification(alert) configuration. + * @param properties The properties of a configure alert request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AlertInner object + */ + public Observable> createWithServiceResponseAsync(String alertSettingName, ConfigureAlertRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (alertSettingName == null) { + throw new IllegalArgumentException("Parameter alertSettingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ConfigureAlertRequest request = new ConfigureAlertRequest(); + request.withProperties(properties); + return service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), alertSettingName, this.client.apiVersion(), this.client.acceptLanguage(), request, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = createDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse createDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<AlertInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AlertInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AlertInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of configured email notification(alert) configurations. + * Gets the list of email notification(alert) configurations for the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<AlertInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsImpl.java new file mode 100644 index 0000000000000..a1f322c6eb6bf --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationEvents; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Event; + +class ReplicationEventsImpl extends WrapperImpl implements ReplicationEvents { + private final RecoveryServicesManager manager; + + ReplicationEventsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationEvents()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private EventImpl wrapModel(EventInner inner) { + return new EventImpl(inner, manager()); + } + + @Override + public Observable listAsync() { + ReplicationEventsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Event call(EventInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String eventName) { + ReplicationEventsInner client = this.inner(); + return client.getAsync(eventName) + .map(new Func1() { + @Override + public Event call(EventInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsInner.java new file mode 100644 index 0000000000000..a37b4af36ddd1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationEventsInner.java @@ -0,0 +1,514 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationEvents. + */ +public class ReplicationEventsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationEventsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationEventsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationEventsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationEventsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationEvents to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationEventsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationEvents list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationEvents") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Query("$filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationEvents get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationEvents/{eventName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("eventName") String eventName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationEvents listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<EventInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<EventInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String filter = null; + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<EventInner> object if successful. + */ + public PagedList list(final String filter) { + ServiceResponse> response = listSinglePageAsync(filter).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param filter OData filter options. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final String filter, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(filter), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable> listAsync(final String filter) { + return listWithServiceResponseAsync(filter) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable>> listWithServiceResponseAsync(final String filter) { + return listSinglePageAsync(filter) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + ServiceResponse> * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<EventInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync(final String filter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Get the details of an Azure Site recovery event. + * The operation to get the details of an Azure Site recovery event. + * + * @param eventName The name of the Azure Site Recovery event. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the EventInner object if successful. + */ + public EventInner get(String eventName) { + return getWithServiceResponseAsync(eventName).toBlocking().single().body(); + } + + /** + * Get the details of an Azure Site recovery event. + * The operation to get the details of an Azure Site recovery event. + * + * @param eventName The name of the Azure Site Recovery event. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String eventName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(eventName), serviceCallback); + } + + /** + * Get the details of an Azure Site recovery event. + * The operation to get the details of an Azure Site recovery event. + * + * @param eventName The name of the Azure Site Recovery event. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the EventInner object + */ + public Observable getAsync(String eventName) { + return getWithServiceResponseAsync(eventName).map(new Func1, EventInner>() { + @Override + public EventInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Get the details of an Azure Site recovery event. + * The operation to get the details of an Azure Site recovery event. + * + * @param eventName The name of the Azure Site Recovery event. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the EventInner object + */ + public Observable> getWithServiceResponseAsync(String eventName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (eventName == null) { + throw new IllegalArgumentException("Parameter eventName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), eventName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<EventInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<EventInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of Azure Site Recovery events. + * Gets the list of Azure Site Recovery events for the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<EventInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsImpl.java new file mode 100644 index 0000000000000..7afa9e4f412aa --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsImpl.java @@ -0,0 +1,129 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Fabric; + +class ReplicationFabricsImpl extends WrapperImpl implements ReplicationFabrics { + private final RecoveryServicesManager manager; + + ReplicationFabricsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationFabrics()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public FabricImpl define(String name) { + return wrapModel(name); + } + + private FabricImpl wrapModel(FabricInner inner) { + return new FabricImpl(inner, manager()); + } + + private FabricImpl wrapModel(String name) { + return new FabricImpl(name, this.manager()); + } + + @Override + public Observable checkConsistencyAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.checkConsistencyAsync(fabricName) + .map(new Func1() { + @Override + public Fabric call(FabricInner inner) { + return new FabricImpl(inner, manager()); + } + }); + } + + @Override + public Completable migrateToAadAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.migrateToAadAsync(fabricName).toCompletable(); + } + + @Override + public Observable reassociateGatewayAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.reassociateGatewayAsync(fabricName) + .map(new Func1() { + @Override + public Fabric call(FabricInner inner) { + return new FabricImpl(inner, manager()); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.deleteAsync(fabricName).toCompletable(); + } + + @Override + public Observable renewCertificateAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.renewCertificateAsync(fabricName) + .map(new Func1() { + @Override + public Fabric call(FabricInner inner) { + return new FabricImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationFabricsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Fabric call(FabricInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.getAsync(fabricName) + .map(new Func1() { + @Override + public Fabric call(FabricInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable purgeAsync(String fabricName) { + ReplicationFabricsInner client = this.inner(); + return client.purgeAsync(fabricName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsInner.java new file mode 100644 index 0000000000000..2f6782ff082f4 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationFabricsInner.java @@ -0,0 +1,2111 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FabricCreationInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FabricCreationInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FailoverProcessServerRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.FailoverProcessServerRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RenewCertificateInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RenewCertificateInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationFabrics. + */ +public class ReplicationFabricsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationFabricsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationFabricsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationFabricsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationFabricsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationFabrics to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationFabricsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body FabricCreationInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body FabricCreationInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics purge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}", method = "DELETE", hasBody = true) + Observable> purge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginPurge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}", method = "DELETE", hasBody = true) + Observable> beginPurge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics checkConsistency" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/checkConsistency") + Observable> checkConsistency(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginCheckConsistency" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/checkConsistency") + Observable> beginCheckConsistency(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics migrateToAad" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/migratetoaad") + Observable> migrateToAad(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginMigrateToAad" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/migratetoaad") + Observable> beginMigrateToAad(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics reassociateGateway" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/reassociateGateway") + Observable> reassociateGateway(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body FailoverProcessServerRequest failoverProcessServerRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginReassociateGateway" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/reassociateGateway") + Observable> beginReassociateGateway(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body FailoverProcessServerRequest failoverProcessServerRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics delete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/remove") + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginDelete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/remove") + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics renewCertificate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/renewCertificate") + Observable> renewCertificate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RenewCertificateInput renewCertificate, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics beginRenewCertificate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/renewCertificate") + Observable> beginRenewCertificate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RenewCertificateInput renewCertificate, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationFabrics listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<FabricInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<FabricInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<FabricInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<FabricInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of an ASR fabric. + * Gets the details of an Azure Site Recovery fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner get(String fabricName) { + return getWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Gets the details of an ASR fabric. + * Gets the details of an Azure Site Recovery fabric. + * + * @param fabricName Fabric name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Gets the details of an ASR fabric. + * Gets the details of an Azure Site Recovery fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable getAsync(String fabricName) { + return getWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of an ASR fabric. + * Gets the details of an Azure Site Recovery fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner create(String fabricName) { + return createWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName) { + return createWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final FabricCreationInputProperties properties = null; + FabricCreationInput input = new FabricCreationInput(); + input.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner create(String fabricName, FabricCreationInputProperties properties) { + return createWithServiceResponseAsync(fabricName, properties).toBlocking().last().body(); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, FabricCreationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, FabricCreationInputProperties properties) { + return createWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, FabricCreationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + FabricCreationInput input = new FabricCreationInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginCreate(String fabricName) { + return beginCreateWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginCreateAsync(String fabricName) { + return beginCreateWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final FabricCreationInputProperties properties = null; + FabricCreationInput input = new FabricCreationInput(); + input.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginCreate(String fabricName, FabricCreationInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, properties).toBlocking().single().body(); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, FabricCreationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginCreateAsync(String fabricName, FabricCreationInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates an Azure Site Recovery fabric. + * The operation to create an Azure Site Recovery fabric (for e.g. Hyper-V site). + * + * @param fabricName Name of the ASR fabric. + * @param properties Fabric creation input. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, FabricCreationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + FabricCreationInput input = new FabricCreationInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void purge(String fabricName) { + purgeWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture purgeAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(purgeWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable purgeAsync(String fabricName) { + return purgeWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> purgeWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.purge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginPurge(String fabricName) { + beginPurgeWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPurgeAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPurgeWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginPurgeAsync(String fabricName) { + return beginPurgeWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges the site. + * The operation to purge(force delete) an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to purge. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginPurgeWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginPurge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPurgeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPurgeDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner checkConsistency(String fabricName) { + return checkConsistencyWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture checkConsistencyAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(checkConsistencyWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable checkConsistencyAsync(String fabricName) { + return checkConsistencyWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> checkConsistencyWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.checkConsistency(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginCheckConsistency(String fabricName) { + return beginCheckConsistencyWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCheckConsistencyAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCheckConsistencyWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginCheckConsistencyAsync(String fabricName) { + return beginCheckConsistencyWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Checks the consistency of the ASR fabric. + * The operation to perform a consistency check on the fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginCheckConsistencyWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginCheckConsistency(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCheckConsistencyDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCheckConsistencyDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void migrateToAad(String fabricName) { + migrateToAadWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture migrateToAadAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(migrateToAadWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable migrateToAadAsync(String fabricName) { + return migrateToAadWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> migrateToAadWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.migrateToAad(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginMigrateToAad(String fabricName) { + beginMigrateToAadWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginMigrateToAadAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginMigrateToAadWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginMigrateToAadAsync(String fabricName) { + return beginMigrateToAadWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Migrates the site to AAD. + * The operation to migrate an Azure Site Recovery fabric to AAD. + * + * @param fabricName ASR fabric to migrate. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginMigrateToAadWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginMigrateToAad(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginMigrateToAadDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginMigrateToAadDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner reassociateGateway(String fabricName) { + return reassociateGatewayWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture reassociateGatewayAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(reassociateGatewayWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable reassociateGatewayAsync(String fabricName) { + return reassociateGatewayWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> reassociateGatewayWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final FailoverProcessServerRequestProperties properties = null; + FailoverProcessServerRequest failoverProcessServerRequest = new FailoverProcessServerRequest(); + failoverProcessServerRequest.withProperties(null); + Observable> observable = service.reassociateGateway(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), failoverProcessServerRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner reassociateGateway(String fabricName, FailoverProcessServerRequestProperties properties) { + return reassociateGatewayWithServiceResponseAsync(fabricName, properties).toBlocking().last().body(); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture reassociateGatewayAsync(String fabricName, FailoverProcessServerRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(reassociateGatewayWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable reassociateGatewayAsync(String fabricName, FailoverProcessServerRequestProperties properties) { + return reassociateGatewayWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> reassociateGatewayWithServiceResponseAsync(String fabricName, FailoverProcessServerRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + FailoverProcessServerRequest failoverProcessServerRequest = new FailoverProcessServerRequest(); + failoverProcessServerRequest.withProperties(properties); + Observable> observable = service.reassociateGateway(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), failoverProcessServerRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginReassociateGateway(String fabricName) { + return beginReassociateGatewayWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginReassociateGatewayAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginReassociateGatewayWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginReassociateGatewayAsync(String fabricName) { + return beginReassociateGatewayWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginReassociateGatewayWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final FailoverProcessServerRequestProperties properties = null; + FailoverProcessServerRequest failoverProcessServerRequest = new FailoverProcessServerRequest(); + failoverProcessServerRequest.withProperties(null); + return service.beginReassociateGateway(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), failoverProcessServerRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginReassociateGatewayDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginReassociateGateway(String fabricName, FailoverProcessServerRequestProperties properties) { + return beginReassociateGatewayWithServiceResponseAsync(fabricName, properties).toBlocking().single().body(); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginReassociateGatewayAsync(String fabricName, FailoverProcessServerRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginReassociateGatewayWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginReassociateGatewayAsync(String fabricName, FailoverProcessServerRequestProperties properties) { + return beginReassociateGatewayWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Perform failover of the process server. + * The operation to move replications from a process server to another process server. + * + * @param fabricName The name of the fabric containing the process server. + * @param properties The properties of the PS Failover request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginReassociateGatewayWithServiceResponseAsync(String fabricName, FailoverProcessServerRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + FailoverProcessServerRequest failoverProcessServerRequest = new FailoverProcessServerRequest(); + failoverProcessServerRequest.withProperties(properties); + return service.beginReassociateGateway(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), failoverProcessServerRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginReassociateGatewayDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginReassociateGatewayDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName) { + deleteWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName) { + return deleteWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName) { + beginDeleteWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName) { + return beginDeleteWithServiceResponseAsync(fabricName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes the site. + * The operation to delete or remove an Azure Site Recovery fabric. + * + * @param fabricName ASR fabric to delete + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner renewCertificate(String fabricName) { + return renewCertificateWithServiceResponseAsync(fabricName).toBlocking().last().body(); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture renewCertificateAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(renewCertificateWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable renewCertificateAsync(String fabricName) { + return renewCertificateWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> renewCertificateWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final RenewCertificateInputProperties properties = null; + RenewCertificateInput renewCertificate = new RenewCertificateInput(); + renewCertificate.withProperties(null); + Observable> observable = service.renewCertificate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), renewCertificate, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner renewCertificate(String fabricName, RenewCertificateInputProperties properties) { + return renewCertificateWithServiceResponseAsync(fabricName, properties).toBlocking().last().body(); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture renewCertificateAsync(String fabricName, RenewCertificateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(renewCertificateWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable renewCertificateAsync(String fabricName, RenewCertificateInputProperties properties) { + return renewCertificateWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> renewCertificateWithServiceResponseAsync(String fabricName, RenewCertificateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + RenewCertificateInput renewCertificate = new RenewCertificateInput(); + renewCertificate.withProperties(properties); + Observable> observable = service.renewCertificate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), renewCertificate, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginRenewCertificate(String fabricName) { + return beginRenewCertificateWithServiceResponseAsync(fabricName).toBlocking().single().body(); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRenewCertificateAsync(String fabricName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRenewCertificateWithServiceResponseAsync(fabricName), serviceCallback); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginRenewCertificateAsync(String fabricName) { + return beginRenewCertificateWithServiceResponseAsync(fabricName).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginRenewCertificateWithServiceResponseAsync(String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final RenewCertificateInputProperties properties = null; + RenewCertificateInput renewCertificate = new RenewCertificateInput(); + renewCertificate.withProperties(null); + return service.beginRenewCertificate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), renewCertificate, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRenewCertificateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the FabricInner object if successful. + */ + public FabricInner beginRenewCertificate(String fabricName, RenewCertificateInputProperties properties) { + return beginRenewCertificateWithServiceResponseAsync(fabricName, properties).toBlocking().single().body(); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRenewCertificateAsync(String fabricName, RenewCertificateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRenewCertificateWithServiceResponseAsync(fabricName, properties), serviceCallback); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable beginRenewCertificateAsync(String fabricName, RenewCertificateInputProperties properties) { + return beginRenewCertificateWithServiceResponseAsync(fabricName, properties).map(new Func1, FabricInner>() { + @Override + public FabricInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Renews certificate for the fabric. + * Renews the connection certificate for the ASR replication fabric. + * + * @param fabricName fabric name to renew certs for. + * @param properties Renew certificate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the FabricInner object + */ + public Observable> beginRenewCertificateWithServiceResponseAsync(String fabricName, RenewCertificateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + RenewCertificateInput renewCertificate = new RenewCertificateInput(); + renewCertificate.withProperties(properties); + return service.beginRenewCertificate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), renewCertificate, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRenewCertificateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginRenewCertificateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<FabricInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<FabricInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<FabricInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of ASR fabrics. + * Gets a list of the Azure Site Recovery fabrics in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<FabricInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsImpl.java new file mode 100644 index 0000000000000..5892f64c026e2 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsImpl.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Job; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.JobQueryParameter; + +class ReplicationJobsImpl extends WrapperImpl implements ReplicationJobs { + private final RecoveryServicesManager manager; + + ReplicationJobsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationJobs()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private JobImpl wrapModel(JobInner inner) { + return new JobImpl(inner, manager()); + } + + @Override + public Observable cancelAsync(String jobName) { + ReplicationJobsInner client = this.inner(); + return client.cancelAsync(jobName) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return new JobImpl(inner, manager()); + } + }); + } + + @Override + public Observable restartAsync(String jobName) { + ReplicationJobsInner client = this.inner(); + return client.restartAsync(jobName) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return new JobImpl(inner, manager()); + } + }); + } + + @Override + public Observable resumeAsync(String jobName) { + ReplicationJobsInner client = this.inner(); + return client.resumeAsync(jobName) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return new JobImpl(inner, manager()); + } + }); + } + + @Override + public Observable exportAsync(JobQueryParameter jobQueryParameter) { + ReplicationJobsInner client = this.inner(); + return client.exportAsync(jobQueryParameter) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return new JobImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationJobsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String jobName) { + ReplicationJobsInner client = this.inner(); + return client.getAsync(jobName) + .map(new Func1() { + @Override + public Job call(JobInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsInner.java new file mode 100644 index 0000000000000..c06782d8dce6a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationJobsInner.java @@ -0,0 +1,1375 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.JobQueryParameter; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ResumeJobParams; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ResumeJobParamsProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationJobs. + */ +public class ReplicationJobsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationJobsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationJobsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationJobsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationJobsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationJobs to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationJobsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Query("$filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs cancel" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/cancel") + Observable> cancel(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs beginCancel" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/cancel") + Observable> beginCancel(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs restart" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/restart") + Observable> restart(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs beginRestart" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/restart") + Observable> beginRestart(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs resume" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/resume") + Observable> resume(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ResumeJobParams resumeJobParams, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs beginResume" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/{jobName}/resume") + Observable> beginResume(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("jobName") String jobName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ResumeJobParams resumeJobParams, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs export" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/export") + Observable> export(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Body JobQueryParameter jobQueryParameter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs beginExport" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationJobs/export") + Observable> beginExport(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Body JobQueryParameter jobQueryParameter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationJobs listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<JobInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<JobInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String filter = null; + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<JobInner> object if successful. + */ + public PagedList list(final String filter) { + ServiceResponse> response = listSinglePageAsync(filter).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param filter OData filter options. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final String filter, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(filter), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable> listAsync(final String filter) { + return listWithServiceResponseAsync(filter) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable>> listWithServiceResponseAsync(final String filter) { + return listSinglePageAsync(filter) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + ServiceResponse> * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<JobInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync(final String filter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the job details. + * Get the details of an Azure Site Recovery job. + * + * @param jobName Job identifier + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner get(String jobName) { + return getWithServiceResponseAsync(jobName).toBlocking().single().body(); + } + + /** + * Gets the job details. + * Get the details of an Azure Site Recovery job. + * + * @param jobName Job identifier + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Gets the job details. + * Get the details of an Azure Site Recovery job. + * + * @param jobName Job identifier + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable getAsync(String jobName) { + return getWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the job details. + * Get the details of an Azure Site Recovery job. + * + * @param jobName Job identifier + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> getWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner cancel(String jobName) { + return cancelWithServiceResponseAsync(jobName).toBlocking().last().body(); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture cancelAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(cancelWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable cancelAsync(String jobName) { + return cancelWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> cancelWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.cancel(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner beginCancel(String jobName) { + return beginCancelWithServiceResponseAsync(jobName).toBlocking().single().body(); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCancelAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCancelWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable beginCancelAsync(String jobName) { + return beginCancelWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Cancels the specified job. + * The operation to cancel an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> beginCancelWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginCancel(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCancelDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCancelDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner restart(String jobName) { + return restartWithServiceResponseAsync(jobName).toBlocking().last().body(); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture restartAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(restartWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable restartAsync(String jobName) { + return restartWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> restartWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.restart(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner beginRestart(String jobName) { + return beginRestartWithServiceResponseAsync(jobName).toBlocking().single().body(); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRestartAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRestartWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable beginRestartAsync(String jobName) { + return beginRestartWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Restarts the specified job. + * The operation to restart an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> beginRestartWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginRestart(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRestartDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginRestartDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner resume(String jobName) { + return resumeWithServiceResponseAsync(jobName).toBlocking().last().body(); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture resumeAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(resumeWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable resumeAsync(String jobName) { + return resumeWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> resumeWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ResumeJobParamsProperties properties = null; + ResumeJobParams resumeJobParams = new ResumeJobParams(); + resumeJobParams.withProperties(null); + Observable> observable = service.resume(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), resumeJobParams, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner resume(String jobName, ResumeJobParamsProperties properties) { + return resumeWithServiceResponseAsync(jobName, properties).toBlocking().last().body(); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture resumeAsync(String jobName, ResumeJobParamsProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(resumeWithServiceResponseAsync(jobName, properties), serviceCallback); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable resumeAsync(String jobName, ResumeJobParamsProperties properties) { + return resumeWithServiceResponseAsync(jobName, properties).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> resumeWithServiceResponseAsync(String jobName, ResumeJobParamsProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ResumeJobParams resumeJobParams = new ResumeJobParams(); + resumeJobParams.withProperties(properties); + Observable> observable = service.resume(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), resumeJobParams, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner beginResume(String jobName) { + return beginResumeWithServiceResponseAsync(jobName).toBlocking().single().body(); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginResumeAsync(String jobName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginResumeWithServiceResponseAsync(jobName), serviceCallback); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable beginResumeAsync(String jobName) { + return beginResumeWithServiceResponseAsync(jobName).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> beginResumeWithServiceResponseAsync(String jobName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ResumeJobParamsProperties properties = null; + ResumeJobParams resumeJobParams = new ResumeJobParams(); + resumeJobParams.withProperties(null); + return service.beginResume(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), resumeJobParams, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginResumeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner beginResume(String jobName, ResumeJobParamsProperties properties) { + return beginResumeWithServiceResponseAsync(jobName, properties).toBlocking().single().body(); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginResumeAsync(String jobName, ResumeJobParamsProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginResumeWithServiceResponseAsync(jobName, properties), serviceCallback); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable beginResumeAsync(String jobName, ResumeJobParamsProperties properties) { + return beginResumeWithServiceResponseAsync(jobName, properties).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resumes the specified job. + * The operation to resume an Azure Site Recovery job. + * + * @param jobName Job identifier. + * @param properties Resume job properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> beginResumeWithServiceResponseAsync(String jobName, ResumeJobParamsProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (jobName == null) { + throw new IllegalArgumentException("Parameter jobName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ResumeJobParams resumeJobParams = new ResumeJobParams(); + resumeJobParams.withProperties(properties); + return service.beginResume(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), jobName, this.client.apiVersion(), this.client.acceptLanguage(), resumeJobParams, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginResumeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginResumeDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner export(JobQueryParameter jobQueryParameter) { + return exportWithServiceResponseAsync(jobQueryParameter).toBlocking().last().body(); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture exportAsync(JobQueryParameter jobQueryParameter, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(exportWithServiceResponseAsync(jobQueryParameter), serviceCallback); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable exportAsync(JobQueryParameter jobQueryParameter) { + return exportWithServiceResponseAsync(jobQueryParameter).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> exportWithServiceResponseAsync(JobQueryParameter jobQueryParameter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (jobQueryParameter == null) { + throw new IllegalArgumentException("Parameter jobQueryParameter is required and cannot be null."); + } + Validator.validate(jobQueryParameter); + Observable> observable = service.export(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), jobQueryParameter, this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the JobInner object if successful. + */ + public JobInner beginExport(JobQueryParameter jobQueryParameter) { + return beginExportWithServiceResponseAsync(jobQueryParameter).toBlocking().single().body(); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginExportAsync(JobQueryParameter jobQueryParameter, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginExportWithServiceResponseAsync(jobQueryParameter), serviceCallback); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable beginExportAsync(JobQueryParameter jobQueryParameter) { + return beginExportWithServiceResponseAsync(jobQueryParameter).map(new Func1, JobInner>() { + @Override + public JobInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Exports the details of the Azure Site Recovery jobs of the vault. + * The operation to export the details of the Azure Site Recovery jobs of the vault. + * + * @param jobQueryParameter job query filter. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the JobInner object + */ + public Observable> beginExportWithServiceResponseAsync(JobQueryParameter jobQueryParameter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (jobQueryParameter == null) { + throw new IllegalArgumentException("Parameter jobQueryParameter is required and cannot be null."); + } + Validator.validate(jobQueryParameter); + return service.beginExport(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), jobQueryParameter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginExportDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginExportDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<JobInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<JobInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of jobs. + * Gets the list of Azure Site Recovery Jobs for the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<JobInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksImpl.java new file mode 100644 index 0000000000000..4039e7bd31681 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationLogicalNetworks; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.LogicalNetwork; + +class ReplicationLogicalNetworksImpl extends WrapperImpl implements ReplicationLogicalNetworks { + private final RecoveryServicesManager manager; + + ReplicationLogicalNetworksImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationLogicalNetworks()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private LogicalNetworkImpl wrapModel(LogicalNetworkInner inner) { + return new LogicalNetworkImpl(inner, manager()); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationLogicalNetworksInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public LogicalNetwork call(LogicalNetworkInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String logicalNetworkName) { + ReplicationLogicalNetworksInner client = this.inner(); + return client.getAsync(fabricName, logicalNetworkName) + .map(new Func1() { + @Override + public LogicalNetwork call(LogicalNetworkInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksInner.java new file mode 100644 index 0000000000000..df3ff367b21ee --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationLogicalNetworksInner.java @@ -0,0 +1,412 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationLogicalNetworks. + */ +public class ReplicationLogicalNetworksInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationLogicalNetworksService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationLogicalNetworksInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationLogicalNetworksInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationLogicalNetworksService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationLogicalNetworks to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationLogicalNetworksService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationLogicalNetworks listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationLogicalNetworks") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationLogicalNetworks get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationLogicalNetworks/{logicalNetworkName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("logicalNetworkName") String logicalNetworkName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationLogicalNetworks listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param fabricName Server Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<LogicalNetworkInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param fabricName Server Id. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param fabricName Server Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<LogicalNetworkInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param fabricName Server Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<LogicalNetworkInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + ServiceResponse> * @param fabricName Server Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<LogicalNetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets a logical network with specified server id and logical network name. + * Gets the details of a logical network. + * + * @param fabricName Server Id. + * @param logicalNetworkName Logical network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the LogicalNetworkInner object if successful. + */ + public LogicalNetworkInner get(String fabricName, String logicalNetworkName) { + return getWithServiceResponseAsync(fabricName, logicalNetworkName).toBlocking().single().body(); + } + + /** + * Gets a logical network with specified server id and logical network name. + * Gets the details of a logical network. + * + * @param fabricName Server Id. + * @param logicalNetworkName Logical network name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String logicalNetworkName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, logicalNetworkName), serviceCallback); + } + + /** + * Gets a logical network with specified server id and logical network name. + * Gets the details of a logical network. + * + * @param fabricName Server Id. + * @param logicalNetworkName Logical network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the LogicalNetworkInner object + */ + public Observable getAsync(String fabricName, String logicalNetworkName) { + return getWithServiceResponseAsync(fabricName, logicalNetworkName).map(new Func1, LogicalNetworkInner>() { + @Override + public LogicalNetworkInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a logical network with specified server id and logical network name. + * Gets the details of a logical network. + * + * @param fabricName Server Id. + * @param logicalNetworkName Logical network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the LogicalNetworkInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String logicalNetworkName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (logicalNetworkName == null) { + throw new IllegalArgumentException("Parameter logicalNetworkName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, logicalNetworkName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<LogicalNetworkInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<LogicalNetworkInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<LogicalNetworkInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of logical networks under a fabric. + * Lists all the logical networks of the Azure Site Recovery fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<LogicalNetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsImpl.java new file mode 100644 index 0000000000000..cd104d0283d16 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsImpl.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrationItem; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrateInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateCleanupInputProperties; + +class ReplicationMigrationItemsImpl extends WrapperImpl implements ReplicationMigrationItems { + private final RecoveryServicesManager manager; + + ReplicationMigrationItemsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationMigrationItems()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public MigrationItemImpl define(String name) { + return wrapModel(name); + } + + private MigrationItemImpl wrapModel(MigrationItemInner inner) { + return new MigrationItemImpl(inner, manager()); + } + + private MigrationItemImpl wrapModel(String name) { + return new MigrationItemImpl(name, this.manager()); + } + + @Override + public Observable migrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + ReplicationMigrationItemsInner client = this.inner(); + return client.migrateAsync(fabricName, protectionContainerName, migrationItemName, properties) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return new MigrationItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable testMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + ReplicationMigrationItemsInner client = this.inner(); + return client.testMigrateAsync(fabricName, protectionContainerName, migrationItemName, properties) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return new MigrationItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable testMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + ReplicationMigrationItemsInner client = this.inner(); + return client.testMigrateCleanupAsync(fabricName, protectionContainerName, migrationItemName, properties) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return new MigrationItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationMigrationItemsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return new MigrationItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + ReplicationMigrationItemsInner client = this.inner(); + return client.listByReplicationProtectionContainersAsync(fabricName, protectionContainerName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName) { + ReplicationMigrationItemsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, migrationItemName) + .map(new Func1() { + @Override + public MigrationItem call(MigrationItemInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String protectionContainerName, String migrationItemName) { + ReplicationMigrationItemsInner client = this.inner(); + return client.deleteAsync(fabricName, protectionContainerName, migrationItemName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsInner.java new file mode 100644 index 0000000000000..b1f6659ae2d6a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationMigrationItemsInner.java @@ -0,0 +1,2445 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableMigrationInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableMigrationInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrateInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.MigrateInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateCleanupInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateCleanupInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestMigrateInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateMigrationItemInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateMigrationItemInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationMigrationItems. + */ +public class ReplicationMigrationItemsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationMigrationItemsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationMigrationItemsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationMigrationItemsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationMigrationItemsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationMigrationItems to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationMigrationItemsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems listByReplicationProtectionContainers" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems") + Observable> listByReplicationProtectionContainers(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body EnableMigrationInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body EnableMigrationInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Query("deleteOption") String deleteOption, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Query("deleteOption") String deleteOption, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateMigrationItemInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateMigrationItemInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems migrate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/migrate") + Observable> migrate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body MigrateInput migrateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginMigrate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/migrate") + Observable> beginMigrate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body MigrateInput migrateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems testMigrate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/testMigrate") + Observable> testMigrate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestMigrateInput testMigrateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginTestMigrate" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/testMigrate") + Observable> beginTestMigrate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestMigrateInput testMigrateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems testMigrateCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/testMigrateCleanup") + Observable> testMigrateCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestMigrateCleanupInput testMigrateCleanupInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems beginTestMigrateCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationMigrationItems/{migrationItemName}/testMigrateCleanup") + Observable> beginTestMigrateCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("migrationItemName") String migrationItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestMigrateCleanupInput testMigrateCleanupInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationMigrationItems") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Query("skipToken") String skipToken, @Query("$filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems listByReplicationProtectionContainersNext" }) + @GET + Observable> listByReplicationProtectionContainersNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationMigrationItems listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainers(final String fabricName, final String protectionContainerName) { + ServiceResponse> response = listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersWithServiceResponseAsync(fabricName, protectionContainerName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable>> listByReplicationProtectionContainersWithServiceResponseAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersSinglePageAsync(final String fabricName, final String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectionContainers(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner get(String fabricName, String protectionContainerName, String migrationItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().single().body(); + } + + /** + * Gets the details of a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String migrationItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName), serviceCallback); + } + + /** + * Gets the details of a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String migrationItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a migration item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner create(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().last().body(); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + EnableMigrationInput input = new EnableMigrationInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginCreate(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().single().body(); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables migration. + * The operation to create an ASR migration item (enable migration). + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Enable migration input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, EnableMigrationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + EnableMigrationInput input = new EnableMigrationInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String migrationItemName) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().last().body(); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String migrationItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName), serviceCallback); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String migrationItemName) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String deleteOption = null; + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), deleteOption, this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption).toBlocking().last().body(); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption), serviceCallback); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), deleteOption, this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String migrationItemName) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().single().body(); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String migrationItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName), serviceCallback); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String migrationItemName) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String deleteOption = null; + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), deleteOption, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption).toBlocking().single().body(); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption), serviceCallback); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, deleteOption).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the migration item. + * The operation to delete an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param deleteOption The delete option. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, String deleteOption) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), deleteOption, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner update(String fabricName, String protectionContainerName, String migrationItemName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().last().body(); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String migrationItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName), serviceCallback); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String migrationItemName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateMigrationItemInputProperties properties = null; + UpdateMigrationItemInput input = new UpdateMigrationItemInput(); + input.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner update(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().last().body(); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateMigrationItemInput input = new UpdateMigrationItemInput(); + input.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginUpdate(String fabricName, String protectionContainerName, String migrationItemName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).toBlocking().single().body(); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String migrationItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName), serviceCallback); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String migrationItemName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateMigrationItemInputProperties properties = null; + UpdateMigrationItemInput input = new UpdateMigrationItemInput(); + input.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginUpdate(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().single().body(); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates migration item. + * The operation to update the recovery settings of an ASR migration item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Update migration item input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, UpdateMigrationItemInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateMigrationItemInput input = new UpdateMigrationItemInput(); + input.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner migrate(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + return migrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().last().body(); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture migrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(migrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable migrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + return migrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> migrateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + MigrateInput migrateInput = new MigrateInput(); + migrateInput.withProperties(properties); + Observable> observable = service.migrate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), migrateInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginMigrate(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + return beginMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().single().body(); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + return beginMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Migrate item. + * The operation to initiate migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginMigrateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, MigrateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + MigrateInput migrateInput = new MigrateInput(); + migrateInput.withProperties(properties); + return service.beginMigrate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), migrateInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginMigrateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginMigrateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner testMigrate(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + return testMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().last().body(); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + return testMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testMigrateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestMigrateInput testMigrateInput = new TestMigrateInput(); + testMigrateInput.withProperties(properties); + Observable> observable = service.testMigrate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), testMigrateInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginTestMigrate(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + return beginTestMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().single().body(); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginTestMigrateAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + return beginTestMigrateWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Test migrate item. + * The operation to initiate test migration of the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginTestMigrateWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestMigrateInput testMigrateInput = new TestMigrateInput(); + testMigrateInput.withProperties(properties); + return service.beginTestMigrate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), testMigrateInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestMigrateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestMigrateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner testMigrateCleanup(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + return testMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().last().body(); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + return testMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testMigrateCleanupWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestMigrateCleanupInput testMigrateCleanupInput = new TestMigrateCleanupInput(); + testMigrateCleanupInput.withProperties(properties); + Observable> observable = service.testMigrateCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), testMigrateCleanupInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the MigrationItemInner object if successful. + */ + public MigrationItemInner beginTestMigrateCleanup(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + return beginTestMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).toBlocking().single().body(); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties), serviceCallback); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable beginTestMigrateCleanupAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + return beginTestMigrateCleanupWithServiceResponseAsync(fabricName, protectionContainerName, migrationItemName, properties).map(new Func1, MigrationItemInner>() { + @Override + public MigrationItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Test migrate cleanup. + * The operation to initiate test migrate cleanup. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param migrationItemName Migration item name. + * @param properties Test migrate cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the MigrationItemInner object + */ + public Observable> beginTestMigrateCleanupWithServiceResponseAsync(String fabricName, String protectionContainerName, String migrationItemName, TestMigrateCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (migrationItemName == null) { + throw new IllegalArgumentException("Parameter migrationItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestMigrateCleanupInput testMigrateCleanupInput = new TestMigrateCleanupInput(); + testMigrateCleanupInput.withProperties(properties); + return service.beginTestMigrateCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, migrationItemName, this.client.apiVersion(), this.client.acceptLanguage(), testMigrateCleanupInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestMigrateCleanupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestMigrateCleanupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of migration items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationItemInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of migration items in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of migration items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String skipToken = null; + final String filter = null; + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), skipToken, filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + * @param skipToken The pagination token. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationItemInner> object if successful. + */ + public PagedList list(final String skipToken, final String filter) { + ServiceResponse> response = listSinglePageAsync(skipToken, filter).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of migration items in the vault. + * + * @param skipToken The pagination token. + * @param filter OData filter options. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final String skipToken, final String filter, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(skipToken, filter), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of migration items in the vault. + * + * @param skipToken The pagination token. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable> listAsync(final String skipToken, final String filter) { + return listWithServiceResponseAsync(skipToken, filter) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + * @param skipToken The pagination token. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable>> listWithServiceResponseAsync(final String skipToken, final String filter) { + return listSinglePageAsync(skipToken, filter) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + ServiceResponse> * @param skipToken The pagination token. + ServiceResponse> * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync(final String skipToken, final String filter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), skipToken, filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainersNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable> listByReplicationProtectionContainersNextAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable>> listByReplicationProtectionContainersNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of migration items in the protection container. + * Gets the list of ASR migration items in the protection container. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectionContainersNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of migration items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<MigrationItemInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of migration items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of migration items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<MigrationItemInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of migration items in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<MigrationItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsImpl.java new file mode 100644 index 0000000000000..49799c89c5b78 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsImpl.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.NetworkMapping; + +class ReplicationNetworkMappingsImpl extends WrapperImpl implements ReplicationNetworkMappings { + private final RecoveryServicesManager manager; + + ReplicationNetworkMappingsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationNetworkMappings()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public NetworkMappingImpl define(String name) { + return wrapModel(name); + } + + private NetworkMappingImpl wrapModel(NetworkMappingInner inner) { + return new NetworkMappingImpl(inner, manager()); + } + + private NetworkMappingImpl wrapModel(String name) { + return new NetworkMappingImpl(name, this.manager()); + } + + @Override + public Observable listAsync() { + ReplicationNetworkMappingsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public NetworkMapping call(NetworkMappingInner inner) { + return new NetworkMappingImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationNetworksAsync(final String fabricName, final String networkName) { + ReplicationNetworkMappingsInner client = this.inner(); + return client.listByReplicationNetworksAsync(fabricName, networkName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public NetworkMapping call(NetworkMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String networkName, String networkMappingName) { + ReplicationNetworkMappingsInner client = this.inner(); + return client.getAsync(fabricName, networkName, networkMappingName) + .map(new Func1() { + @Override + public NetworkMapping call(NetworkMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String networkName, String networkMappingName) { + ReplicationNetworkMappingsInner client = this.inner(); + return client.deleteAsync(fabricName, networkName, networkMappingName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsInner.java new file mode 100644 index 0000000000000..568b12a577259 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworkMappingsInner.java @@ -0,0 +1,1672 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateNetworkMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateNetworkMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateNetworkMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateNetworkMappingInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationNetworkMappings. + */ +public class ReplicationNetworkMappingsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationNetworkMappingsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationNetworkMappingsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationNetworkMappingsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationNetworkMappingsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationNetworkMappings to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationNetworkMappingsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings listByReplicationNetworks" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings") + Observable> listByReplicationNetworks(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateNetworkMappingInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateNetworkMappingInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateNetworkMappingInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}/replicationNetworkMappings/{networkMappingName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Path("networkMappingName") String networkMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateNetworkMappingInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationNetworkMappings") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings listByReplicationNetworksNext" }) + @GET + Observable> listByReplicationNetworksNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworkMappings listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkMappingInner> object if successful. + */ + public PagedList listByReplicationNetworks(final String fabricName, final String networkName) { + ServiceResponse> response = listByReplicationNetworksSinglePageAsync(fabricName, networkName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationNetworksNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationNetworksAsync(final String fabricName, final String networkName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationNetworksSinglePageAsync(fabricName, networkName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationNetworksNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable> listByReplicationNetworksAsync(final String fabricName, final String networkName) { + return listByReplicationNetworksWithServiceResponseAsync(fabricName, networkName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable>> listByReplicationNetworksWithServiceResponseAsync(final String fabricName, final String networkName) { + return listByReplicationNetworksSinglePageAsync(fabricName, networkName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationNetworksNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + ServiceResponse> * @param fabricName Primary fabric name. + ServiceResponse> * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationNetworksSinglePageAsync(final String fabricName, final String networkName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationNetworks(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationNetworksDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationNetworksDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets network mapping by name. + * Gets the details of an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner get(String fabricName, String networkName, String networkMappingName) { + return getWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().single().body(); + } + + /** + * Gets network mapping by name. + * Gets the details of an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Gets network mapping by name. + * Gets the details of an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable getAsync(String fabricName, String networkName, String networkMappingName) { + return getWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets network mapping by name. + * Gets the details of an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner create(String fabricName, String networkName, String networkMappingName) { + return createWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().last().body(); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String networkName, String networkMappingName) { + return createWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateNetworkMappingInputProperties properties = null; + CreateNetworkMappingInput input = new CreateNetworkMappingInput(); + input.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner create(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).toBlocking().last().body(); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties), serviceCallback); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateNetworkMappingInput input = new CreateNetworkMappingInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner beginCreate(String fabricName, String networkName, String networkMappingName) { + return beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().single().body(); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String networkName, String networkMappingName) { + return beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateNetworkMappingInputProperties properties = null; + CreateNetworkMappingInput input = new CreateNetworkMappingInput(); + input.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner beginCreate(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).toBlocking().single().body(); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties), serviceCallback); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates network mapping. + * The operation to create an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties Input properties for creating network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName, CreateNetworkMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateNetworkMappingInput input = new CreateNetworkMappingInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String networkName, String networkMappingName) { + deleteWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().last().body(); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String networkName, String networkMappingName) { + return deleteWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String networkName, String networkMappingName) { + beginDeleteWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().single().body(); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String networkName, String networkMappingName) { + return beginDeleteWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete network mapping. + * The operation to delete a network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName ARM Resource Name for network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner update(String fabricName, String networkName, String networkMappingName) { + return updateWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().last().body(); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String networkName, String networkMappingName) { + return updateWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateNetworkMappingInputProperties properties = null; + UpdateNetworkMappingInput input = new UpdateNetworkMappingInput(); + input.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner update(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).toBlocking().last().body(); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties), serviceCallback); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateNetworkMappingInput input = new UpdateNetworkMappingInput(); + input.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner beginUpdate(String fabricName, String networkName, String networkMappingName) { + return beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName).toBlocking().single().body(); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String networkName, String networkMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName), serviceCallback); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable beginUpdateAsync(String fabricName, String networkName, String networkMappingName) { + return beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateNetworkMappingInputProperties properties = null; + UpdateNetworkMappingInput input = new UpdateNetworkMappingInput(); + input.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkMappingInner object if successful. + */ + public NetworkMappingInner beginUpdate(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).toBlocking().single().body(); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties), serviceCallback); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable beginUpdateAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, networkName, networkMappingName, properties).map(new Func1, NetworkMappingInner>() { + @Override + public NetworkMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates network mapping. + * The operation to update an ASR network mapping. + * + * @param fabricName Primary fabric name. + * @param networkName Primary network name. + * @param networkMappingName Network mapping name. + * @param properties The input properties needed to update network mapping. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkMappingInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String networkName, String networkMappingName, UpdateNetworkMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (networkMappingName == null) { + throw new IllegalArgumentException("Parameter networkMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateNetworkMappingInput input = new UpdateNetworkMappingInput(); + input.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, networkMappingName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkMappingInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkMappingInner> object if successful. + */ + public PagedList listByReplicationNetworksNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationNetworksNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationNetworksNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationNetworksNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationNetworksNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationNetworksNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable> listByReplicationNetworksNextAsync(final String nextPageLink) { + return listByReplicationNetworksNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable>> listByReplicationNetworksNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationNetworksNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationNetworksNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all the network mappings under a network. + * Lists all ASR network mappings for the specified network. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationNetworksNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationNetworksNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationNetworksNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationNetworksNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkMappingInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkMappingInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all the network mappings under a vault. + * Lists all ASR network mappings in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksImpl.java new file mode 100644 index 0000000000000..dc11fe2060e9a --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksImpl.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Network; + +class ReplicationNetworksImpl extends WrapperImpl implements ReplicationNetworks { + private final RecoveryServicesManager manager; + + ReplicationNetworksImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationNetworks()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private NetworkImpl wrapModel(NetworkInner inner) { + return new NetworkImpl(inner, manager()); + } + + @Override + public Observable listAsync() { + ReplicationNetworksInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Network call(NetworkInner inner) { + return new NetworkImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationNetworksInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Network call(NetworkInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String networkName) { + ReplicationNetworksInner client = this.inner(); + return client.getAsync(fabricName, networkName) + .map(new Func1() { + @Override + public Network call(NetworkInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksInner.java new file mode 100644 index 0000000000000..48cb656a28ed5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationNetworksInner.java @@ -0,0 +1,654 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationNetworks. + */ +public class ReplicationNetworksInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationNetworksService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationNetworksInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationNetworksInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationNetworksService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationNetworks to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationNetworksService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationNetworks/{networkName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("networkName") String networkName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationNetworks") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationNetworks listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param fabricName Fabric name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + ServiceResponse> * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets a network with specified server id and network name. + * Gets the details of a network. + * + * @param fabricName Server Id. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the NetworkInner object if successful. + */ + public NetworkInner get(String fabricName, String networkName) { + return getWithServiceResponseAsync(fabricName, networkName).toBlocking().single().body(); + } + + /** + * Gets a network with specified server id and network name. + * Gets the details of a network. + * + * @param fabricName Server Id. + * @param networkName Primary network name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String networkName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, networkName), serviceCallback); + } + + /** + * Gets a network with specified server id and network name. + * Gets the details of a network. + * + * @param fabricName Server Id. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkInner object + */ + public Observable getAsync(String fabricName, String networkName) { + return getWithServiceResponseAsync(fabricName, networkName).map(new Func1, NetworkInner>() { + @Override + public NetworkInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a network with specified server id and network name. + * Gets the details of a network. + * + * @param fabricName Server Id. + * @param networkName Primary network name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the NetworkInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String networkName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (networkName == null) { + throw new IllegalArgumentException("Parameter networkName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, networkName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of networks under a fabric. + * Lists the networks available for a fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<NetworkInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<NetworkInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of networks. View-only API. + * Lists the networks available in a vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<NetworkInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesImpl.java new file mode 100644 index 0000000000000..1860cccd3f648 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesImpl.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.Policy; + +class ReplicationPoliciesImpl extends WrapperImpl implements ReplicationPolicies { + private final RecoveryServicesManager manager; + + ReplicationPoliciesImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationPolicies()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public PolicyImpl define(String name) { + return wrapModel(name); + } + + private PolicyImpl wrapModel(PolicyInner inner) { + return new PolicyImpl(inner, manager()); + } + + private PolicyImpl wrapModel(String name) { + return new PolicyImpl(name, this.manager()); + } + + @Override + public Observable listAsync() { + ReplicationPoliciesInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Policy call(PolicyInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String policyName) { + ReplicationPoliciesInner client = this.inner(); + return client.getAsync(policyName) + .map(new Func1() { + @Override + public Policy call(PolicyInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String policyName) { + ReplicationPoliciesInner client = this.inner(); + return client.deleteAsync(policyName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesInner.java new file mode 100644 index 0000000000000..7aa1e83db4d76 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationPoliciesInner.java @@ -0,0 +1,1260 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreatePolicyInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreatePolicyInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdatePolicyInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdatePolicyInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationPolicies. + */ +public class ReplicationPoliciesInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationPoliciesService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationPoliciesInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationPoliciesInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationPoliciesService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationPolicies to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationPoliciesService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreatePolicyInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreatePolicyInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdatePolicyInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationPolicies/{policyName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("policyName") String policyName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdatePolicyInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationPolicies listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<PolicyInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<PolicyInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<PolicyInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<PolicyInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the requested policy. + * Gets the details of a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner get(String policyName) { + return getWithServiceResponseAsync(policyName).toBlocking().single().body(); + } + + /** + * Gets the requested policy. + * Gets the details of a replication policy. + * + * @param policyName Replication policy name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Gets the requested policy. + * Gets the details of a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable getAsync(String policyName) { + return getWithServiceResponseAsync(policyName).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the requested policy. + * Gets the details of a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable> getWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner create(String policyName) { + return createWithServiceResponseAsync(policyName).toBlocking().last().body(); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String policyName) { + return createWithServiceResponseAsync(policyName).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreatePolicyInputProperties properties = null; + CreatePolicyInput input = new CreatePolicyInput(); + input.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner create(String policyName, CreatePolicyInputProperties properties) { + return createWithServiceResponseAsync(policyName, properties).toBlocking().last().body(); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String policyName, CreatePolicyInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(policyName, properties), serviceCallback); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String policyName, CreatePolicyInputProperties properties) { + return createWithServiceResponseAsync(policyName, properties).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String policyName, CreatePolicyInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreatePolicyInput input = new CreatePolicyInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner beginCreate(String policyName) { + return beginCreateWithServiceResponseAsync(policyName).toBlocking().single().body(); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable beginCreateAsync(String policyName) { + return beginCreateWithServiceResponseAsync(policyName).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreatePolicyInputProperties properties = null; + CreatePolicyInput input = new CreatePolicyInput(); + input.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner beginCreate(String policyName, CreatePolicyInputProperties properties) { + return beginCreateWithServiceResponseAsync(policyName, properties).toBlocking().single().body(); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String policyName, CreatePolicyInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(policyName, properties), serviceCallback); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable beginCreateAsync(String policyName, CreatePolicyInputProperties properties) { + return beginCreateWithServiceResponseAsync(policyName, properties).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates the policy. + * The operation to create a replication policy. + * + * @param policyName Replication policy name + * @param properties Policy creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String policyName, CreatePolicyInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreatePolicyInput input = new CreatePolicyInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String policyName) { + deleteWithServiceResponseAsync(policyName).toBlocking().last().body(); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String policyName) { + return deleteWithServiceResponseAsync(policyName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String policyName) { + beginDeleteWithServiceResponseAsync(policyName).toBlocking().single().body(); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String policyName) { + return beginDeleteWithServiceResponseAsync(policyName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete the policy. + * The operation to delete a replication policy. + * + * @param policyName Replication policy name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner update(String policyName) { + return updateWithServiceResponseAsync(policyName).toBlocking().last().body(); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String policyName) { + return updateWithServiceResponseAsync(policyName).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdatePolicyInputProperties properties = null; + UpdatePolicyInput input = new UpdatePolicyInput(); + input.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner update(String policyName, UpdatePolicyInputProperties properties) { + return updateWithServiceResponseAsync(policyName, properties).toBlocking().last().body(); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String policyName, UpdatePolicyInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(policyName, properties), serviceCallback); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String policyName, UpdatePolicyInputProperties properties) { + return updateWithServiceResponseAsync(policyName, properties).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String policyName, UpdatePolicyInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdatePolicyInput input = new UpdatePolicyInput(); + input.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner beginUpdate(String policyName) { + return beginUpdateWithServiceResponseAsync(policyName).toBlocking().single().body(); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String policyName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(policyName), serviceCallback); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable beginUpdateAsync(String policyName) { + return beginUpdateWithServiceResponseAsync(policyName).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String policyName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdatePolicyInputProperties properties = null; + UpdatePolicyInput input = new UpdatePolicyInput(); + input.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PolicyInner object if successful. + */ + public PolicyInner beginUpdate(String policyName, UpdatePolicyInputProperties properties) { + return beginUpdateWithServiceResponseAsync(policyName, properties).toBlocking().single().body(); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String policyName, UpdatePolicyInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(policyName, properties), serviceCallback); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable beginUpdateAsync(String policyName, UpdatePolicyInputProperties properties) { + return beginUpdateWithServiceResponseAsync(policyName, properties).map(new Func1, PolicyInner>() { + @Override + public PolicyInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the policy. + * The operation to update a replication policy. + * + * @param policyName Policy Id. + * @param properties The ReplicationProviderSettings. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PolicyInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String policyName, UpdatePolicyInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (policyName == null) { + throw new IllegalArgumentException("Parameter policyName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdatePolicyInput input = new UpdatePolicyInput(); + input.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), policyName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<PolicyInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<PolicyInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<PolicyInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of replication policies. + * Lists the replication policies for a vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<PolicyInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsImpl.java new file mode 100644 index 0000000000000..9fa1b725b101c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsImpl.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectableItems; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectableItem; + +class ReplicationProtectableItemsImpl extends WrapperImpl implements ReplicationProtectableItems { + private final RecoveryServicesManager manager; + + ReplicationProtectableItemsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationProtectableItems()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private ProtectableItemImpl wrapModel(ProtectableItemInner inner) { + return new ProtectableItemImpl(inner, manager()); + } + + @Override + public Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + ReplicationProtectableItemsInner client = this.inner(); + return client.listByReplicationProtectionContainersAsync(fabricName, protectionContainerName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ProtectableItem call(ProtectableItemInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String protectableItemName) { + ReplicationProtectableItemsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, protectableItemName) + .map(new Func1() { + @Override + public ProtectableItem call(ProtectableItemInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsInner.java new file mode 100644 index 0000000000000..297f719c82006 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectableItemsInner.java @@ -0,0 +1,560 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationProtectableItems. + */ +public class ReplicationProtectableItemsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationProtectableItemsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationProtectableItemsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationProtectableItemsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationProtectableItemsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationProtectableItems to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationProtectableItemsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectableItems listByReplicationProtectionContainers" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectableItems") + Observable> listByReplicationProtectionContainers(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Query("$filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectableItems get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectableItems/{protectableItemName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("protectableItemName") String protectableItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectableItems listByReplicationProtectionContainersNext" }) + @GET + Observable> listByReplicationProtectionContainersNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectableItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainers(final String fabricName, final String protectionContainerName) { + ServiceResponse> response = listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersWithServiceResponseAsync(fabricName, protectionContainerName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable>> listByReplicationProtectionContainersWithServiceResponseAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectableItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersSinglePageAsync(final String fabricName, final String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String filter = null; + return service.listByReplicationProtectionContainers(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectableItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainers(final String fabricName, final String protectionContainerName, final String filter) { + ServiceResponse> response = listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName, filter).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param filter OData filter options. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final String filter, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName, filter), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final String filter) { + return listByReplicationProtectionContainersWithServiceResponseAsync(fabricName, protectionContainerName, filter) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable>> listByReplicationProtectionContainersWithServiceResponseAsync(final String fabricName, final String protectionContainerName, final String filter) { + return listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName, filter) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param protectionContainerName Protection container name. + ServiceResponse> * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectableItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersSinglePageAsync(final String fabricName, final String protectionContainerName, final String filter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectionContainers(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a protectable item. + * The operation to get the details of a protectable item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param protectableItemName Protectable item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectableItemInner object if successful. + */ + public ProtectableItemInner get(String fabricName, String protectionContainerName, String protectableItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, protectableItemName).toBlocking().single().body(); + } + + /** + * Gets the details of a protectable item. + * The operation to get the details of a protectable item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param protectableItemName Protectable item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String protectableItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, protectableItemName), serviceCallback); + } + + /** + * Gets the details of a protectable item. + * The operation to get the details of a protectable item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param protectableItemName Protectable item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectableItemInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String protectableItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, protectableItemName).map(new Func1, ProtectableItemInner>() { + @Override + public ProtectableItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a protectable item. + * The operation to get the details of a protectable item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param protectableItemName Protectable item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectableItemInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String protectableItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (protectableItemName == null) { + throw new IllegalArgumentException("Parameter protectableItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, protectableItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectableItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainersNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable> listByReplicationProtectionContainersNextAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectableItemInner> object + */ + public Observable>> listByReplicationProtectionContainersNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protectable items. + * Lists the protectable items in a protection container. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectableItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectionContainersNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemImpl.java new file mode 100644 index 0000000000000..0b0d8c4e1e057 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemImpl.java @@ -0,0 +1,145 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItem; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateReplicationProtectedItemInputProperties; +import java.util.List; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableProtectionInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItemProperties; +import rx.functions.Func1; + +class ReplicationProtectedItemImpl extends CreatableUpdatableImpl implements ReplicationProtectedItem, ReplicationProtectedItem.Definition, ReplicationProtectedItem.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String protectionContainerName; + private String replicatedProtectedItemName; + private EnableProtectionInputProperties cproperties; + private UpdateReplicationProtectedItemInputProperties uproperties; + + ReplicationProtectedItemImpl(String name, RecoveryServicesManager manager) { + super(name, new ReplicationProtectedItemInner()); + this.manager = manager; + // Set resource name + this.replicatedProtectedItemName = name; + // + this.cproperties = new EnableProtectionInputProperties(); + this.uproperties = new UpdateReplicationProtectedItemInputProperties(); + } + + ReplicationProtectedItemImpl(ReplicationProtectedItemInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.replicatedProtectedItemName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.protectionContainerName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectionContainers"); + this.replicatedProtectedItemName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationProtectedItems"); + // + this.cproperties = new EnableProtectionInputProperties(); + this.uproperties = new UpdateReplicationProtectedItemInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationProtectedItemsInner client = this.manager().inner().replicationProtectedItems(); + return client.createAsync(this.fabricName, this.protectionContainerName, this.replicatedProtectedItemName, this.cproperties) + .map(new Func1() { + @Override + public ReplicationProtectedItemInner call(ReplicationProtectedItemInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationProtectedItemsInner client = this.manager().inner().replicationProtectedItems(); + return client.updateAsync(this.fabricName, this.protectionContainerName, this.replicatedProtectedItemName, this.uproperties) + .map(new Func1() { + @Override + public ReplicationProtectedItemInner call(ReplicationProtectedItemInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationProtectedItemsInner client = this.manager().inner().replicationProtectedItems(); + return client.getAsync(this.fabricName, this.protectionContainerName, this.replicatedProtectedItemName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new EnableProtectionInputProperties(); + this.uproperties = new UpdateReplicationProtectedItemInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public ReplicationProtectedItemProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public ReplicationProtectedItemImpl withExistingReplicationProtectionContainer(String fabricName, String protectionContainerName) { + this.fabricName = fabricName; + this.protectionContainerName = protectionContainerName; + return this; + } + + @Override + public ReplicationProtectedItemImpl withProperties(EnableProtectionInputProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public ReplicationProtectedItemImpl withProperties(UpdateReplicationProtectedItemInputProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemInner.java new file mode 100644 index 0000000000000..a9cbea5d986c0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItemProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Replication protected item. + */ +public class ReplicationProtectedItemInner extends ProxyResource { + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private ReplicationProtectedItemProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the custom data. + * + * @return the properties value + */ + public ReplicationProtectedItemProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the ReplicationProtectedItemInner object itself. + */ + public ReplicationProtectedItemInner withProperties(ReplicationProtectedItemProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the ReplicationProtectedItemInner object itself. + */ + public ReplicationProtectedItemInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsImpl.java new file mode 100644 index 0000000000000..3120b5920e806 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsImpl.java @@ -0,0 +1,214 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItem; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestFailoverCleanupInputProperties; + +class ReplicationProtectedItemsImpl extends WrapperImpl implements ReplicationProtectedItems { + private final RecoveryServicesManager manager; + + ReplicationProtectedItemsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationProtectedItems()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public ReplicationProtectedItemImpl define(String name) { + return wrapModel(name); + } + + private ReplicationProtectedItemImpl wrapModel(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + + private ReplicationProtectedItemImpl wrapModel(String name) { + return new ReplicationProtectedItemImpl(name, this.manager()); + } + + @Override + public Observable applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.applyRecoveryPointAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable failoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.failoverCommitAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.plannedFailoverAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.deleteAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toCompletable(); + } + + @Override + public Observable repairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.repairReplicationAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.reprotectAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.testFailoverAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable testFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + ReplicationProtectedItemsInner client = this.inner(); + return client.testFailoverCleanupAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.unplannedFailoverAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.updateMobilityServiceAsync(fabricName, protectionContainerName, replicationProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationProtectedItemsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return new ReplicationProtectedItemImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.listByReplicationProtectionContainersAsync(fabricName, protectionContainerName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1() { + @Override + public ReplicationProtectedItem call(ReplicationProtectedItemInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable purgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + ReplicationProtectedItemsInner client = this.inner(); + return client.purgeAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsInner.java new file mode 100644 index 0000000000000..0928578a288ed --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectedItemsInner.java @@ -0,0 +1,5215 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ApplyRecoveryPointInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ApplyRecoveryPointInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.DisableProtectionInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.DisableProtectionInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableProtectionInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.EnableProtectionInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.PlannedFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.PlannedFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReverseReplicationInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReverseReplicationInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestFailoverCleanupInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestFailoverCleanupInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TestFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UnplannedFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UnplannedFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateMobilityServiceRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateMobilityServiceRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateReplicationProtectedItemInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateReplicationProtectedItemInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationProtectedItems. + */ +public class ReplicationProtectedItemsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationProtectedItemsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationProtectedItemsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationProtectedItemsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationProtectedItemsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationProtectedItems to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationProtectedItemsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems listByReplicationProtectionContainers" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems") + Observable> listByReplicationProtectionContainers(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body EnableProtectionInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body EnableProtectionInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems purge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}", method = "DELETE", hasBody = true) + Observable> purge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginPurge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}", method = "DELETE", hasBody = true) + Observable> beginPurge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateReplicationProtectedItemInput updateProtectionInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateReplicationProtectedItemInput updateProtectionInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems applyRecoveryPoint" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/applyRecoveryPoint") + Observable> applyRecoveryPoint(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ApplyRecoveryPointInput applyRecoveryPointInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginApplyRecoveryPoint" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/applyRecoveryPoint") + Observable> beginApplyRecoveryPoint(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ApplyRecoveryPointInput applyRecoveryPointInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems failoverCommit" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/failoverCommit") + Observable> failoverCommit(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginFailoverCommit" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/failoverCommit") + Observable> beginFailoverCommit(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems plannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/plannedFailover") + Observable> plannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body PlannedFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginPlannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/plannedFailover") + Observable> beginPlannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body PlannedFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems delete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/remove") + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body DisableProtectionInput disableProtectionInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginDelete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/remove") + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body DisableProtectionInput disableProtectionInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems repairReplication" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/repairReplication") + Observable> repairReplication(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginRepairReplication" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/repairReplication") + Observable> beginRepairReplication(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems reprotect" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/reProtect") + Observable> reprotect(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ReverseReplicationInput rrInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginReprotect" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/reProtect") + Observable> beginReprotect(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body ReverseReplicationInput rrInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems testFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/testFailover") + Observable> testFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginTestFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/testFailover") + Observable> beginTestFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems testFailoverCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/testFailoverCleanup") + Observable> testFailoverCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestFailoverCleanupInput cleanupInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginTestFailoverCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/testFailoverCleanup") + Observable> beginTestFailoverCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body TestFailoverCleanupInput cleanupInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems unplannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/unplannedFailover") + Observable> unplannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UnplannedFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginUnplannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/unplannedFailover") + Observable> beginUnplannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UnplannedFailoverInput failoverInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems updateMobilityService" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicationProtectedItemName}/updateMobilityService") + Observable> updateMobilityService(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicationProtectedItemName") String replicationProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateMobilityServiceRequest updateMobilityServiceRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems beginUpdateMobilityService" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicationProtectedItemName}/updateMobilityService") + Observable> beginUpdateMobilityService(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicationProtectedItemName") String replicationProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateMobilityServiceRequest updateMobilityServiceRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationProtectedItems") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Query("skipToken") String skipToken, @Query("$filter") String filter, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems listByReplicationProtectionContainersNext" }) + @GET + Observable> listByReplicationProtectionContainersNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectedItems listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ReplicationProtectedItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainers(final String fabricName, final String protectionContainerName) { + ServiceResponse> response = listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersWithServiceResponseAsync(fabricName, protectionContainerName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable>> listByReplicationProtectionContainersWithServiceResponseAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ReplicationProtectedItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersSinglePageAsync(final String fabricName, final String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectionContainers(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a Replication protected item. + * Gets the details of an ASR replication protected item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner get(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Gets the details of a Replication protected item. + * Gets the details of an ASR replication protected item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Gets the details of a Replication protected item. + * Gets the details of an ASR replication protected item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a Replication protected item. + * Gets the details of an ASR replication protected item. + * + * @param fabricName Fabric unique name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner create(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final EnableProtectionInputProperties properties = null; + EnableProtectionInput input = new EnableProtectionInput(); + input.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner create(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + EnableProtectionInput input = new EnableProtectionInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginCreate(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final EnableProtectionInputProperties properties = null; + EnableProtectionInput input = new EnableProtectionInput(); + input.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginCreate(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Enables protection. + * The operation to create an ASR replication protected item (Enable replication). + * + * @param fabricName Name of the fabric. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName A name for the replication protected item. + * @param properties Enable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, EnableProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + EnableProtectionInput input = new EnableProtectionInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void purge(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + purgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture purgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(purgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable purgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return purgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> purgeWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.purge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginPurge(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPurgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginPurgeAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges protection. + * The operation to delete or purge a replication protected item. This operation will force delete the replication protected item. Use the remove operation on replication protected item to perform a clean disable replication for the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginPurgeWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginPurge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPurgeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPurgeDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner update(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateReplicationProtectedItemInputProperties properties = null; + UpdateReplicationProtectedItemInput updateProtectionInput = new UpdateReplicationProtectedItemInput(); + updateProtectionInput.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateProtectionInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner update(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateReplicationProtectedItemInput updateProtectionInput = new UpdateReplicationProtectedItemInput(); + updateProtectionInput.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateProtectionInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUpdate(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateReplicationProtectedItemInputProperties properties = null; + UpdateReplicationProtectedItemInput updateProtectionInput = new UpdateReplicationProtectedItemInput(); + updateProtectionInput.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateProtectionInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUpdate(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates protection. + * The operation to update the recovery settings of an ASR replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Update replication protected item properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UpdateReplicationProtectedItemInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateReplicationProtectedItemInput updateProtectionInput = new UpdateReplicationProtectedItemInput(); + updateProtectionInput.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateProtectionInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner applyRecoveryPoint(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> applyRecoveryPointWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ApplyRecoveryPointInputProperties properties = null; + ApplyRecoveryPointInput applyRecoveryPointInput = new ApplyRecoveryPointInput(); + applyRecoveryPointInput.withProperties(null); + Observable> observable = service.applyRecoveryPoint(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), applyRecoveryPointInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner applyRecoveryPoint(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + return applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable applyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + return applyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> applyRecoveryPointWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ApplyRecoveryPointInput applyRecoveryPointInput = new ApplyRecoveryPointInput(); + applyRecoveryPointInput.withProperties(properties); + Observable> observable = service.applyRecoveryPoint(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), applyRecoveryPointInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginApplyRecoveryPoint(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginApplyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginApplyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginApplyRecoveryPointWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ApplyRecoveryPointInputProperties properties = null; + ApplyRecoveryPointInput applyRecoveryPointInput = new ApplyRecoveryPointInput(); + applyRecoveryPointInput.withProperties(null); + return service.beginApplyRecoveryPoint(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), applyRecoveryPointInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginApplyRecoveryPointDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginApplyRecoveryPoint(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + return beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginApplyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginApplyRecoveryPointAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + return beginApplyRecoveryPointWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Change or apply recovery point. + * The operation to change the recovery point of a failed over replication protected item. + * + * @param fabricName The ARM fabric name. + * @param protectionContainerName The protection container name. + * @param replicatedProtectedItemName The replicated protected item's name. + * @param properties The input properties to apply recovery point. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginApplyRecoveryPointWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ApplyRecoveryPointInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ApplyRecoveryPointInput applyRecoveryPointInput = new ApplyRecoveryPointInput(); + applyRecoveryPointInput.withProperties(properties); + return service.beginApplyRecoveryPoint(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), applyRecoveryPointInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginApplyRecoveryPointDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginApplyRecoveryPointDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner failoverCommit(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return failoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture failoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(failoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable failoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return failoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> failoverCommitWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.failoverCommit(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginFailoverCommit(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginFailoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginFailoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginFailoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginFailoverCommitAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginFailoverCommitWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute commit failover. + * Operation to commit the failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginFailoverCommitWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginFailoverCommit(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginFailoverCommitDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginFailoverCommitDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner plannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> plannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final PlannedFailoverInputProperties properties = null; + PlannedFailoverInput failoverInput = new PlannedFailoverInput(); + failoverInput.withProperties(null); + Observable> observable = service.plannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner plannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + return plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable plannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + return plannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> plannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + PlannedFailoverInput failoverInput = new PlannedFailoverInput(); + failoverInput.withProperties(properties); + Observable> observable = service.plannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginPlannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPlannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginPlannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginPlannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final PlannedFailoverInputProperties properties = null; + PlannedFailoverInput failoverInput = new PlannedFailoverInput(); + failoverInput.withProperties(null); + return service.beginPlannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPlannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginPlannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + return beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPlannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginPlannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + return beginPlannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover. + * Operation to initiate a planned failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginPlannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, PlannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + PlannedFailoverInput failoverInput = new PlannedFailoverInput(); + failoverInput.withProperties(properties); + return service.beginPlannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPlannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPlannedFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final DisableProtectionInputProperties properties = null; + DisableProtectionInput disableProtectionInput = new DisableProtectionInput(); + disableProtectionInput.withProperties(null); + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), disableProtectionInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + DisableProtectionInput disableProtectionInput = new DisableProtectionInput(); + disableProtectionInput.withProperties(properties); + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), disableProtectionInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final DisableProtectionInputProperties properties = null; + DisableProtectionInput disableProtectionInput = new DisableProtectionInput(); + disableProtectionInput.withProperties(null); + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), disableProtectionInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Disables protection. + * The operation to disable replication on a replication protected item. This will also remove the item. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Disable protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, DisableProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + DisableProtectionInput disableProtectionInput = new DisableProtectionInput(); + disableProtectionInput.withProperties(properties); + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), disableProtectionInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner repairReplication(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return repairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture repairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(repairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable repairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return repairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> repairReplicationWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.repairReplication(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginRepairReplication(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginRepairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRepairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRepairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginRepairReplicationAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginRepairReplicationWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Resynchronize or repair replication. + * The operation to start resynchronize/repair replication for a replication protected item requiring resynchronization. + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the container. + * @param replicatedProtectedItemName The name of the replication protected item. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginRepairReplicationWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginRepairReplication(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRepairReplicationDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginRepairReplicationDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner reprotect(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> reprotectWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ReverseReplicationInputProperties properties = null; + ReverseReplicationInput rrInput = new ReverseReplicationInput(); + rrInput.withProperties(null); + Observable> observable = service.reprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), rrInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner reprotect(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + return reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable reprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + return reprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> reprotectWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ReverseReplicationInput rrInput = new ReverseReplicationInput(); + rrInput.withProperties(properties); + Observable> observable = service.reprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), rrInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginReprotect(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginReprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginReprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginReprotectWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final ReverseReplicationInputProperties properties = null; + ReverseReplicationInput rrInput = new ReverseReplicationInput(); + rrInput.withProperties(null); + return service.beginReprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), rrInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginReprotectDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginReprotect(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + return beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginReprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginReprotectAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + return beginReprotectWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute Reverse Replication\Reprotect. + * Operation to reprotect or reverse replicate a failed over replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Reverse replication properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginReprotectWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, ReverseReplicationInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + ReverseReplicationInput rrInput = new ReverseReplicationInput(); + rrInput.withProperties(properties); + return service.beginReprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), rrInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginReprotectDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginReprotectDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner testFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final TestFailoverInputProperties properties = null; + TestFailoverInput failoverInput = new TestFailoverInput(); + failoverInput.withProperties(null); + Observable> observable = service.testFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner testFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + return testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + return testFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + TestFailoverInput failoverInput = new TestFailoverInput(); + failoverInput.withProperties(properties); + Observable> observable = service.testFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginTestFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginTestFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginTestFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final TestFailoverInputProperties properties = null; + TestFailoverInput failoverInput = new TestFailoverInput(); + failoverInput.withProperties(null); + return service.beginTestFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginTestFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + return beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginTestFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + return beginTestFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover. + * Operation to perform a test failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginTestFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + TestFailoverInput failoverInput = new TestFailoverInput(); + failoverInput.withProperties(properties); + return service.beginTestFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner testFailoverCleanup(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + return testFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + return testFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testFailoverCleanupWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestFailoverCleanupInput cleanupInput = new TestFailoverCleanupInput(); + cleanupInput.withProperties(properties); + Observable> observable = service.testFailoverCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), cleanupInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginTestFailoverCleanup(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + return beginTestFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginTestFailoverCleanupAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + return beginTestFailoverCleanupWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover cleanup. + * Operation to clean up the test failover of a replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginTestFailoverCleanupWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, TestFailoverCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + TestFailoverCleanupInput cleanupInput = new TestFailoverCleanupInput(); + cleanupInput.withProperties(properties); + return service.beginTestFailoverCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), cleanupInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestFailoverCleanupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestFailoverCleanupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner unplannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().last().body(); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> unplannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UnplannedFailoverInputProperties properties = null; + UnplannedFailoverInput failoverInput = new UnplannedFailoverInput(); + failoverInput.withProperties(null); + Observable> observable = service.unplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner unplannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + return unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable unplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + return unplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> unplannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UnplannedFailoverInput failoverInput = new UnplannedFailoverInput(); + failoverInput.withProperties(properties); + Observable> observable = service.unplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUnplannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single().body(); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUnplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName), serviceCallback); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUnplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + return beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUnplannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UnplannedFailoverInputProperties properties = null; + UnplannedFailoverInput failoverInput = new UnplannedFailoverInput(); + failoverInput.withProperties(null); + return service.beginUnplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUnplannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUnplannedFailover(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + return beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUnplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties), serviceCallback); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUnplannedFailoverAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + return beginUnplannedFailoverWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover. + * Operation to initiate a failover of the replication protected item. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param properties Planned failover input properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUnplannedFailoverWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicatedProtectedItemName, UnplannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UnplannedFailoverInput failoverInput = new UnplannedFailoverInput(); + failoverInput.withProperties(properties); + return service.beginUnplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), failoverInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUnplannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUnplannedFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner updateMobilityService(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + return updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName).toBlocking().last().body(); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName), serviceCallback); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + return updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateMobilityServiceWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicationProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicationProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateMobilityServiceRequestProperties properties = null; + UpdateMobilityServiceRequest updateMobilityServiceRequest = new UpdateMobilityServiceRequest(); + updateMobilityServiceRequest.withProperties(null); + Observable> observable = service.updateMobilityService(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicationProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateMobilityServiceRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner updateMobilityService(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + return updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties).toBlocking().last().body(); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties), serviceCallback); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + return updateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateMobilityServiceWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicationProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicationProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateMobilityServiceRequest updateMobilityServiceRequest = new UpdateMobilityServiceRequest(); + updateMobilityServiceRequest.withProperties(properties); + Observable> observable = service.updateMobilityService(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicationProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateMobilityServiceRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUpdateMobilityService(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + return beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName).toBlocking().single().body(); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName), serviceCallback); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUpdateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + return beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUpdateMobilityServiceWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicationProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicationProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateMobilityServiceRequestProperties properties = null; + UpdateMobilityServiceRequest updateMobilityServiceRequest = new UpdateMobilityServiceRequest(); + updateMobilityServiceRequest.withProperties(null); + return service.beginUpdateMobilityService(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicationProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateMobilityServiceRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateMobilityServiceDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ReplicationProtectedItemInner object if successful. + */ + public ReplicationProtectedItemInner beginUpdateMobilityService(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + return beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties).toBlocking().single().body(); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties), serviceCallback); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable beginUpdateMobilityServiceAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + return beginUpdateMobilityServiceWithServiceResponseAsync(fabricName, protectionContainerName, replicationProtectedItemName, properties).map(new Func1, ReplicationProtectedItemInner>() { + @Override + public ReplicationProtectedItemInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update the mobility service on a protected item. + * The operation to update(push update) the installed mobility service software on a replication protected item to the latest available version. + * + * @param fabricName The name of the fabric containing the protected item. + * @param protectionContainerName The name of the container containing the protected item. + * @param replicationProtectedItemName The name of the protected item on which the agent is to be updated. + * @param properties The properties of the update mobility service request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ReplicationProtectedItemInner object + */ + public Observable> beginUpdateMobilityServiceWithServiceResponseAsync(String fabricName, String protectionContainerName, String replicationProtectedItemName, UpdateMobilityServiceRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicationProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicationProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateMobilityServiceRequest updateMobilityServiceRequest = new UpdateMobilityServiceRequest(); + updateMobilityServiceRequest.withProperties(properties); + return service.beginUpdateMobilityService(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicationProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), updateMobilityServiceRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateMobilityServiceDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateMobilityServiceDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ReplicationProtectedItemInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ReplicationProtectedItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String skipToken = null; + final String filter = null; + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), skipToken, filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param skipToken The pagination token. Possible values: "FabricId" or "FabricId_CloudId" or null + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ReplicationProtectedItemInner> object if successful. + */ + public PagedList list(final String skipToken, final String filter) { + ServiceResponse> response = listSinglePageAsync(skipToken, filter).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param skipToken The pagination token. Possible values: "FabricId" or "FabricId_CloudId" or null + * @param filter OData filter options. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final String skipToken, final String filter, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(skipToken, filter), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param skipToken The pagination token. Possible values: "FabricId" or "FabricId_CloudId" or null + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable> listAsync(final String skipToken, final String filter) { + return listWithServiceResponseAsync(skipToken, filter) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param skipToken The pagination token. Possible values: "FabricId" or "FabricId_CloudId" or null + * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable>> listWithServiceResponseAsync(final String skipToken, final String filter) { + return listSinglePageAsync(skipToken, filter) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + ServiceResponse> * @param skipToken The pagination token. Possible values: "FabricId" or "FabricId_CloudId" or null + ServiceResponse> * @param filter OData filter options. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ReplicationProtectedItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync(final String skipToken, final String filter) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), skipToken, filter, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ReplicationProtectedItemInner> object if successful. + */ + public PagedList listByReplicationProtectionContainersNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable> listByReplicationProtectionContainersNextAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable>> listByReplicationProtectionContainersNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of Replication protected items. + * Gets the list of ASR replication protected items in the protection container. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ReplicationProtectedItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectionContainersNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ReplicationProtectedItemInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ReplicationProtectedItemInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of replication protected items. + * Gets the list of ASR replication protected items in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ReplicationProtectedItemInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsImpl.java new file mode 100644 index 0000000000000..011d88db4c38f --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsImpl.java @@ -0,0 +1,105 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainerMapping; + +class ReplicationProtectionContainerMappingsImpl extends WrapperImpl implements ReplicationProtectionContainerMappings { + private final RecoveryServicesManager manager; + + ReplicationProtectionContainerMappingsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationProtectionContainerMappings()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public ProtectionContainerMappingImpl define(String name) { + return wrapModel(name); + } + + private ProtectionContainerMappingImpl wrapModel(ProtectionContainerMappingInner inner) { + return new ProtectionContainerMappingImpl(inner, manager()); + } + + private ProtectionContainerMappingImpl wrapModel(String name) { + return new ProtectionContainerMappingImpl(name, this.manager()); + } + + @Override + public Completable deleteAsync(String fabricName, String protectionContainerName, String mappingName) { + ReplicationProtectionContainerMappingsInner client = this.inner(); + return client.deleteAsync(fabricName, protectionContainerName, mappingName).toCompletable(); + } + + @Override + public Observable listAsync() { + ReplicationProtectionContainerMappingsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ProtectionContainerMapping call(ProtectionContainerMappingInner inner) { + return new ProtectionContainerMappingImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + ReplicationProtectionContainerMappingsInner client = this.inner(); + return client.listByReplicationProtectionContainersAsync(fabricName, protectionContainerName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ProtectionContainerMapping call(ProtectionContainerMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName, String mappingName) { + ReplicationProtectionContainerMappingsInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName, mappingName) + .map(new Func1() { + @Override + public ProtectionContainerMapping call(ProtectionContainerMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable purgeAsync(String fabricName, String protectionContainerName, String mappingName) { + ReplicationProtectionContainerMappingsInner client = this.inner(); + return client.purgeAsync(fabricName, protectionContainerName, mappingName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsInner.java new file mode 100644 index 0000000000000..6173b3eda81d8 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainerMappingsInner.java @@ -0,0 +1,2070 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RemoveProtectionContainerMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RemoveProtectionContainerMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateProtectionContainerMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateProtectionContainerMappingInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationProtectionContainerMappings. + */ +public class ReplicationProtectionContainerMappingsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationProtectionContainerMappingsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationProtectionContainerMappingsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationProtectionContainerMappingsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationProtectionContainerMappingsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationProtectionContainerMappings to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationProtectionContainerMappingsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings listByReplicationProtectionContainers" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings") + Observable> listByReplicationProtectionContainers(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateProtectionContainerMappingInput creationInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateProtectionContainerMappingInput creationInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings purge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}", method = "DELETE", hasBody = true) + Observable> purge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings beginPurge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}", method = "DELETE", hasBody = true) + Observable> beginPurge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateProtectionContainerMappingInput updateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateProtectionContainerMappingInput updateInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings delete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}/remove") + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RemoveProtectionContainerMappingInput removalInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings beginDelete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectionContainerMappings/{mappingName}/remove") + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("mappingName") String mappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RemoveProtectionContainerMappingInput removalInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationProtectionContainerMappings") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings listByReplicationProtectionContainersNext" }) + @GET + Observable> listByReplicationProtectionContainersNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainerMappings listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerMappingInner> object if successful. + */ + public PagedList listByReplicationProtectionContainers(final String fabricName, final String protectionContainerName) { + ServiceResponse> response = listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable> listByReplicationProtectionContainersAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersWithServiceResponseAsync(fabricName, protectionContainerName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable>> listByReplicationProtectionContainersWithServiceResponseAsync(final String fabricName, final String protectionContainerName) { + return listByReplicationProtectionContainersSinglePageAsync(fabricName, protectionContainerName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersSinglePageAsync(final String fabricName, final String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectionContainers(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets a protection container mapping/. + * Gets the details of a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection Container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner get(String fabricName, String protectionContainerName, String mappingName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().single().body(); + } + + /** + * Gets a protection container mapping/. + * Gets the details of a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection Container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Gets a protection container mapping/. + * Gets the details of a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection Container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName, String mappingName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a protection container mapping/. + * Gets the details of a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection Container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner create(String fabricName, String protectionContainerName, String mappingName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().last().body(); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, String mappingName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateProtectionContainerMappingInputProperties properties = null; + CreateProtectionContainerMappingInput creationInput = new CreateProtectionContainerMappingInput(); + creationInput.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner create(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().last().body(); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateProtectionContainerMappingInput creationInput = new CreateProtectionContainerMappingInput(); + creationInput.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner beginCreate(String fabricName, String protectionContainerName, String mappingName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().single().body(); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, String mappingName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateProtectionContainerMappingInputProperties properties = null; + CreateProtectionContainerMappingInput creationInput = new CreateProtectionContainerMappingInput(); + creationInput.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner beginCreate(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().single().body(); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create protection container mapping. + * The operation to create a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, CreateProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateProtectionContainerMappingInput creationInput = new CreateProtectionContainerMappingInput(); + creationInput.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void purge(String fabricName, String protectionContainerName, String mappingName) { + purgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().last().body(); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture purgeAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(purgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable purgeAsync(String fabricName, String protectionContainerName, String mappingName) { + return purgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> purgeWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.purge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginPurge(String fabricName, String protectionContainerName, String mappingName) { + beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().single().body(); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPurgeAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginPurgeAsync(String fabricName, String protectionContainerName, String mappingName) { + return beginPurgeWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purge protection container mapping. + * The operation to purge(force delete) a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginPurgeWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginPurge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPurgeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPurgeDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner update(String fabricName, String protectionContainerName, String mappingName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().last().body(); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String mappingName) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateProtectionContainerMappingInputProperties properties = null; + UpdateProtectionContainerMappingInput updateInput = new UpdateProtectionContainerMappingInput(); + updateInput.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), updateInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner update(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().last().body(); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + return updateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateProtectionContainerMappingInput updateInput = new UpdateProtectionContainerMappingInput(); + updateInput.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), updateInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner beginUpdate(String fabricName, String protectionContainerName, String mappingName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().single().body(); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String mappingName) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateProtectionContainerMappingInputProperties properties = null; + UpdateProtectionContainerMappingInput updateInput = new UpdateProtectionContainerMappingInput(); + updateInput.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), updateInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerMappingInner object if successful. + */ + public ProtectionContainerMappingInner beginUpdate(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().single().body(); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable beginUpdateAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, ProtectionContainerMappingInner>() { + @Override + public ProtectionContainerMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update protection container mapping. + * The operation to update protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Update protection container mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerMappingInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, UpdateProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateProtectionContainerMappingInput updateInput = new UpdateProtectionContainerMappingInput(); + updateInput.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), updateInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String mappingName) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().last().body(); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String mappingName) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final RemoveProtectionContainerMappingInputProperties properties = null; + RemoveProtectionContainerMappingInput removalInput = new RemoveProtectionContainerMappingInput(); + removalInput.withProperties(null); + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), removalInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().last().body(); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + RemoveProtectionContainerMappingInput removalInput = new RemoveProtectionContainerMappingInput(); + removalInput.withProperties(properties); + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), removalInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String mappingName) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).toBlocking().single().body(); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String mappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName), serviceCallback); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String mappingName) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final RemoveProtectionContainerMappingInputProperties properties = null; + RemoveProtectionContainerMappingInput removalInput = new RemoveProtectionContainerMappingInput(); + removalInput.withProperties(null); + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), removalInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).toBlocking().single().body(); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties), serviceCallback); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName, mappingName, properties).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove protection container mapping. + * The operation to delete or remove a protection container mapping. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param mappingName Protection container mapping name. + * @param properties Configure protection input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName, String mappingName, RemoveProtectionContainerMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (mappingName == null) { + throw new IllegalArgumentException("Parameter mappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + RemoveProtectionContainerMappingInput removalInput = new RemoveProtectionContainerMappingInput(); + removalInput.withProperties(properties); + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, mappingName, this.client.apiVersion(), this.client.acceptLanguage(), removalInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerMappingInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerMappingInner> object if successful. + */ + public PagedList listByReplicationProtectionContainersNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectionContainersNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable> listByReplicationProtectionContainersNextAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable>> listByReplicationProtectionContainersNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectionContainersNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectionContainersNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protection container mappings for a protection container. + * Lists the protection container mappings for a protection container. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectionContainersNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectionContainersNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectionContainersNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectionContainersNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerMappingInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerMappingInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of all protection container mappings in a vault. + * Lists the protection container mappings in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersImpl.java new file mode 100644 index 0000000000000..93fca6e6d22e1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersImpl.java @@ -0,0 +1,123 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import rx.Completable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ProtectionContainer; + +class ReplicationProtectionContainersImpl extends WrapperImpl implements ReplicationProtectionContainers { + private final RecoveryServicesManager manager; + + ReplicationProtectionContainersImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationProtectionContainers()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public ProtectionContainerImpl define(String name) { + return wrapModel(name); + } + + private ProtectionContainerImpl wrapModel(ProtectionContainerInner inner) { + return new ProtectionContainerImpl(inner, manager()); + } + + private ProtectionContainerImpl wrapModel(String name) { + return new ProtectionContainerImpl(name, this.manager()); + } + + @Override + public Observable discoverProtectableItemAsync(String fabricName, String protectionContainerName) { + ReplicationProtectionContainersInner client = this.inner(); + return client.discoverProtectableItemAsync(fabricName, protectionContainerName) + .map(new Func1() { + @Override + public ProtectionContainer call(ProtectionContainerInner inner) { + return new ProtectionContainerImpl(inner, manager()); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String protectionContainerName) { + ReplicationProtectionContainersInner client = this.inner(); + return client.deleteAsync(fabricName, protectionContainerName).toCompletable(); + } + + @Override + public Observable switchProtectionAsync(String fabricName, String protectionContainerName) { + ReplicationProtectionContainersInner client = this.inner(); + return client.switchProtectionAsync(fabricName, protectionContainerName) + .map(new Func1() { + @Override + public ProtectionContainer call(ProtectionContainerInner inner) { + return new ProtectionContainerImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationProtectionContainersInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ProtectionContainer call(ProtectionContainerInner inner) { + return new ProtectionContainerImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationProtectionContainersInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public ProtectionContainer call(ProtectionContainerInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String protectionContainerName) { + ReplicationProtectionContainersInner client = this.inner(); + return client.getAsync(fabricName, protectionContainerName) + .map(new Func1() { + @Override + public ProtectionContainer call(ProtectionContainerInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersInner.java new file mode 100644 index 0000000000000..366b926ee6507 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationProtectionContainersInner.java @@ -0,0 +1,1960 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateProtectionContainerInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.DiscoverProtectableItemRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.DiscoverProtectableItemRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.SwitchProtectionInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.SwitchProtectionInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationProtectionContainers. + */ +public class ReplicationProtectionContainersInner implements InnerSupportsDelete { + /** The Retrofit service to perform REST calls. */ + private ReplicationProtectionContainersService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationProtectionContainersInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationProtectionContainersInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationProtectionContainersService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationProtectionContainers to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationProtectionContainersService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateProtectionContainerInput creationInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateProtectionContainerInput creationInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers discoverProtectableItem" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/discoverProtectableItem") + Observable> discoverProtectableItem(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body DiscoverProtectableItemRequest discoverProtectableItemRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers beginDiscoverProtectableItem" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/discoverProtectableItem") + Observable> beginDiscoverProtectableItem(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body DiscoverProtectableItemRequest discoverProtectableItemRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers delete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/remove") + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers beginDelete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/remove") + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers switchProtection" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/switchprotection") + Observable> switchProtection(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SwitchProtectionInput switchInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers beginSwitchProtection" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/switchprotection") + Observable> beginSwitchProtection(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SwitchProtectionInput switchInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationProtectionContainers") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationProtectionContainers listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param fabricName Fabric name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + ServiceResponse> * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the protection container details. + * Gets the details of a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner get(String fabricName, String protectionContainerName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().single().body(); + } + + /** + * Gets the protection container details. + * Gets the details of a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Gets the protection container details. + * Gets the details of a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable getAsync(String fabricName, String protectionContainerName) { + return getWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the protection container details. + * Gets the details of a protection container. + * + * @param fabricName Fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner create(String fabricName, String protectionContainerName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().last().body(); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName) { + return createWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateProtectionContainerInputProperties properties = null; + CreateProtectionContainerInput creationInput = new CreateProtectionContainerInput(); + creationInput.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner create(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().last().body(); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + return createWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateProtectionContainerInput creationInput = new CreateProtectionContainerInput(); + creationInput.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginCreate(String fabricName, String protectionContainerName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().single().body(); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final CreateProtectionContainerInputProperties properties = null; + CreateProtectionContainerInput creationInput = new CreateProtectionContainerInput(); + creationInput.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginCreate(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().single().body(); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginCreateAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create a protection container. + * Operation to create a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param properties Create protection container input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String protectionContainerName, CreateProtectionContainerInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + CreateProtectionContainerInput creationInput = new CreateProtectionContainerInput(); + creationInput.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), creationInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner discoverProtectableItem(String fabricName, String protectionContainerName) { + return discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().last().body(); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture discoverProtectableItemAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable discoverProtectableItemAsync(String fabricName, String protectionContainerName) { + return discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> discoverProtectableItemWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final DiscoverProtectableItemRequestProperties properties = null; + DiscoverProtectableItemRequest discoverProtectableItemRequest = new DiscoverProtectableItemRequest(); + discoverProtectableItemRequest.withProperties(null); + Observable> observable = service.discoverProtectableItem(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), discoverProtectableItemRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner discoverProtectableItem(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + return discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().last().body(); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture discoverProtectableItemAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable discoverProtectableItemAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + return discoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> discoverProtectableItemWithServiceResponseAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + DiscoverProtectableItemRequest discoverProtectableItemRequest = new DiscoverProtectableItemRequest(); + discoverProtectableItemRequest.withProperties(properties); + Observable> observable = service.discoverProtectableItem(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), discoverProtectableItemRequest, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginDiscoverProtectableItem(String fabricName, String protectionContainerName) { + return beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().single().body(); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDiscoverProtectableItemAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginDiscoverProtectableItemAsync(String fabricName, String protectionContainerName) { + return beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginDiscoverProtectableItemWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final DiscoverProtectableItemRequestProperties properties = null; + DiscoverProtectableItemRequest discoverProtectableItemRequest = new DiscoverProtectableItemRequest(); + discoverProtectableItemRequest.withProperties(null); + return service.beginDiscoverProtectableItem(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), discoverProtectableItemRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDiscoverProtectableItemDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginDiscoverProtectableItem(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + return beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().single().body(); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDiscoverProtectableItemAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginDiscoverProtectableItemAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + return beginDiscoverProtectableItemWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a protectable item to the replication protection container. + * The operation to a add a protectable item to a protection container(Add physical server.). + * + * @param fabricName The name of the fabric. + * @param protectionContainerName The name of the protection container. + * @param properties The properties of a discover protectable item request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginDiscoverProtectableItemWithServiceResponseAsync(String fabricName, String protectionContainerName, DiscoverProtectableItemRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + DiscoverProtectableItemRequest discoverProtectableItemRequest = new DiscoverProtectableItemRequest(); + discoverProtectableItemRequest.withProperties(properties); + return service.beginDiscoverProtectableItem(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), discoverProtectableItemRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDiscoverProtectableItemDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDiscoverProtectableItemDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String protectionContainerName) { + deleteWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().last().body(); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String protectionContainerName) { + return deleteWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String protectionContainerName) { + beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().single().body(); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String protectionContainerName) { + return beginDeleteWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Removes a protection container. + * Operation to remove a protection container. + * + * @param fabricName Unique fabric ARM name. + * @param protectionContainerName Unique protection container ARM name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner switchProtection(String fabricName, String protectionContainerName) { + return switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().last().body(); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture switchProtectionAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable switchProtectionAsync(String fabricName, String protectionContainerName) { + return switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> switchProtectionWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final SwitchProtectionInputProperties properties = null; + SwitchProtectionInput switchInput = new SwitchProtectionInput(); + switchInput.withProperties(null); + Observable> observable = service.switchProtection(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), switchInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner switchProtection(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + return switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().last().body(); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture switchProtectionAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable switchProtectionAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + return switchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> switchProtectionWithServiceResponseAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + SwitchProtectionInput switchInput = new SwitchProtectionInput(); + switchInput.withProperties(properties); + Observable> observable = service.switchProtection(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), switchInput, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginSwitchProtection(String fabricName, String protectionContainerName) { + return beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName).toBlocking().single().body(); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginSwitchProtectionAsync(String fabricName, String protectionContainerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName), serviceCallback); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginSwitchProtectionAsync(String fabricName, String protectionContainerName) { + return beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginSwitchProtectionWithServiceResponseAsync(String fabricName, String protectionContainerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final SwitchProtectionInputProperties properties = null; + SwitchProtectionInput switchInput = new SwitchProtectionInput(); + switchInput.withProperties(null); + return service.beginSwitchProtection(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), switchInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginSwitchProtectionDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the ProtectionContainerInner object if successful. + */ + public ProtectionContainerInner beginSwitchProtection(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + return beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties).toBlocking().single().body(); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginSwitchProtectionAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties), serviceCallback); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable beginSwitchProtectionAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + return beginSwitchProtectionWithServiceResponseAsync(fabricName, protectionContainerName, properties).map(new Func1, ProtectionContainerInner>() { + @Override + public ProtectionContainerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Switches protection from one container to another or one replication provider to another. + * Operation to switch protection from one container to another or one replication provider to another. + * + * @param fabricName Unique fabric name. + * @param protectionContainerName Protection container name. + * @param properties Switch protection properties + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the ProtectionContainerInner object + */ + public Observable> beginSwitchProtectionWithServiceResponseAsync(String fabricName, String protectionContainerName, SwitchProtectionInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + SwitchProtectionInput switchInput = new SwitchProtectionInput(); + switchInput.withProperties(properties); + return service.beginSwitchProtection(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, this.client.apiVersion(), this.client.acceptLanguage(), switchInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginSwitchProtectionDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginSwitchProtectionDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of protection container for a fabric. + * Lists the protection containers in the specified fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<ProtectionContainerInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<ProtectionContainerInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of all protection containers in a vault. + * Lists the protection containers in a vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<ProtectionContainerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansImpl.java new file mode 100644 index 0000000000000..44ee8d8e6c6c6 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansImpl.java @@ -0,0 +1,157 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlan; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanPlannedFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverCleanupInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanUnplannedFailoverInputProperties; + +class ReplicationRecoveryPlansImpl extends WrapperImpl implements ReplicationRecoveryPlans { + private final RecoveryServicesManager manager; + + ReplicationRecoveryPlansImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationRecoveryPlans()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public RecoveryPlanImpl define(String name) { + return wrapModel(name); + } + + private RecoveryPlanImpl wrapModel(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + + private RecoveryPlanImpl wrapModel(String name) { + return new RecoveryPlanImpl(name, this.manager()); + } + + @Override + public Observable failoverCommitAsync(String recoveryPlanName) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.failoverCommitAsync(recoveryPlanName) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable plannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.plannedFailoverAsync(recoveryPlanName, properties) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable reprotectAsync(String recoveryPlanName) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.reprotectAsync(recoveryPlanName) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable testFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.testFailoverAsync(recoveryPlanName, properties) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable testFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.testFailoverCleanupAsync(recoveryPlanName, properties) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable unplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.unplannedFailoverAsync(recoveryPlanName, properties) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return new RecoveryPlanImpl(inner, manager()); + } + }); + } + + @Override + public Observable listAsync() { + ReplicationRecoveryPlansInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String recoveryPlanName) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.getAsync(recoveryPlanName) + .map(new Func1() { + @Override + public RecoveryPlan call(RecoveryPlanInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String recoveryPlanName) { + ReplicationRecoveryPlansInner client = this.inner(); + return client.deleteAsync(recoveryPlanName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansInner.java new file mode 100644 index 0000000000000..72515aa4b7f0c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryPlansInner.java @@ -0,0 +1,2216 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateRecoveryPlanInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.CreateRecoveryPlanInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanPlannedFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanPlannedFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverCleanupInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverCleanupInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanTestFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanUnplannedFailoverInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryPlanUnplannedFailoverInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateRecoveryPlanInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateRecoveryPlanInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationRecoveryPlans. + */ +public class ReplicationRecoveryPlansInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationRecoveryPlansService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationRecoveryPlansInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationRecoveryPlansInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationRecoveryPlansService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationRecoveryPlans to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationRecoveryPlansService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateRecoveryPlanInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body CreateRecoveryPlanInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateRecoveryPlanInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateRecoveryPlanInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans failoverCommit" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/failoverCommit") + Observable> failoverCommit(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginFailoverCommit" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/failoverCommit") + Observable> beginFailoverCommit(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans plannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/plannedFailover") + Observable> plannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanPlannedFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginPlannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/plannedFailover") + Observable> beginPlannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanPlannedFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans reprotect" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/reProtect") + Observable> reprotect(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginReprotect" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/reProtect") + Observable> beginReprotect(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans testFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/testFailover") + Observable> testFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanTestFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginTestFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/testFailover") + Observable> beginTestFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanTestFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans testFailoverCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/testFailoverCleanup") + Observable> testFailoverCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanTestFailoverCleanupInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginTestFailoverCleanup" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/testFailoverCleanup") + Observable> beginTestFailoverCleanup(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanTestFailoverCleanupInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans unplannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/unplannedFailover") + Observable> unplannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanUnplannedFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans beginUnplannedFailover" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryPlans/{recoveryPlanName}/unplannedFailover") + Observable> beginUnplannedFailover(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("recoveryPlanName") String recoveryPlanName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body RecoveryPlanUnplannedFailoverInput input, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryPlans listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryPlanInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPlanInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPlanInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryPlanInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the requested recovery plan. + * Gets the details of the recovery plan. + * + * @param recoveryPlanName Name of the recovery plan. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner get(String recoveryPlanName) { + return getWithServiceResponseAsync(recoveryPlanName).toBlocking().single().body(); + } + + /** + * Gets the requested recovery plan. + * Gets the details of the recovery plan. + * + * @param recoveryPlanName Name of the recovery plan. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Gets the requested recovery plan. + * Gets the details of the recovery plan. + * + * @param recoveryPlanName Name of the recovery plan. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable getAsync(String recoveryPlanName) { + return getWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the requested recovery plan. + * Gets the details of the recovery plan. + * + * @param recoveryPlanName Name of the recovery plan. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> getWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner create(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + return createWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + return createWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + CreateRecoveryPlanInput input = new CreateRecoveryPlanInput(); + input.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginCreate(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + return beginCreateWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginCreateAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + return beginCreateWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates a recovery plan with the given details. + * The operation to create a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan creation properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String recoveryPlanName, CreateRecoveryPlanInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + CreateRecoveryPlanInput input = new CreateRecoveryPlanInput(); + input.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String recoveryPlanName) { + deleteWithServiceResponseAsync(recoveryPlanName).toBlocking().last().body(); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String recoveryPlanName) { + return deleteWithServiceResponseAsync(recoveryPlanName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String recoveryPlanName) { + beginDeleteWithServiceResponseAsync(recoveryPlanName).toBlocking().single().body(); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String recoveryPlanName) { + return beginDeleteWithServiceResponseAsync(recoveryPlanName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes the specified recovery plan. + * Delete a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner update(String recoveryPlanName) { + return updateWithServiceResponseAsync(recoveryPlanName).toBlocking().last().body(); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String recoveryPlanName) { + return updateWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateRecoveryPlanInputProperties properties = null; + UpdateRecoveryPlanInput input = new UpdateRecoveryPlanInput(); + input.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner update(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + return updateWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + return updateWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateRecoveryPlanInput input = new UpdateRecoveryPlanInput(); + input.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginUpdate(String recoveryPlanName) { + return beginUpdateWithServiceResponseAsync(recoveryPlanName).toBlocking().single().body(); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginUpdateAsync(String recoveryPlanName) { + return beginUpdateWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateRecoveryPlanInputProperties properties = null; + UpdateRecoveryPlanInput input = new UpdateRecoveryPlanInput(); + input.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginUpdate(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + return beginUpdateWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginUpdateAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + return beginUpdateWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates the given recovery plan. + * The operation to update a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties Recovery plan update properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String recoveryPlanName, UpdateRecoveryPlanInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateRecoveryPlanInput input = new UpdateRecoveryPlanInput(); + input.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner failoverCommit(String recoveryPlanName) { + return failoverCommitWithServiceResponseAsync(recoveryPlanName).toBlocking().last().body(); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture failoverCommitAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(failoverCommitWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable failoverCommitAsync(String recoveryPlanName) { + return failoverCommitWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> failoverCommitWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.failoverCommit(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginFailoverCommit(String recoveryPlanName) { + return beginFailoverCommitWithServiceResponseAsync(recoveryPlanName).toBlocking().single().body(); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginFailoverCommitAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginFailoverCommitWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginFailoverCommitAsync(String recoveryPlanName) { + return beginFailoverCommitWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute commit failover of the recovery plan. + * The operation to commit the fail over of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginFailoverCommitWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginFailoverCommit(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginFailoverCommitDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginFailoverCommitDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner plannedFailover(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + return plannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture plannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(plannedFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable plannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + return plannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> plannedFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanPlannedFailoverInput input = new RecoveryPlanPlannedFailoverInput(); + input.withProperties(properties); + Observable> observable = service.plannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginPlannedFailover(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + return beginPlannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPlannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPlannedFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginPlannedFailoverAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + return beginPlannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute planned failover of the recovery plan. + * The operation to start the planned failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan planned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginPlannedFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanPlannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanPlannedFailoverInput input = new RecoveryPlanPlannedFailoverInput(); + input.withProperties(properties); + return service.beginPlannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPlannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPlannedFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner reprotect(String recoveryPlanName) { + return reprotectWithServiceResponseAsync(recoveryPlanName).toBlocking().last().body(); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture reprotectAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(reprotectWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable reprotectAsync(String recoveryPlanName) { + return reprotectWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> reprotectWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.reprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginReprotect(String recoveryPlanName) { + return beginReprotectWithServiceResponseAsync(recoveryPlanName).toBlocking().single().body(); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginReprotectAsync(String recoveryPlanName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginReprotectWithServiceResponseAsync(recoveryPlanName), serviceCallback); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginReprotectAsync(String recoveryPlanName) { + return beginReprotectWithServiceResponseAsync(recoveryPlanName).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute reprotect of the recovery plan. + * The operation to reprotect(reverse replicate) a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginReprotectWithServiceResponseAsync(String recoveryPlanName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginReprotect(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginReprotectDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginReprotectDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner testFailover(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + return testFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + return testFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanTestFailoverInput input = new RecoveryPlanTestFailoverInput(); + input.withProperties(properties); + Observable> observable = service.testFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginTestFailover(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + return beginTestFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginTestFailoverAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + return beginTestFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover of the recovery plan. + * The operation to start the test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginTestFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanTestFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanTestFailoverInput input = new RecoveryPlanTestFailoverInput(); + input.withProperties(properties); + return service.beginTestFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner testFailoverCleanup(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + return testFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture testFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(testFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable testFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + return testFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> testFailoverCleanupWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanTestFailoverCleanupInput input = new RecoveryPlanTestFailoverCleanupInput(); + input.withProperties(properties); + Observable> observable = service.testFailoverCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginTestFailoverCleanup(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + return beginTestFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginTestFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginTestFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginTestFailoverCleanupAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + return beginTestFailoverCleanupWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute test failover cleanup of the recovery plan. + * The operation to cleanup test failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan test failover cleanup input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginTestFailoverCleanupWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanTestFailoverCleanupInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanTestFailoverCleanupInput input = new RecoveryPlanTestFailoverCleanupInput(); + input.withProperties(properties); + return service.beginTestFailoverCleanup(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginTestFailoverCleanupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginTestFailoverCleanupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner unplannedFailover(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + return unplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().last().body(); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture unplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(unplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable unplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + return unplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> unplannedFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanUnplannedFailoverInput input = new RecoveryPlanUnplannedFailoverInput(); + input.withProperties(properties); + Observable> observable = service.unplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryPlanInner object if successful. + */ + public RecoveryPlanInner beginUnplannedFailover(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + return beginUnplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).toBlocking().single().body(); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUnplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUnplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties), serviceCallback); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable beginUnplannedFailoverAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + return beginUnplannedFailoverWithServiceResponseAsync(recoveryPlanName, properties).map(new Func1, RecoveryPlanInner>() { + @Override + public RecoveryPlanInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Execute unplanned failover of the recovery plan. + * The operation to start the failover of a recovery plan. + * + * @param recoveryPlanName Recovery plan name. + * @param properties The recovery plan unplanned failover input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryPlanInner object + */ + public Observable> beginUnplannedFailoverWithServiceResponseAsync(String recoveryPlanName, RecoveryPlanUnplannedFailoverInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (recoveryPlanName == null) { + throw new IllegalArgumentException("Parameter recoveryPlanName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + RecoveryPlanUnplannedFailoverInput input = new RecoveryPlanUnplannedFailoverInput(); + input.withProperties(properties); + return service.beginUnplannedFailover(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), recoveryPlanName, this.client.apiVersion(), this.client.acceptLanguage(), input, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUnplannedFailoverDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUnplannedFailoverDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryPlanInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPlanInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryPlanInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of recovery plans. + * Lists the recovery plans in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryPlanInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersImpl.java new file mode 100644 index 0000000000000..46908098e7735 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersImpl.java @@ -0,0 +1,117 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.RecoveryServicesProvider; + +class ReplicationRecoveryServicesProvidersImpl extends WrapperImpl implements ReplicationRecoveryServicesProviders { + private final RecoveryServicesManager manager; + + ReplicationRecoveryServicesProvidersImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationRecoveryServicesProviders()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public RecoveryServicesProviderImpl define(String name) { + return wrapModel(name); + } + + private RecoveryServicesProviderImpl wrapModel(RecoveryServicesProviderInner inner) { + return new RecoveryServicesProviderImpl(inner, manager()); + } + + private RecoveryServicesProviderImpl wrapModel(String name) { + return new RecoveryServicesProviderImpl(name, this.manager()); + } + + @Override + public Observable refreshProviderAsync(String fabricName, String providerName) { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.refreshProviderAsync(fabricName, providerName) + .map(new Func1() { + @Override + public RecoveryServicesProvider call(RecoveryServicesProviderInner inner) { + return new RecoveryServicesProviderImpl(inner, manager()); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String providerName) { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.deleteAsync(fabricName, providerName).toCompletable(); + } + + @Override + public Observable listAsync() { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public RecoveryServicesProvider call(RecoveryServicesProviderInner inner) { + return new RecoveryServicesProviderImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public RecoveryServicesProvider call(RecoveryServicesProviderInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String providerName) { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.getAsync(fabricName, providerName) + .map(new Func1() { + @Override + public RecoveryServicesProvider call(RecoveryServicesProviderInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable purgeAsync(String fabricName, String providerName) { + ReplicationRecoveryServicesProvidersInner client = this.inner(); + return client.purgeAsync(fabricName, providerName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersInner.java new file mode 100644 index 0000000000000..027229eaeff12 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationRecoveryServicesProvidersInner.java @@ -0,0 +1,1414 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddRecoveryServicesProviderInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddRecoveryServicesProviderInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationRecoveryServicesProviders. + */ +public class ReplicationRecoveryServicesProvidersInner implements InnerSupportsDelete { + /** The Retrofit service to perform REST calls. */ + private ReplicationRecoveryServicesProvidersService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationRecoveryServicesProvidersInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationRecoveryServicesProvidersInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationRecoveryServicesProvidersService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationRecoveryServicesProviders to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationRecoveryServicesProvidersService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body AddRecoveryServicesProviderInput addProviderInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body AddRecoveryServicesProviderInput addProviderInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders purge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}", method = "DELETE", hasBody = true) + Observable> purge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders beginPurge" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}", method = "DELETE", hasBody = true) + Observable> beginPurge(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders refreshProvider" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}/refreshProvider") + Observable> refreshProvider(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders beginRefreshProvider" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}/refreshProvider") + Observable> beginRefreshProvider(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders delete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}/remove") + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders beginDelete" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationRecoveryServicesProviders/{providerName}/remove") + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("providerName") String providerName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationRecoveryServicesProviders") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationRecoveryServicesProviders listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryServicesProviderInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param fabricName Fabric name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + ServiceResponse> * @param fabricName Fabric name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryServicesProviderInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a recovery services provider. + * Gets the details of registered recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryServicesProviderInner object if successful. + */ + public RecoveryServicesProviderInner get(String fabricName, String providerName) { + return getWithServiceResponseAsync(fabricName, providerName).toBlocking().single().body(); + } + + /** + * Gets the details of a recovery services provider. + * Gets the details of registered recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Gets the details of a recovery services provider. + * Gets the details of registered recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable getAsync(String fabricName, String providerName) { + return getWithServiceResponseAsync(fabricName, providerName).map(new Func1, RecoveryServicesProviderInner>() { + @Override + public RecoveryServicesProviderInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a recovery services provider. + * Gets the details of registered recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryServicesProviderInner object if successful. + */ + public RecoveryServicesProviderInner create(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + return createWithServiceResponseAsync(fabricName, providerName, properties).toBlocking().last().body(); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, providerName, properties), serviceCallback); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + return createWithServiceResponseAsync(fabricName, providerName, properties).map(new Func1, RecoveryServicesProviderInner>() { + @Override + public RecoveryServicesProviderInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + AddRecoveryServicesProviderInput addProviderInput = new AddRecoveryServicesProviderInput(); + addProviderInput.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), addProviderInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryServicesProviderInner object if successful. + */ + public RecoveryServicesProviderInner beginCreate(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, providerName, properties).toBlocking().single().body(); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, providerName, properties), serviceCallback); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable beginCreateAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, providerName, properties).map(new Func1, RecoveryServicesProviderInner>() { + @Override + public RecoveryServicesProviderInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Adds a recovery services provider. + * The operation to add a recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param properties The properties of an add provider request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String providerName, AddRecoveryServicesProviderInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + if (properties == null) { + throw new IllegalArgumentException("Parameter properties is required and cannot be null."); + } + Validator.validate(properties); + AddRecoveryServicesProviderInput addProviderInput = new AddRecoveryServicesProviderInput(); + addProviderInput.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), addProviderInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void purge(String fabricName, String providerName) { + purgeWithServiceResponseAsync(fabricName, providerName).toBlocking().last().body(); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture purgeAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(purgeWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable purgeAsync(String fabricName, String providerName) { + return purgeWithServiceResponseAsync(fabricName, providerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> purgeWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.purge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginPurge(String fabricName, String providerName) { + beginPurgeWithServiceResponseAsync(fabricName, providerName).toBlocking().single().body(); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginPurgeAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginPurgeWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginPurgeAsync(String fabricName, String providerName) { + return beginPurgeWithServiceResponseAsync(fabricName, providerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Purges recovery service provider from fabric. + * The operation to purge(force delete) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginPurgeWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginPurge(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginPurgeDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginPurgeDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryServicesProviderInner object if successful. + */ + public RecoveryServicesProviderInner refreshProvider(String fabricName, String providerName) { + return refreshProviderWithServiceResponseAsync(fabricName, providerName).toBlocking().last().body(); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture refreshProviderAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(refreshProviderWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable refreshProviderAsync(String fabricName, String providerName) { + return refreshProviderWithServiceResponseAsync(fabricName, providerName).map(new Func1, RecoveryServicesProviderInner>() { + @Override + public RecoveryServicesProviderInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> refreshProviderWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.refreshProvider(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the RecoveryServicesProviderInner object if successful. + */ + public RecoveryServicesProviderInner beginRefreshProvider(String fabricName, String providerName) { + return beginRefreshProviderWithServiceResponseAsync(fabricName, providerName).toBlocking().single().body(); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRefreshProviderAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRefreshProviderWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable beginRefreshProviderAsync(String fabricName, String providerName) { + return beginRefreshProviderWithServiceResponseAsync(fabricName, providerName).map(new Func1, RecoveryServicesProviderInner>() { + @Override + public RecoveryServicesProviderInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Refresh details from the recovery services provider. + * The operation to refresh the information from the recovery services provider. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the RecoveryServicesProviderInner object + */ + public Observable> beginRefreshProviderWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginRefreshProvider(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRefreshProviderDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginRefreshProviderDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String providerName) { + deleteWithServiceResponseAsync(fabricName, providerName).toBlocking().last().body(); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String providerName) { + return deleteWithServiceResponseAsync(fabricName, providerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String providerName) { + beginDeleteWithServiceResponseAsync(fabricName, providerName).toBlocking().single().body(); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String providerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, providerName), serviceCallback); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String providerName) { + return beginDeleteWithServiceResponseAsync(fabricName, providerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes provider from fabric. Note: Deleting provider for any fabric other than SingleHost is unsupported. To maintain backward compatibility for released clients the object "deleteRspInput" is used (if the object is empty we assume that it is old client and continue the old behavior). + * The operation to removes/delete(unregister) a recovery services provider from the vault. + * + * @param fabricName Fabric name. + * @param providerName Recovery services provider name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String providerName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (providerName == null) { + throw new IllegalArgumentException("Parameter providerName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, providerName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryServicesProviderInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryServicesProviderInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryServicesProviderInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of registered recovery services providers for the fabric. + * Lists the registered recovery services providers for the specified fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryServicesProviderInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<RecoveryServicesProviderInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<RecoveryServicesProviderInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of registered recovery services providers in the vault. This is a view only api. + * Lists the registered recovery services providers in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<RecoveryServicesProviderInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsImpl.java new file mode 100644 index 0000000000000..d3e10330aaa44 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsImpl.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationMapping; + +class ReplicationStorageClassificationMappingsImpl extends WrapperImpl implements ReplicationStorageClassificationMappings { + private final RecoveryServicesManager manager; + + ReplicationStorageClassificationMappingsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationStorageClassificationMappings()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public StorageClassificationMappingImpl define(String name) { + return wrapModel(name); + } + + private StorageClassificationMappingImpl wrapModel(StorageClassificationMappingInner inner) { + return new StorageClassificationMappingImpl(inner, manager()); + } + + private StorageClassificationMappingImpl wrapModel(String name) { + return new StorageClassificationMappingImpl(name, this.manager()); + } + + @Override + public Observable listAsync() { + ReplicationStorageClassificationMappingsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public StorageClassificationMapping call(StorageClassificationMappingInner inner) { + return new StorageClassificationMappingImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationStorageClassificationsAsync(final String fabricName, final String storageClassificationName) { + ReplicationStorageClassificationMappingsInner client = this.inner(); + return client.listByReplicationStorageClassificationsAsync(fabricName, storageClassificationName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public StorageClassificationMapping call(StorageClassificationMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + ReplicationStorageClassificationMappingsInner client = this.inner(); + return client.getAsync(fabricName, storageClassificationName, storageClassificationMappingName) + .map(new Func1() { + @Override + public StorageClassificationMapping call(StorageClassificationMappingInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + ReplicationStorageClassificationMappingsInner client = this.inner(); + return client.deleteAsync(fabricName, storageClassificationName, storageClassificationMappingName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsInner.java new file mode 100644 index 0000000000000..1a383fe5386b5 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationMappingsInner.java @@ -0,0 +1,1270 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationMappingInput; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageMappingInputProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationStorageClassificationMappings. + */ +public class ReplicationStorageClassificationMappingsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationStorageClassificationMappingsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationStorageClassificationMappingsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationStorageClassificationMappingsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationStorageClassificationMappingsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationStorageClassificationMappings to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationStorageClassificationMappingsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings listByReplicationStorageClassifications" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings") + Observable> listByReplicationStorageClassifications(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings/{storageClassificationMappingName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Path("storageClassificationMappingName") String storageClassificationMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings/{storageClassificationMappingName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Path("storageClassificationMappingName") String storageClassificationMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body StorageClassificationMappingInput pairingInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings/{storageClassificationMappingName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Path("storageClassificationMappingName") String storageClassificationMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body StorageClassificationMappingInput pairingInput, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings/{storageClassificationMappingName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Path("storageClassificationMappingName") String storageClassificationMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}/replicationStorageClassificationMappings/{storageClassificationMappingName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Path("storageClassificationMappingName") String storageClassificationMappingName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationStorageClassificationMappings") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings listByReplicationStorageClassificationsNext" }) + @GET + Observable> listByReplicationStorageClassificationsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassificationMappings listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationMappingInner> object if successful. + */ + public PagedList listByReplicationStorageClassifications(final String fabricName, final String storageClassificationName) { + ServiceResponse> response = listByReplicationStorageClassificationsSinglePageAsync(fabricName, storageClassificationName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationStorageClassificationsAsync(final String fabricName, final String storageClassificationName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationStorageClassificationsSinglePageAsync(fabricName, storageClassificationName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable> listByReplicationStorageClassificationsAsync(final String fabricName, final String storageClassificationName) { + return listByReplicationStorageClassificationsWithServiceResponseAsync(fabricName, storageClassificationName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable>> listByReplicationStorageClassificationsWithServiceResponseAsync(final String fabricName, final String storageClassificationName) { + return listByReplicationStorageClassificationsSinglePageAsync(fabricName, storageClassificationName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationStorageClassificationsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationStorageClassificationsSinglePageAsync(final String fabricName, final String storageClassificationName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationStorageClassifications(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationStorageClassificationsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationStorageClassificationsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a storage classification mapping. + * Gets the details of the specified storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationMappingInner object if successful. + */ + public StorageClassificationMappingInner get(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return getWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).toBlocking().single().body(); + } + + /** + * Gets the details of a storage classification mapping. + * Gets the details of the specified storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName), serviceCallback); + } + + /** + * Gets the details of a storage classification mapping. + * Gets the details of the specified storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable getAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return getWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).map(new Func1, StorageClassificationMappingInner>() { + @Override + public StorageClassificationMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a storage classification mapping. + * Gets the details of the specified storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationMappingInner object if successful. + */ + public StorageClassificationMappingInner create(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).toBlocking().last().body(); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName), serviceCallback); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).map(new Func1, StorageClassificationMappingInner>() { + @Override + public StorageClassificationMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final StorageMappingInputProperties properties = null; + StorageClassificationMappingInput pairingInput = new StorageClassificationMappingInput(); + pairingInput.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), pairingInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationMappingInner object if successful. + */ + public StorageClassificationMappingInner create(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties).toBlocking().last().body(); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties), serviceCallback); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + return createWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties).map(new Func1, StorageClassificationMappingInner>() { + @Override + public StorageClassificationMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + StorageClassificationMappingInput pairingInput = new StorageClassificationMappingInput(); + pairingInput.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), pairingInput, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationMappingInner object if successful. + */ + public StorageClassificationMappingInner beginCreate(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).toBlocking().single().body(); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName), serviceCallback); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).map(new Func1, StorageClassificationMappingInner>() { + @Override + public StorageClassificationMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final StorageMappingInputProperties properties = null; + StorageClassificationMappingInput pairingInput = new StorageClassificationMappingInput(); + pairingInput.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), pairingInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationMappingInner object if successful. + */ + public StorageClassificationMappingInner beginCreate(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties).toBlocking().single().body(); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties), serviceCallback); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable beginCreateAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName, properties).map(new Func1, StorageClassificationMappingInner>() { + @Override + public StorageClassificationMappingInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Create storage classification mapping. + * The operation to create a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param properties Storage mapping input properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationMappingInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, StorageMappingInputProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + StorageClassificationMappingInput pairingInput = new StorageClassificationMappingInput(); + pairingInput.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), pairingInput, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + deleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).toBlocking().last().body(); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName), serviceCallback); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return deleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + beginDeleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).toBlocking().single().body(); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName), serviceCallback); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + return beginDeleteWithServiceResponseAsync(fabricName, storageClassificationName, storageClassificationMappingName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Delete a storage classification mapping. + * The operation to delete a storage classification mapping. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param storageClassificationMappingName Storage classification mapping name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String storageClassificationName, String storageClassificationMappingName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (storageClassificationMappingName == null) { + throw new IllegalArgumentException("Parameter storageClassificationMappingName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, storageClassificationMappingName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationMappingInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationMappingInner> object if successful. + */ + public PagedList listByReplicationStorageClassificationsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationStorageClassificationsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable> listByReplicationStorageClassificationsNextAsync(final String nextPageLink) { + return listByReplicationStorageClassificationsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable>> listByReplicationStorageClassificationsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationStorageClassificationsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationStorageClassificationsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a storage. + * Lists the storage classification mappings for the fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationStorageClassificationsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationStorageClassificationsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationStorageClassificationsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationStorageClassificationsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationMappingInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationMappingInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification mappings objects under a vault. + * Lists the storage classification mappings in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationMappingInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsImpl.java new file mode 100644 index 0000000000000..9e63970faf162 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsImpl.java @@ -0,0 +1,83 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassification; + +class ReplicationStorageClassificationsImpl extends WrapperImpl implements ReplicationStorageClassifications { + private final RecoveryServicesManager manager; + + ReplicationStorageClassificationsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationStorageClassifications()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private StorageClassificationImpl wrapModel(StorageClassificationInner inner) { + return new StorageClassificationImpl(inner, manager()); + } + + @Override + public Observable listAsync() { + ReplicationStorageClassificationsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public StorageClassification call(StorageClassificationInner inner) { + return new StorageClassificationImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationStorageClassificationsInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public StorageClassification call(StorageClassificationInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String storageClassificationName) { + ReplicationStorageClassificationsInner client = this.inner(); + return client.getAsync(fabricName, storageClassificationName) + .map(new Func1() { + @Override + public StorageClassification call(StorageClassificationInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsInner.java new file mode 100644 index 0000000000000..edaf1b79b310b --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationStorageClassificationsInner.java @@ -0,0 +1,654 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationStorageClassifications. + */ +public class ReplicationStorageClassificationsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationStorageClassificationsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationStorageClassificationsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationStorageClassificationsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationStorageClassificationsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationStorageClassifications to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationStorageClassificationsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationStorageClassifications/{storageClassificationName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("storageClassificationName") String storageClassificationName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationStorageClassifications") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationStorageClassifications listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param fabricName Site name of interest. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param fabricName Site name of interest. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param fabricName Site name of interest. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param fabricName Site name of interest. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + ServiceResponse> * @param fabricName Site name of interest. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a storage classification. + * Gets the details of the specified storage classification. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the StorageClassificationInner object if successful. + */ + public StorageClassificationInner get(String fabricName, String storageClassificationName) { + return getWithServiceResponseAsync(fabricName, storageClassificationName).toBlocking().single().body(); + } + + /** + * Gets the details of a storage classification. + * Gets the details of the specified storage classification. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String storageClassificationName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, storageClassificationName), serviceCallback); + } + + /** + * Gets the details of a storage classification. + * Gets the details of the specified storage classification. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationInner object + */ + public Observable getAsync(String fabricName, String storageClassificationName) { + return getWithServiceResponseAsync(fabricName, storageClassificationName).map(new Func1, StorageClassificationInner>() { + @Override + public StorageClassificationInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a storage classification. + * Gets the details of the specified storage classification. + * + * @param fabricName Fabric name. + * @param storageClassificationName Storage classification name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the StorageClassificationInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String storageClassificationName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (storageClassificationName == null) { + throw new IllegalArgumentException("Parameter storageClassificationName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, storageClassificationName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification objects under a fabric. + * Lists the storage classifications available in the specified fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<StorageClassificationInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<StorageClassificationInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of storage classification objects under a vault. + * Lists the storage classifications in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<StorageClassificationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsImpl.java new file mode 100644 index 0000000000000..d456f4462e718 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsImpl.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * abc + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationVaultHealths; +import rx.functions.Func1; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VaultHealthDetails; + +class ReplicationVaultHealthsImpl extends WrapperImpl implements ReplicationVaultHealths { + private final RecoveryServicesManager manager; + + ReplicationVaultHealthsImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationVaultHealths()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable getAsync() { + ReplicationVaultHealthsInner client = this.inner(); + return client.getAsync() + .map(new Func1() { + @Override + public VaultHealthDetails call(VaultHealthDetailsInner inner) { + return new VaultHealthDetailsImpl(inner, manager()); + } + }); + } + + @Override + public Observable refreshAsync() { + ReplicationVaultHealthsInner client = this.inner(); + return client.refreshAsync() + .map(new Func1() { + @Override + public VaultHealthDetails call(VaultHealthDetailsInner inner) { + return new VaultHealthDetailsImpl(inner, manager()); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsInner.java new file mode 100644 index 0000000000000..b35dd0e2b1f8e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationVaultHealthsInner.java @@ -0,0 +1,291 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.CloudException; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.POST; +import retrofit2.http.Query; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationVaultHealths. + */ +public class ReplicationVaultHealthsInner { + /** The Retrofit service to perform REST calls. */ + private ReplicationVaultHealthsService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationVaultHealthsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationVaultHealthsInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationVaultHealthsService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationVaultHealths to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationVaultHealthsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationVaultHealths get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationVaultHealth") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationVaultHealths refresh" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationVaultHealth/default/refresh") + Observable> refresh(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationVaultHealths beginRefresh" }) + @POST("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationVaultHealth/default/refresh") + Observable> beginRefresh(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the health summary for the vault. + * Gets the health details of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VaultHealthDetailsInner object if successful. + */ + public VaultHealthDetailsInner get() { + return getWithServiceResponseAsync().toBlocking().single().body(); + } + + /** + * Gets the health summary for the vault. + * Gets the health details of the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(), serviceCallback); + } + + /** + * Gets the health summary for the vault. + * Gets the health details of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VaultHealthDetailsInner object + */ + public Observable getAsync() { + return getWithServiceResponseAsync().map(new Func1, VaultHealthDetailsInner>() { + @Override + public VaultHealthDetailsInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the health summary for the vault. + * Gets the health details of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VaultHealthDetailsInner object + */ + public Observable> getWithServiceResponseAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VaultHealthDetailsInner object if successful. + */ + public VaultHealthDetailsInner refresh() { + return refreshWithServiceResponseAsync().toBlocking().last().body(); + } + + /** + * Refreshes health summary of the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture refreshAsync(final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(refreshWithServiceResponseAsync(), serviceCallback); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable refreshAsync() { + return refreshWithServiceResponseAsync().map(new Func1, VaultHealthDetailsInner>() { + @Override + public VaultHealthDetailsInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> refreshWithServiceResponseAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.refresh(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VaultHealthDetailsInner object if successful. + */ + public VaultHealthDetailsInner beginRefresh() { + return beginRefreshWithServiceResponseAsync().toBlocking().single().body(); + } + + /** + * Refreshes health summary of the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginRefreshAsync(final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginRefreshWithServiceResponseAsync(), serviceCallback); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VaultHealthDetailsInner object + */ + public Observable beginRefreshAsync() { + return beginRefreshWithServiceResponseAsync().map(new Func1, VaultHealthDetailsInner>() { + @Override + public VaultHealthDetailsInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Refreshes health summary of the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VaultHealthDetailsInner object + */ + public Observable> beginRefreshWithServiceResponseAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginRefresh(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginRefreshDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginRefreshDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersImpl.java new file mode 100644 index 0000000000000..852d2e9b9fee1 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersImpl.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VCenter; + +class ReplicationvCentersImpl extends WrapperImpl implements ReplicationvCenters { + private final RecoveryServicesManager manager; + + ReplicationvCentersImpl(RecoveryServicesManager manager) { + super(manager.inner().replicationvCenters()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public VCenterImpl define(String name) { + return wrapModel(name); + } + + private VCenterImpl wrapModel(VCenterInner inner) { + return new VCenterImpl(inner, manager()); + } + + private VCenterImpl wrapModel(String name) { + return new VCenterImpl(name, this.manager()); + } + + @Override + public Observable listAsync() { + ReplicationvCentersInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public VCenter call(VCenterInner inner) { + return new VCenterImpl(inner, manager()); + } + }); + } + + @Override + public Observable listByReplicationFabricsAsync(final String fabricName) { + ReplicationvCentersInner client = this.inner(); + return client.listByReplicationFabricsAsync(fabricName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public VCenter call(VCenterInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String fabricName, String vCenterName) { + ReplicationvCentersInner client = this.inner(); + return client.getAsync(fabricName, vCenterName) + .map(new Func1() { + @Override + public VCenter call(VCenterInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Completable deleteAsync(String fabricName, String vCenterName) { + ReplicationvCentersInner client = this.inner(); + return client.deleteAsync(fabricName, vCenterName).toCompletable(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersInner.java new file mode 100644 index 0000000000000..3f4d6b12b8413 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/ReplicationvCentersInner.java @@ -0,0 +1,1588 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddVCenterRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddVCenterRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateVCenterRequest; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateVCenterRequestProperties; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in ReplicationvCenters. + */ +public class ReplicationvCentersInner implements InnerSupportsDelete { + /** The Retrofit service to perform REST calls. */ + private ReplicationvCentersService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of ReplicationvCentersInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public ReplicationvCentersInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(ReplicationvCentersService.class); + this.client = client; + } + + /** + * The interface defining all the services for ReplicationvCenters to be + * used by Retrofit to perform actually REST calls. + */ + interface ReplicationvCentersService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters listByReplicationFabrics" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters") + Observable> listByReplicationFabrics(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters get" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}") + Observable> get(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters create" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}") + Observable> create(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body AddVCenterRequest addVCenterRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters beginCreate" }) + @PUT("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}") + Observable> beginCreate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body AddVCenterRequest addVCenterRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters delete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters beginDelete" }) + @HTTP(path = "Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters update" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}") + Observable> update(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateVCenterRequest updateVCenterRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters beginUpdate" }) + @PATCH("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationvCenters/{vCenterName}") + Observable> beginUpdate(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("vCenterName") String vCenterName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body UpdateVCenterRequest updateVCenterRequest, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters list" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationvCenters") + Observable> list(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters listByReplicationFabricsNext" }) + @GET + Observable> listByReplicationFabricsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.ReplicationvCenters listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<VCenterInner> object if successful. + */ + public PagedList listByReplicationFabrics(final String fabricName) { + ServiceResponse> response = listByReplicationFabricsSinglePageAsync(fabricName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param fabricName Fabric name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsAsync(final String fabricName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsSinglePageAsync(fabricName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable> listByReplicationFabricsAsync(final String fabricName) { + return listByReplicationFabricsWithServiceResponseAsync(fabricName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable>> listByReplicationFabricsWithServiceResponseAsync(final String fabricName) { + return listByReplicationFabricsSinglePageAsync(fabricName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + ServiceResponse> * @param fabricName Fabric name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<VCenterInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsSinglePageAsync(final String fabricName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationFabrics(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the details of a vCenter. + * Gets the details of a registered vCenter server(Add vCenter server.). + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner get(String fabricName, String vCenterName) { + return getWithServiceResponseAsync(fabricName, vCenterName).toBlocking().single().body(); + } + + /** + * Gets the details of a vCenter. + * Gets the details of a registered vCenter server(Add vCenter server.). + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Gets the details of a vCenter. + * Gets the details of a registered vCenter server(Add vCenter server.). + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable getAsync(String fabricName, String vCenterName) { + return getWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets the details of a vCenter. + * Gets the details of a registered vCenter server(Add vCenter server.). + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable> getWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner create(String fabricName, String vCenterName) { + return createWithServiceResponseAsync(fabricName, vCenterName).toBlocking().last().body(); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String vCenterName) { + return createWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final AddVCenterRequestProperties properties = null; + AddVCenterRequest addVCenterRequest = new AddVCenterRequest(); + addVCenterRequest.withProperties(null); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), addVCenterRequest, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner create(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + return createWithServiceResponseAsync(fabricName, vCenterName, properties).toBlocking().last().body(); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createWithServiceResponseAsync(fabricName, vCenterName, properties), serviceCallback); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + return createWithServiceResponseAsync(fabricName, vCenterName, properties).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createWithServiceResponseAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + AddVCenterRequest addVCenterRequest = new AddVCenterRequest(); + addVCenterRequest.withProperties(properties); + Observable> observable = service.create(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), addVCenterRequest, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner beginCreate(String fabricName, String vCenterName) { + return beginCreateWithServiceResponseAsync(fabricName, vCenterName).toBlocking().single().body(); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable beginCreateAsync(String fabricName, String vCenterName) { + return beginCreateWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final AddVCenterRequestProperties properties = null; + AddVCenterRequest addVCenterRequest = new AddVCenterRequest(); + addVCenterRequest.withProperties(null); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), addVCenterRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner beginCreate(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, vCenterName, properties).toBlocking().single().body(); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateWithServiceResponseAsync(fabricName, vCenterName, properties), serviceCallback); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable beginCreateAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + return beginCreateWithServiceResponseAsync(fabricName, vCenterName, properties).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Add vCenter. + * The operation to create a vCenter object.. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param properties The properties of an add vCenter request. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable> beginCreateWithServiceResponseAsync(String fabricName, String vCenterName, AddVCenterRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + AddVCenterRequest addVCenterRequest = new AddVCenterRequest(); + addVCenterRequest.withProperties(properties); + return service.beginCreate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), addVCenterRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String fabricName, String vCenterName) { + deleteWithServiceResponseAsync(fabricName, vCenterName).toBlocking().last().body(); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String fabricName, String vCenterName) { + return deleteWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String fabricName, String vCenterName) { + beginDeleteWithServiceResponseAsync(fabricName, vCenterName).toBlocking().single().body(); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String fabricName, String vCenterName) { + return beginDeleteWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Remove vCenter operation. + * The operation to remove(unregister) a registered vCenter server from the vault. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner update(String fabricName, String vCenterName) { + return updateWithServiceResponseAsync(fabricName, vCenterName).toBlocking().last().body(); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String vCenterName) { + return updateWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateVCenterRequestProperties properties = null; + UpdateVCenterRequest updateVCenterRequest = new UpdateVCenterRequest(); + updateVCenterRequest.withProperties(null); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), updateVCenterRequest, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner update(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + return updateWithServiceResponseAsync(fabricName, vCenterName, properties).toBlocking().last().body(); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(fabricName, vCenterName, properties), serviceCallback); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + return updateWithServiceResponseAsync(fabricName, vCenterName, properties).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateVCenterRequest updateVCenterRequest = new UpdateVCenterRequest(); + updateVCenterRequest.withProperties(properties); + Observable> observable = service.update(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), updateVCenterRequest, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner beginUpdate(String fabricName, String vCenterName) { + return beginUpdateWithServiceResponseAsync(fabricName, vCenterName).toBlocking().single().body(); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String vCenterName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, vCenterName), serviceCallback); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable beginUpdateAsync(String fabricName, String vCenterName) { + return beginUpdateWithServiceResponseAsync(fabricName, vCenterName).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String vCenterName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final UpdateVCenterRequestProperties properties = null; + UpdateVCenterRequest updateVCenterRequest = new UpdateVCenterRequest(); + updateVCenterRequest.withProperties(null); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), updateVCenterRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the VCenterInner object if successful. + */ + public VCenterInner beginUpdate(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, vCenterName, properties).toBlocking().single().body(); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(fabricName, vCenterName, properties), serviceCallback); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable beginUpdateAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + return beginUpdateWithServiceResponseAsync(fabricName, vCenterName, properties).map(new Func1, VCenterInner>() { + @Override + public VCenterInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Update vCenter operation. + * The operation to update a registered vCenter. + * + * @param fabricName Fabric name. + * @param vCenterName vCenter name + * @param properties The update VCenter Request Properties. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the VCenterInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String fabricName, String vCenterName, UpdateVCenterRequestProperties properties) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (vCenterName == null) { + throw new IllegalArgumentException("Parameter vCenterName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(properties); + UpdateVCenterRequest updateVCenterRequest = new UpdateVCenterRequest(); + updateVCenterRequest.withProperties(properties); + return service.beginUpdate(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, vCenterName, this.client.apiVersion(), this.client.acceptLanguage(), updateVCenterRequest, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<VCenterInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<VCenterInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<VCenterInner> object if successful. + */ + public PagedList listByReplicationFabricsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationFabricsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationFabricsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable> listByReplicationFabricsNextAsync(final String nextPageLink) { + return listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable>> listByReplicationFabricsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationFabricsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationFabricsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of vCenter registered under a fabric. + * Lists the vCenter servers registered in a fabric. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<VCenterInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationFabricsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationFabricsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationFabricsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationFabricsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<VCenterInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<VCenterInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of vCenter registered under the vault. + * Lists the vCenter servers registered in the vault. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<VCenterInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/SiteRecoveryManagementClientImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/SiteRecoveryManagementClientImpl.java new file mode 100644 index 0000000000000..5025b18140b52 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/SiteRecoveryManagementClientImpl.java @@ -0,0 +1,550 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.AzureClient; +import com.microsoft.azure.AzureServiceClient; +import com.microsoft.rest.credentials.ServiceClientCredentials; +import com.microsoft.rest.RestClient; + +/** + * Initializes a new instance of the SiteRecoveryManagementClientImpl class. + */ +public class SiteRecoveryManagementClientImpl extends AzureServiceClient { + /** the {@link AzureClient} used for long running operations. */ + private AzureClient azureClient; + + /** + * Gets the {@link AzureClient} used for long running operations. + * @return the azure client; + */ + public AzureClient getAzureClient() { + return this.azureClient; + } + + /** The subscription Id. */ + private String subscriptionId; + + /** + * Gets The subscription Id. + * + * @return the subscriptionId value. + */ + public String subscriptionId() { + return this.subscriptionId; + } + + /** + * Sets The subscription Id. + * + * @param subscriptionId the subscriptionId value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + return this; + } + + /** The name of the resource group where the recovery services vault is present. */ + private String resourceGroupName; + + /** + * Gets The name of the resource group where the recovery services vault is present. + * + * @return the resourceGroupName value. + */ + public String resourceGroupName() { + return this.resourceGroupName; + } + + /** + * Sets The name of the resource group where the recovery services vault is present. + * + * @param resourceGroupName the resourceGroupName value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withResourceGroupName(String resourceGroupName) { + this.resourceGroupName = resourceGroupName; + return this; + } + + /** The name of the recovery services vault. */ + private String resourceName; + + /** + * Gets The name of the recovery services vault. + * + * @return the resourceName value. + */ + public String resourceName() { + return this.resourceName; + } + + /** + * Sets The name of the recovery services vault. + * + * @param resourceName the resourceName value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withResourceName(String resourceName) { + this.resourceName = resourceName; + return this; + } + + /** Client Api Version. */ + private String apiVersion; + + /** + * Gets Client Api Version. + * + * @return the apiVersion value. + */ + public String apiVersion() { + return this.apiVersion; + } + + /** The preferred language for the response. */ + private String acceptLanguage; + + /** + * Gets The preferred language for the response. + * + * @return the acceptLanguage value. + */ + public String acceptLanguage() { + return this.acceptLanguage; + } + + /** + * Sets The preferred language for the response. + * + * @param acceptLanguage the acceptLanguage value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withAcceptLanguage(String acceptLanguage) { + this.acceptLanguage = acceptLanguage; + return this; + } + + /** The retry timeout in seconds for Long Running Operations. Default value is 30. */ + private int longRunningOperationRetryTimeout; + + /** + * Gets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @return the longRunningOperationRetryTimeout value. + */ + public int longRunningOperationRetryTimeout() { + return this.longRunningOperationRetryTimeout; + } + + /** + * Sets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @param longRunningOperationRetryTimeout the longRunningOperationRetryTimeout value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withLongRunningOperationRetryTimeout(int longRunningOperationRetryTimeout) { + this.longRunningOperationRetryTimeout = longRunningOperationRetryTimeout; + return this; + } + + /** Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. */ + private boolean generateClientRequestId; + + /** + * Gets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @return the generateClientRequestId value. + */ + public boolean generateClientRequestId() { + return this.generateClientRequestId; + } + + /** + * Sets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @param generateClientRequestId the generateClientRequestId value. + * @return the service client itself + */ + public SiteRecoveryManagementClientImpl withGenerateClientRequestId(boolean generateClientRequestId) { + this.generateClientRequestId = generateClientRequestId; + return this; + } + + /** + * The OperationsInner object to access its operations. + */ + private OperationsInner operations; + + /** + * Gets the OperationsInner object to access its operations. + * @return the OperationsInner object. + */ + public OperationsInner operations() { + return this.operations; + } + + /** + * The ReplicationAlertSettingsInner object to access its operations. + */ + private ReplicationAlertSettingsInner replicationAlertSettings; + + /** + * Gets the ReplicationAlertSettingsInner object to access its operations. + * @return the ReplicationAlertSettingsInner object. + */ + public ReplicationAlertSettingsInner replicationAlertSettings() { + return this.replicationAlertSettings; + } + + /** + * The ReplicationEventsInner object to access its operations. + */ + private ReplicationEventsInner replicationEvents; + + /** + * Gets the ReplicationEventsInner object to access its operations. + * @return the ReplicationEventsInner object. + */ + public ReplicationEventsInner replicationEvents() { + return this.replicationEvents; + } + + /** + * The ReplicationFabricsInner object to access its operations. + */ + private ReplicationFabricsInner replicationFabrics; + + /** + * Gets the ReplicationFabricsInner object to access its operations. + * @return the ReplicationFabricsInner object. + */ + public ReplicationFabricsInner replicationFabrics() { + return this.replicationFabrics; + } + + /** + * The ReplicationLogicalNetworksInner object to access its operations. + */ + private ReplicationLogicalNetworksInner replicationLogicalNetworks; + + /** + * Gets the ReplicationLogicalNetworksInner object to access its operations. + * @return the ReplicationLogicalNetworksInner object. + */ + public ReplicationLogicalNetworksInner replicationLogicalNetworks() { + return this.replicationLogicalNetworks; + } + + /** + * The ReplicationNetworksInner object to access its operations. + */ + private ReplicationNetworksInner replicationNetworks; + + /** + * Gets the ReplicationNetworksInner object to access its operations. + * @return the ReplicationNetworksInner object. + */ + public ReplicationNetworksInner replicationNetworks() { + return this.replicationNetworks; + } + + /** + * The ReplicationNetworkMappingsInner object to access its operations. + */ + private ReplicationNetworkMappingsInner replicationNetworkMappings; + + /** + * Gets the ReplicationNetworkMappingsInner object to access its operations. + * @return the ReplicationNetworkMappingsInner object. + */ + public ReplicationNetworkMappingsInner replicationNetworkMappings() { + return this.replicationNetworkMappings; + } + + /** + * The ReplicationProtectionContainersInner object to access its operations. + */ + private ReplicationProtectionContainersInner replicationProtectionContainers; + + /** + * Gets the ReplicationProtectionContainersInner object to access its operations. + * @return the ReplicationProtectionContainersInner object. + */ + public ReplicationProtectionContainersInner replicationProtectionContainers() { + return this.replicationProtectionContainers; + } + + /** + * The ReplicationMigrationItemsInner object to access its operations. + */ + private ReplicationMigrationItemsInner replicationMigrationItems; + + /** + * Gets the ReplicationMigrationItemsInner object to access its operations. + * @return the ReplicationMigrationItemsInner object. + */ + public ReplicationMigrationItemsInner replicationMigrationItems() { + return this.replicationMigrationItems; + } + + /** + * The MigrationRecoveryPointsInner object to access its operations. + */ + private MigrationRecoveryPointsInner migrationRecoveryPoints; + + /** + * Gets the MigrationRecoveryPointsInner object to access its operations. + * @return the MigrationRecoveryPointsInner object. + */ + public MigrationRecoveryPointsInner migrationRecoveryPoints() { + return this.migrationRecoveryPoints; + } + + /** + * The ReplicationProtectableItemsInner object to access its operations. + */ + private ReplicationProtectableItemsInner replicationProtectableItems; + + /** + * Gets the ReplicationProtectableItemsInner object to access its operations. + * @return the ReplicationProtectableItemsInner object. + */ + public ReplicationProtectableItemsInner replicationProtectableItems() { + return this.replicationProtectableItems; + } + + /** + * The ReplicationProtectedItemsInner object to access its operations. + */ + private ReplicationProtectedItemsInner replicationProtectedItems; + + /** + * Gets the ReplicationProtectedItemsInner object to access its operations. + * @return the ReplicationProtectedItemsInner object. + */ + public ReplicationProtectedItemsInner replicationProtectedItems() { + return this.replicationProtectedItems; + } + + /** + * The RecoveryPointsInner object to access its operations. + */ + private RecoveryPointsInner recoveryPoints; + + /** + * Gets the RecoveryPointsInner object to access its operations. + * @return the RecoveryPointsInner object. + */ + public RecoveryPointsInner recoveryPoints() { + return this.recoveryPoints; + } + + /** + * The TargetComputeSizesInner object to access its operations. + */ + private TargetComputeSizesInner targetComputeSizes; + + /** + * Gets the TargetComputeSizesInner object to access its operations. + * @return the TargetComputeSizesInner object. + */ + public TargetComputeSizesInner targetComputeSizes() { + return this.targetComputeSizes; + } + + /** + * The ReplicationProtectionContainerMappingsInner object to access its operations. + */ + private ReplicationProtectionContainerMappingsInner replicationProtectionContainerMappings; + + /** + * Gets the ReplicationProtectionContainerMappingsInner object to access its operations. + * @return the ReplicationProtectionContainerMappingsInner object. + */ + public ReplicationProtectionContainerMappingsInner replicationProtectionContainerMappings() { + return this.replicationProtectionContainerMappings; + } + + /** + * The ReplicationRecoveryServicesProvidersInner object to access its operations. + */ + private ReplicationRecoveryServicesProvidersInner replicationRecoveryServicesProviders; + + /** + * Gets the ReplicationRecoveryServicesProvidersInner object to access its operations. + * @return the ReplicationRecoveryServicesProvidersInner object. + */ + public ReplicationRecoveryServicesProvidersInner replicationRecoveryServicesProviders() { + return this.replicationRecoveryServicesProviders; + } + + /** + * The ReplicationStorageClassificationsInner object to access its operations. + */ + private ReplicationStorageClassificationsInner replicationStorageClassifications; + + /** + * Gets the ReplicationStorageClassificationsInner object to access its operations. + * @return the ReplicationStorageClassificationsInner object. + */ + public ReplicationStorageClassificationsInner replicationStorageClassifications() { + return this.replicationStorageClassifications; + } + + /** + * The ReplicationStorageClassificationMappingsInner object to access its operations. + */ + private ReplicationStorageClassificationMappingsInner replicationStorageClassificationMappings; + + /** + * Gets the ReplicationStorageClassificationMappingsInner object to access its operations. + * @return the ReplicationStorageClassificationMappingsInner object. + */ + public ReplicationStorageClassificationMappingsInner replicationStorageClassificationMappings() { + return this.replicationStorageClassificationMappings; + } + + /** + * The ReplicationvCentersInner object to access its operations. + */ + private ReplicationvCentersInner replicationvCenters; + + /** + * Gets the ReplicationvCentersInner object to access its operations. + * @return the ReplicationvCentersInner object. + */ + public ReplicationvCentersInner replicationvCenters() { + return this.replicationvCenters; + } + + /** + * The ReplicationJobsInner object to access its operations. + */ + private ReplicationJobsInner replicationJobs; + + /** + * Gets the ReplicationJobsInner object to access its operations. + * @return the ReplicationJobsInner object. + */ + public ReplicationJobsInner replicationJobs() { + return this.replicationJobs; + } + + /** + * The ReplicationPoliciesInner object to access its operations. + */ + private ReplicationPoliciesInner replicationPolicies; + + /** + * Gets the ReplicationPoliciesInner object to access its operations. + * @return the ReplicationPoliciesInner object. + */ + public ReplicationPoliciesInner replicationPolicies() { + return this.replicationPolicies; + } + + /** + * The ReplicationRecoveryPlansInner object to access its operations. + */ + private ReplicationRecoveryPlansInner replicationRecoveryPlans; + + /** + * Gets the ReplicationRecoveryPlansInner object to access its operations. + * @return the ReplicationRecoveryPlansInner object. + */ + public ReplicationRecoveryPlansInner replicationRecoveryPlans() { + return this.replicationRecoveryPlans; + } + + /** + * The ReplicationVaultHealthsInner object to access its operations. + */ + private ReplicationVaultHealthsInner replicationVaultHealths; + + /** + * Gets the ReplicationVaultHealthsInner object to access its operations. + * @return the ReplicationVaultHealthsInner object. + */ + public ReplicationVaultHealthsInner replicationVaultHealths() { + return this.replicationVaultHealths; + } + + /** + * Initializes an instance of SiteRecoveryManagementClient client. + * + * @param credentials the management credentials for Azure + */ + public SiteRecoveryManagementClientImpl(ServiceClientCredentials credentials) { + this("https://management.azure.com", credentials); + } + + /** + * Initializes an instance of SiteRecoveryManagementClient client. + * + * @param baseUrl the base URL of the host + * @param credentials the management credentials for Azure + */ + public SiteRecoveryManagementClientImpl(String baseUrl, ServiceClientCredentials credentials) { + super(baseUrl, credentials); + initialize(); + } + + /** + * Initializes an instance of SiteRecoveryManagementClient client. + * + * @param restClient the REST client to connect to Azure. + */ + public SiteRecoveryManagementClientImpl(RestClient restClient) { + super(restClient); + initialize(); + } + + protected void initialize() { + this.apiVersion = "2018-01-10"; + this.acceptLanguage = "en-US"; + this.longRunningOperationRetryTimeout = 30; + this.generateClientRequestId = true; + this.operations = new OperationsInner(restClient().retrofit(), this); + this.replicationAlertSettings = new ReplicationAlertSettingsInner(restClient().retrofit(), this); + this.replicationEvents = new ReplicationEventsInner(restClient().retrofit(), this); + this.replicationFabrics = new ReplicationFabricsInner(restClient().retrofit(), this); + this.replicationLogicalNetworks = new ReplicationLogicalNetworksInner(restClient().retrofit(), this); + this.replicationNetworks = new ReplicationNetworksInner(restClient().retrofit(), this); + this.replicationNetworkMappings = new ReplicationNetworkMappingsInner(restClient().retrofit(), this); + this.replicationProtectionContainers = new ReplicationProtectionContainersInner(restClient().retrofit(), this); + this.replicationMigrationItems = new ReplicationMigrationItemsInner(restClient().retrofit(), this); + this.migrationRecoveryPoints = new MigrationRecoveryPointsInner(restClient().retrofit(), this); + this.replicationProtectableItems = new ReplicationProtectableItemsInner(restClient().retrofit(), this); + this.replicationProtectedItems = new ReplicationProtectedItemsInner(restClient().retrofit(), this); + this.recoveryPoints = new RecoveryPointsInner(restClient().retrofit(), this); + this.targetComputeSizes = new TargetComputeSizesInner(restClient().retrofit(), this); + this.replicationProtectionContainerMappings = new ReplicationProtectionContainerMappingsInner(restClient().retrofit(), this); + this.replicationRecoveryServicesProviders = new ReplicationRecoveryServicesProvidersInner(restClient().retrofit(), this); + this.replicationStorageClassifications = new ReplicationStorageClassificationsInner(restClient().retrofit(), this); + this.replicationStorageClassificationMappings = new ReplicationStorageClassificationMappingsInner(restClient().retrofit(), this); + this.replicationvCenters = new ReplicationvCentersInner(restClient().retrofit(), this); + this.replicationJobs = new ReplicationJobsInner(restClient().retrofit(), this); + this.replicationPolicies = new ReplicationPoliciesInner(restClient().retrofit(), this); + this.replicationRecoveryPlans = new ReplicationRecoveryPlansInner(restClient().retrofit(), this); + this.replicationVaultHealths = new ReplicationVaultHealthsInner(restClient().retrofit(), this); + this.azureClient = new AzureClient(this); + } + + /** + * Gets the User-Agent header for the client. + * + * @return the user agent string. + */ + @Override + public String userAgent() { + return String.format("%s (%s, %s, auto-generated)", super.userAgent(), "SiteRecoveryManagementClient", "2018-01-10"); + } +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationImpl.java new file mode 100644 index 0000000000000..cc5603cec3665 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationImpl.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassification; +import com.microsoft.azure.arm.model.implementation.IndexableRefreshableWrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationProperties; + +class StorageClassificationImpl extends IndexableRefreshableWrapperImpl implements StorageClassification { + private final RecoveryServicesManager manager; + private String fabricName; + private String storageClassificationName; + + StorageClassificationImpl(StorageClassificationInner inner, RecoveryServicesManager manager) { + super(null, inner); + this.manager = manager; + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.storageClassificationName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationStorageClassifications"); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + protected Observable getInnerAsync() { + ReplicationStorageClassificationsInner client = this.manager().inner().replicationStorageClassifications(); + return client.getAsync(this.fabricName, this.storageClassificationName); + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public StorageClassificationProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationInner.java new file mode 100644 index 0000000000000..7243a22b0f640 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Storage object definition. + */ +public class StorageClassificationInner extends ProxyResource { + /** + * Properties of the storage object. + */ + @JsonProperty(value = "properties") + private StorageClassificationProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get properties of the storage object. + * + * @return the properties value + */ + public StorageClassificationProperties properties() { + return this.properties; + } + + /** + * Set properties of the storage object. + * + * @param properties the properties value to set + * @return the StorageClassificationInner object itself. + */ + public StorageClassificationInner withProperties(StorageClassificationProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the StorageClassificationInner object itself. + */ + public StorageClassificationInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingImpl.java new file mode 100644 index 0000000000000..1cda9856e7f8e --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingImpl.java @@ -0,0 +1,141 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationMapping; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageMappingInputProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationMappingProperties; +import rx.functions.Func1; + +class StorageClassificationMappingImpl extends CreatableUpdatableImpl implements StorageClassificationMapping, StorageClassificationMapping.Definition, StorageClassificationMapping.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String storageClassificationName; + private String storageClassificationMappingName; + private StorageMappingInputProperties cproperties; + private StorageMappingInputProperties uproperties; + + StorageClassificationMappingImpl(String name, RecoveryServicesManager manager) { + super(name, new StorageClassificationMappingInner()); + this.manager = manager; + // Set resource name + this.storageClassificationMappingName = name; + // + this.cproperties = new StorageMappingInputProperties(); + this.uproperties = new StorageMappingInputProperties(); + } + + StorageClassificationMappingImpl(StorageClassificationMappingInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.storageClassificationMappingName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.storageClassificationName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationStorageClassifications"); + this.storageClassificationMappingName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationStorageClassificationMappings"); + // + this.cproperties = new StorageMappingInputProperties(); + this.uproperties = new StorageMappingInputProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationStorageClassificationMappingsInner client = this.manager().inner().replicationStorageClassificationMappings(); + return client.createAsync(this.fabricName, this.storageClassificationName, this.storageClassificationMappingName, this.cproperties) + .map(new Func1() { + @Override + public StorageClassificationMappingInner call(StorageClassificationMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationStorageClassificationMappingsInner client = this.manager().inner().replicationStorageClassificationMappings(); + return client.createAsync(this.fabricName, this.storageClassificationName, this.storageClassificationMappingName, this.uproperties) + .map(new Func1() { + @Override + public StorageClassificationMappingInner call(StorageClassificationMappingInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationStorageClassificationMappingsInner client = this.manager().inner().replicationStorageClassificationMappings(); + return client.getAsync(this.fabricName, this.storageClassificationName, this.storageClassificationMappingName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new StorageMappingInputProperties(); + this.uproperties = new StorageMappingInputProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public StorageClassificationMappingProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public StorageClassificationMappingImpl withExistingReplicationStorageClassification(String fabricName, String storageClassificationName) { + this.fabricName = fabricName; + this.storageClassificationName = storageClassificationName; + return this; + } + + @Override + public StorageClassificationMappingImpl withProperties(StorageMappingInputProperties properties) { + if (isInCreateMode()) { + this.cproperties = properties; + } else { + this.uproperties = properties; + } + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingInner.java new file mode 100644 index 0000000000000..8f91fec845d27 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/StorageClassificationMappingInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.StorageClassificationMappingProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Storage mapping object. + */ +public class StorageClassificationMappingInner extends ProxyResource { + /** + * Properties of the storage mapping object. + */ + @JsonProperty(value = "properties") + private StorageClassificationMappingProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get properties of the storage mapping object. + * + * @return the properties value + */ + public StorageClassificationMappingProperties properties() { + return this.properties; + } + + /** + * Set properties of the storage mapping object. + * + * @param properties the properties value to set + * @return the StorageClassificationMappingInner object itself. + */ + public StorageClassificationMappingInner withProperties(StorageClassificationMappingProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the StorageClassificationMappingInner object itself. + */ + public StorageClassificationMappingInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeImpl.java new file mode 100644 index 0000000000000..a94d301dc78bc --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeImpl.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSize; +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizeProperties; + +class TargetComputeSizeImpl extends WrapperImpl implements TargetComputeSize { + private final RecoveryServicesManager manager; + + TargetComputeSizeImpl(TargetComputeSizeInner inner, RecoveryServicesManager manager) { + super(inner); + this.manager = manager; + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public TargetComputeSizeProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeInner.java new file mode 100644 index 0000000000000..28a060a6a3fd0 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizeInner.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizeProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Represents applicable recovery vm sizes. + */ +public class TargetComputeSizeInner { + /** + * The Id. + */ + @JsonProperty(value = "id") + private String id; + + /** + * The name. + */ + @JsonProperty(value = "name") + private String name; + + /** + * The Type of the object. + */ + @JsonProperty(value = "type") + private String type; + + /** + * The custom data. + */ + @JsonProperty(value = "properties") + private TargetComputeSizeProperties properties; + + /** + * Get the Id. + * + * @return the id value + */ + public String id() { + return this.id; + } + + /** + * Set the Id. + * + * @param id the id value to set + * @return the TargetComputeSizeInner object itself. + */ + public TargetComputeSizeInner withId(String id) { + this.id = id; + return this; + } + + /** + * Get the name. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Set the name. + * + * @param name the name value to set + * @return the TargetComputeSizeInner object itself. + */ + public TargetComputeSizeInner withName(String name) { + this.name = name; + return this; + } + + /** + * Get the Type of the object. + * + * @return the type value + */ + public String type() { + return this.type; + } + + /** + * Set the Type of the object. + * + * @param type the type value to set + * @return the TargetComputeSizeInner object itself. + */ + public TargetComputeSizeInner withType(String type) { + this.type = type; + return this; + } + + /** + * Get the custom data. + * + * @return the properties value + */ + public TargetComputeSizeProperties properties() { + return this.properties; + } + + /** + * Set the custom data. + * + * @param properties the properties value to set + * @return the TargetComputeSizeInner object itself. + */ + public TargetComputeSizeInner withProperties(TargetComputeSizeProperties properties) { + this.properties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesImpl.java new file mode 100644 index 0000000000000..f347e994a0e11 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesImpl.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizes; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSize; + +class TargetComputeSizesImpl extends WrapperImpl implements TargetComputeSizes { + private final RecoveryServicesManager manager; + + TargetComputeSizesImpl(RecoveryServicesManager manager) { + super(manager.inner().targetComputeSizes()); + this.manager = manager; + } + + public RecoveryServicesManager manager() { + return this.manager; + } + + private TargetComputeSizeImpl wrapModel(TargetComputeSizeInner inner) { + return new TargetComputeSizeImpl(inner, manager()); + } + + @Override + public Observable listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + TargetComputeSizesInner client = this.inner(); + return client.listByReplicationProtectedItemsAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public TargetComputeSize call(TargetComputeSizeInner inner) { + return wrapModel(inner); + } + }); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesInner.java new file mode 100644 index 0000000000000..ade5aa518aaca --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/TargetComputeSizesInner.java @@ -0,0 +1,327 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in TargetComputeSizes. + */ +public class TargetComputeSizesInner { + /** The Retrofit service to perform REST calls. */ + private TargetComputeSizesService service; + /** The service client containing this operation class. */ + private SiteRecoveryManagementClientImpl client; + + /** + * Initializes an instance of TargetComputeSizesInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public TargetComputeSizesInner(Retrofit retrofit, SiteRecoveryManagementClientImpl client) { + this.service = retrofit.create(TargetComputeSizesService.class); + this.client = client; + } + + /** + * The interface defining all the services for TargetComputeSizes to be + * used by Retrofit to perform actually REST calls. + */ + interface TargetComputeSizesService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizes listByReplicationProtectedItems" }) + @GET("Subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.RecoveryServices/vaults/{resourceName}/replicationFabrics/{fabricName}/replicationProtectionContainers/{protectionContainerName}/replicationProtectedItems/{replicatedProtectedItemName}/targetComputeSizes") + Observable> listByReplicationProtectedItems(@Path("resourceName") String resourceName, @Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Path("fabricName") String fabricName, @Path("protectionContainerName") String protectionContainerName, @Path("replicatedProtectedItemName") String replicatedProtectedItemName, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.TargetComputeSizes listByReplicationProtectedItemsNext" }) + @GET + Observable> listByReplicationProtectedItemsNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<TargetComputeSizeInner> object if successful. + */ + public PagedList listByReplicationProtectedItems(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + ServiceResponse> response = listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<TargetComputeSizeInner> object + */ + public Observable> listByReplicationProtectedItemsAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + return listByReplicationProtectedItemsWithServiceResponseAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param fabricName Fabric name. + * @param protectionContainerName protection container name. + * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<TargetComputeSizeInner> object + */ + public Observable>> listByReplicationProtectedItemsWithServiceResponseAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + return listByReplicationProtectedItemsSinglePageAsync(fabricName, protectionContainerName, replicatedProtectedItemName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + ServiceResponse> * @param fabricName Fabric name. + ServiceResponse> * @param protectionContainerName protection container name. + ServiceResponse> * @param replicatedProtectedItemName Replication protected item name. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<TargetComputeSizeInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectedItemsSinglePageAsync(final String fabricName, final String protectionContainerName, final String replicatedProtectedItemName) { + if (this.client.resourceName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceName() is required and cannot be null."); + } + if (this.client.resourceGroupName() == null) { + throw new IllegalArgumentException("Parameter this.client.resourceGroupName() is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (fabricName == null) { + throw new IllegalArgumentException("Parameter fabricName is required and cannot be null."); + } + if (protectionContainerName == null) { + throw new IllegalArgumentException("Parameter protectionContainerName is required and cannot be null."); + } + if (replicatedProtectedItemName == null) { + throw new IllegalArgumentException("Parameter replicatedProtectedItemName is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByReplicationProtectedItems(this.client.resourceName(), this.client.resourceGroupName(), this.client.subscriptionId(), fabricName, protectionContainerName, replicatedProtectedItemName, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectedItemsDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectedItemsDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<TargetComputeSizeInner> object if successful. + */ + public PagedList listByReplicationProtectedItemsNext(final String nextPageLink) { + ServiceResponse> response = listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByReplicationProtectedItemsNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<TargetComputeSizeInner> object + */ + public Observable> listByReplicationProtectedItemsNextAsync(final String nextPageLink) { + return listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<TargetComputeSizeInner> object + */ + public Observable>> listByReplicationProtectedItemsNextWithServiceResponseAsync(final String nextPageLink) { + return listByReplicationProtectedItemsNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByReplicationProtectedItemsNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets the list of target compute sizes for the replication protected item. + * Lists the available target compute sizes for a replication protected item. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<TargetComputeSizeInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByReplicationProtectedItemsNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByReplicationProtectedItemsNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByReplicationProtectedItemsNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByReplicationProtectedItemsNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterImpl.java new file mode 100644 index 0000000000000..934e6cb2ce978 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterImpl.java @@ -0,0 +1,141 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VCenter; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.UpdateVCenterRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.AddVCenterRequestProperties; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VCenterProperties; +import rx.functions.Func1; + +class VCenterImpl extends CreatableUpdatableImpl implements VCenter, VCenter.Definition, VCenter.Update { + private final RecoveryServicesManager manager; + private String fabricName; + private String vCenterName; + private AddVCenterRequestProperties cproperties; + private UpdateVCenterRequestProperties uproperties; + + VCenterImpl(String name, RecoveryServicesManager manager) { + super(name, new VCenterInner()); + this.manager = manager; + // Set resource name + this.vCenterName = name; + // + this.cproperties = new AddVCenterRequestProperties(); + this.uproperties = new UpdateVCenterRequestProperties(); + } + + VCenterImpl(VCenterInner inner, RecoveryServicesManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.vCenterName = inner.name(); + // set resource ancestor and positional variables + this.fabricName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationFabrics"); + this.vCenterName = IdParsingUtils.getValueFromIdByName(inner.id(), "replicationvCenters"); + // + this.cproperties = new AddVCenterRequestProperties(); + this.uproperties = new UpdateVCenterRequestProperties(); + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + ReplicationvCentersInner client = this.manager().inner().replicationvCenters(); + return client.createAsync(this.fabricName, this.vCenterName, this.cproperties) + .map(new Func1() { + @Override + public VCenterInner call(VCenterInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + ReplicationvCentersInner client = this.manager().inner().replicationvCenters(); + return client.updateAsync(this.fabricName, this.vCenterName, this.uproperties) + .map(new Func1() { + @Override + public VCenterInner call(VCenterInner resource) { + resetCreateUpdateParameters(); + return resource; + } + }) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + ReplicationvCentersInner client = this.manager().inner().replicationvCenters(); + return client.getAsync(this.fabricName, this.vCenterName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + private void resetCreateUpdateParameters() { + this.cproperties = new AddVCenterRequestProperties(); + this.uproperties = new UpdateVCenterRequestProperties(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public VCenterProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public VCenterImpl withExistingReplicationFabric(String fabricName) { + this.fabricName = fabricName; + return this; + } + + @Override + public VCenterImpl withProperties(AddVCenterRequestProperties properties) { + this.cproperties = properties; + return this; + } + + @Override + public VCenterImpl withProperties(UpdateVCenterRequestProperties properties) { + this.uproperties = properties; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterInner.java new file mode 100644 index 0000000000000..30aa515a1ffa4 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VCenterInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VCenterProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * vCenter definition. + */ +public class VCenterInner extends ProxyResource { + /** + * VCenter related data. + */ + @JsonProperty(value = "properties") + private VCenterProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get vCenter related data. + * + * @return the properties value + */ + public VCenterProperties properties() { + return this.properties; + } + + /** + * Set vCenter related data. + * + * @param properties the properties value to set + * @return the VCenterInner object itself. + */ + public VCenterInner withProperties(VCenterProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the VCenterInner object itself. + */ + public VCenterInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsImpl.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsImpl.java new file mode 100644 index 0000000000000..7e7ac40949e9c --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsImpl.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VaultHealthDetails; +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VaultHealthProperties; + +class VaultHealthDetailsImpl extends WrapperImpl implements VaultHealthDetails { + private final RecoveryServicesManager manager; + VaultHealthDetailsImpl(VaultHealthDetailsInner inner, RecoveryServicesManager manager) { + super(inner); + this.manager = manager; + } + + @Override + public RecoveryServicesManager manager() { + return this.manager; + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public String location() { + return this.inner().location(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public VaultHealthProperties properties() { + return this.inner().properties(); + } + + @Override + public String type() { + return this.inner().type(); + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsInner.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsInner.java new file mode 100644 index 0000000000000..b1c758f52be37 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/VaultHealthDetailsInner.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; + +import com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.VaultHealthProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.ProxyResource; + +/** + * Vault health details definition. + */ +public class VaultHealthDetailsInner extends ProxyResource { + /** + * The vault health related data. + */ + @JsonProperty(value = "properties") + private VaultHealthProperties properties; + + /** + * Resource Location. + */ + @JsonProperty(value = "location") + private String location; + + /** + * Get the vault health related data. + * + * @return the properties value + */ + public VaultHealthProperties properties() { + return this.properties; + } + + /** + * Set the vault health related data. + * + * @param properties the properties value to set + * @return the VaultHealthDetailsInner object itself. + */ + public VaultHealthDetailsInner withProperties(VaultHealthProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get resource Location. + * + * @return the location value + */ + public String location() { + return this.location; + } + + /** + * Set resource Location. + * + * @param location the location value to set + * @return the VaultHealthDetailsInner object itself. + */ + public VaultHealthDetailsInner withLocation(String location) { + this.location = location; + return this; + } + +} diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/package-info.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/package-info.java new file mode 100644 index 0000000000000..12e976d958486 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/implementation/package-info.java @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementation classes for SiteRecoveryManagementClient. + */ +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10.implementation; diff --git a/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/package-info.java b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/package-info.java new file mode 100644 index 0000000000000..507520184bab7 --- /dev/null +++ b/recoveryservices.siterecovery/resource-manager/v2018_01_10/src/main/java/com/microsoft/azure/management/recoveryservices/siterecovery/v2018_01_10/package-info.java @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the classes for SiteRecoveryManagementClient. + */ +package com.microsoft.azure.management.recoveryservices.siterecovery.v2018_01_10; diff --git a/relay/resource-manager/v2017_04_01/pom.xml b/relay/resource-manager/v2017_04_01/pom.xml index ae40ed2b2f1c3..c0339025f1b5c 100644 --- a/relay/resource-manager/v2017_04_01/pom.xml +++ b/relay/resource-manager/v2017_04_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5
diff --git a/resourcehealth/resource-manager/v2015_01_01/pom.xml b/resourcehealth/resource-manager/v2015_01_01/pom.xml index b35fcde154c64..1baf0aa38a317 100644 --- a/resourcehealth/resource-manager/v2015_01_01/pom.xml +++ b/resourcehealth/resource-manager/v2015_01_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5
diff --git a/resourcehealth/resource-manager/v2017_07_01/pom.xml b/resourcehealth/resource-manager/v2017_07_01/pom.xml index 58d389a738ce3..6c7701b4d0419 100644 --- a/resourcehealth/resource-manager/v2017_07_01/pom.xml +++ b/resourcehealth/resource-manager/v2017_07_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/resources/resource-manager/v2016_09_01/pom.xml b/resources/resource-manager/v2016_09_01/pom.xml index 0fa6698b6ff77..59b942d2fc758 100644 --- a/resources/resource-manager/v2016_09_01/pom.xml +++ b/resources/resource-manager/v2016_09_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/resources/resource-manager/v2019_05_01/pom.xml b/resources/resource-manager/v2019_05_01/pom.xml index 5ea7968f30c55..876f64e4c98e6 100644 --- a/resources/resource-manager/v2019_05_01/pom.xml +++ b/resources/resource-manager/v2019_05_01/pom.xml @@ -15,7 +15,7 @@ ../../../pom.management.xml azure-mgmt-resources - 1.0.0-beta + 1.0.0-beta-1 jar Microsoft Azure SDK for Resources Management This package contains Microsoft Resources Management SDK. @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/ExportTemplateRequest.java b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/ExportTemplateRequest.java index 78ff8304a7997..849e59b07cf22 100644 --- a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/ExportTemplateRequest.java +++ b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/ExportTemplateRequest.java @@ -16,23 +16,23 @@ */ public class ExportTemplateRequest { /** - * The IDs of the resources. The only supported string currently is '*' - * (all resources). Future updates will support exporting specific - * resources. + * The IDs of the resources to filter the export by. To export all + * resources, supply an array with single entry '*'. */ @JsonProperty(value = "resources") private List resources; /** - * The export template options. Supported values include - * 'IncludeParameterDefaultValue', 'IncludeComments' or - * 'IncludeParameterDefaultValue, IncludeComments. + * The export template options. A CSV-formatted list containing zero or + * more of the following: 'IncludeParameterDefaultValue', + * 'IncludeComments', 'SkipResourceNameParameterization', + * 'SkipAllParameterization'. */ @JsonProperty(value = "options") private String options; /** - * Get the IDs of the resources. The only supported string currently is '*' (all resources). Future updates will support exporting specific resources. + * Get the IDs of the resources to filter the export by. To export all resources, supply an array with single entry '*'. * * @return the resources value */ @@ -41,7 +41,7 @@ public List resources() { } /** - * Set the IDs of the resources. The only supported string currently is '*' (all resources). Future updates will support exporting specific resources. + * Set the IDs of the resources to filter the export by. To export all resources, supply an array with single entry '*'. * * @param resources the resources value to set * @return the ExportTemplateRequest object itself. @@ -52,7 +52,7 @@ public ExportTemplateRequest withResources(List resources) { } /** - * Get the export template options. Supported values include 'IncludeParameterDefaultValue', 'IncludeComments' or 'IncludeParameterDefaultValue, IncludeComments. + * Get the export template options. A CSV-formatted list containing zero or more of the following: 'IncludeParameterDefaultValue', 'IncludeComments', 'SkipResourceNameParameterization', 'SkipAllParameterization'. * * @return the options value */ @@ -61,7 +61,7 @@ public String options() { } /** - * Set the export template options. Supported values include 'IncludeParameterDefaultValue', 'IncludeComments' or 'IncludeParameterDefaultValue, IncludeComments. + * Set the export template options. A CSV-formatted list containing zero or more of the following: 'IncludeParameterDefaultValue', 'IncludeComments', 'SkipResourceNameParameterization', 'SkipAllParameterization'. * * @param options the options value to set * @return the ExportTemplateRequest object itself. diff --git a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/DeploymentOperationsImpl.java b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/DeploymentOperationsImpl.java index ee2ba19fa3d05..feff2c66838c1 100644 --- a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/DeploymentOperationsImpl.java +++ b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/DeploymentOperationsImpl.java @@ -114,10 +114,14 @@ public DeploymentOperation call(DeploymentOperationInner inner) { public Observable getAtManagementGroupScopeAsync(String groupId, String deploymentName, String operationId) { DeploymentOperationsInner client = this.inner(); return client.getAtManagementGroupScopeAsync(groupId, deploymentName, operationId) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public DeploymentOperation call(DeploymentOperationInner inner) { - return wrapModel(inner); + public Observable call(DeploymentOperationInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((DeploymentOperation)wrapModel(inner)); + } } }); } diff --git a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ProvidersImpl.java b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ProvidersImpl.java index 60b5f189ceb4e..0d0e9d92facbb 100644 --- a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ProvidersImpl.java +++ b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ProvidersImpl.java @@ -78,10 +78,14 @@ public Provider call(ProviderInner inner) { public Observable getAsync(String resourceProviderNamespace) { ProvidersInner client = this.inner(); return client.getAsync(resourceProviderNamespace) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public Provider call(ProviderInner inner) { - return wrapModel(inner); + public Observable call(ProviderInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((Provider)wrapModel(inner)); + } } }); } diff --git a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ResourceGroupsImpl.java b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ResourceGroupsImpl.java index b942e2864c31b..440565aa7dd9f 100644 --- a/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ResourceGroupsImpl.java +++ b/resources/resource-manager/v2019_05_01/src/main/java/com/microsoft/azure/management/resources/v2019_05_01/implementation/ResourceGroupsImpl.java @@ -84,10 +84,14 @@ public ResourceGroup call(ResourceGroupInner inner) { public Observable getAsync(String resourceGroupName) { ResourceGroupsInner client = this.inner(); return client.getAsync(resourceGroupName) - .map(new Func1() { + .flatMap(new Func1>() { @Override - public ResourceGroup call(ResourceGroupInner inner) { - return wrapModel(inner); + public Observable call(ResourceGroupInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((ResourceGroup)wrapModel(inner)); + } } }); } diff --git a/appconfiguration/client/README.md b/sdk/appconfiguration/azure-data-appconfiguration/README.md similarity index 82% rename from appconfiguration/client/README.md rename to sdk/appconfiguration/azure-data-appconfiguration/README.md index cdc77d4139f32..9f9d8d835e29c 100644 --- a/appconfiguration/client/README.md +++ b/sdk/appconfiguration/azure-data-appconfiguration/README.md @@ -11,7 +11,7 @@ Use the client library for App Configuration to create and manage application co ### Prerequisites -- [Java Development Kit (JDK)][jdk] with version 8 or above +- Java Development Kit (JDK) with version 8 or above - [Azure Subscription][azure_subscription] - [App Configuration Store][app_config_store] @@ -20,8 +20,8 @@ Use the client library for App Configuration to create and manage application co ```xml com.azure - azure-app-configuration - 1.0.0-SNAPSHOT + azure-data-appconfiguration + 1.0.0-preview.1 ``` @@ -58,17 +58,17 @@ Alternatively, get the connection string from the Azure Portal. Once you have the value of the connection string you can create the configuration client: ```Java -ConfigurationClient client = ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildClient(); ``` or ```Java -ConfigurationAsyncClient client = ConfigurationAsyncClient.builder() +ConfigurationAsyncClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildAsyncClient(); ``` ## Key concepts @@ -83,12 +83,12 @@ The Label property of a Configuration Setting provides a way to separate Configu The client performs the interactions with the App Configuration service, getting, setting, updating, deleting, and selecting configuration settings. An asynchronous, `ConfigurationAsyncClient`, and synchronous, `ConfigurationClient`, client exists in the SDK allowing for selection of a client based on an application's use case. -An application that needs to retrieve startup configurations is better suited using the syncrhonous client, for example setting up a SQL connection. +An application that needs to retrieve startup configurations is better suited using the synchronous client, for example setting up a SQL connection. ```Java -ConfigurationClient client = new ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClient() .credentials(new ConfigurationClientCredentials(appConfigConnectionString)) - .build(); + .buildClient(); String url = client.getSetting(urlKey).value(); Connection conn; @@ -100,12 +100,12 @@ try { ``` -An application that has a large set of configurations that it needs to periodically update is be better suited using the asynchonous client, for example all settings with a specific label are periodically updated. +An application that has a large set of configurations that it needs to periodically update is be better suited using the asynchronous client, for example all settings with a specific label are periodically updated. ```Java -ConfigurationAsyncClient client = new ConfigurationAsyncClient.builder() +ConfigurationAsyncClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(appConfigConnectionString)) - .build(); + .buildAsyncClient(); client.listSettings(new SettingSelection().label(periodicUpdateLabel)) .subscribe(setting -> updateConfiguration(setting)); @@ -125,9 +125,9 @@ Create a Configuration Setting to be stored in the Configuration Store. There ar - addSetting creates a setting only if the setting does not already exist in the store. - setSetting creates a setting if it doesn't exist or overrides an existing setting. ```Java -ConfigurationClient client = ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildClient(); ConfigurationSetting setting = client.setSetting("some_key", "some_value"); ``` @@ -135,9 +135,9 @@ ConfigurationSetting setting = client.setSetting("some_key", "some_value"); Retrieve a previously stored Configuration Setting by calling getSetting. ```Java -ConfigurationClient client = ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildClient(); client.setSetting("some_key", "some_value"); ConfigurationSetting setting = client.getSetting("some_key"); ``` @@ -146,9 +146,9 @@ ConfigurationSetting setting = client.getSetting("some_key"); Update an existing Configuration Setting by calling updateSetting. ```Java -ConfigurationClient client = ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildClient(); client.setSetting("some_key", "some_value"); ConfigurationSetting setting = client.updateSetting("some_key", "new_value"); ``` @@ -157,9 +157,9 @@ ConfigurationSetting setting = client.updateSetting("some_key", "new_value"); Delete an existing Configuration Setting by calling deleteSetting. ```Java -ConfigurationClient client = ConfigurationClient.builder() +ConfigurationClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildClient(); client.setSetting("some_key", "some_value"); ConfigurationSetting setting = client.deleteSetting("some_key"); ``` @@ -168,7 +168,7 @@ ConfigurationSetting setting = client.deleteSetting("some_key"); ### General -When you interact with App Configuration using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][azconfig_rest] requests. For example, if you try to retrieve a Configuration Setting that doesn't exist in your Configuration Store, a `404` error is returned, indicating `Not Found`. +When you interact with App Configuration using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][rest_api] requests. For example, if you try to retrieve a Configuration Setting that doesn't exist in your Configuration Store, a `404` error is returned, indicating `Not Found`. ## Next steps @@ -185,14 +185,12 @@ If you would like to become an active contributor to this project please follow 5. Create new Pull Request -[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/master/applicationconfig/client/src -[package]:not-valid-link -[api_documentation]: not-valid-link -[azconfig_docs]: https://docs.microsoft.com/en-us/azure/azure-app-configuration/ -[jdk]: https://docs.microsoft.com/en-us/java/azure/java-supported-jdk-runtime?view=azure-java-stable -[maven]: https://maven.apache.org/ -[azure_subscription]: https://azure.microsoft.com/en-us/free/ +[api_documentation]: https://aka.ms/java-docs [app_config_store]: https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-dotnet-core-app#create-an-app-configuration-store +[azconfig_docs]: https://docs.microsoft.com/en-us/azure/azure-app-configuration/ [azure_cli]: https://docs.microsoft.com/cli/azure +[azure_subscription]: https://azure.microsoft.com/en-us/free/ +[maven]: https://maven.apache.org/ +[package]: https://search.maven.org/artifact/com.azure/azure-data-appconfiguration [rest_api]: https://github.com/Azure/AppConfiguration#rest-api-reference -[azconfig_rest]: https://github.com/Azure/AppConfiguration#rest-api-reference +[source_code]: src diff --git a/appconfiguration/client/pom.xml b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml similarity index 82% rename from appconfiguration/client/pom.xml rename to sdk/appconfiguration/azure-data-appconfiguration/pom.xml index 457fed3587a86..5f3c743e6a266 100644 --- a/appconfiguration/client/pom.xml +++ b/sdk/appconfiguration/azure-data-appconfiguration/pom.xml @@ -7,16 +7,16 @@ com.azure azure-client-sdk-parent - 1.0.0 - ../../pom.client.xml + 1.1.0 + ../../../pom.client.xml com.azure azure-data-appconfiguration - 1.0.0-SNAPSHOT + 1.0.0-preview.1 - Microsoft Azure client library for Application Configuration - This package contains the Microsoft Azure Application Configuration client library. + Microsoft Azure client library for App Configuration + This package contains the Microsoft Azure App Configuration client library. https://github.com/Azure/azure-sdk-for-java @@ -36,7 +36,7 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 org.slf4j @@ -46,7 +46,7 @@ com.azure azure-core-test - 1.0.0-preview.1 + 1.0.0-preview.3 test diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/AzureConfiguration.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/AzureConfiguration.java similarity index 100% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/AzureConfiguration.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/AzureConfiguration.java diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java similarity index 89% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java index f31f3588b4109..267df4df2f213 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClient.java @@ -35,18 +35,14 @@ * *

Instantiating an Asynchronous Configuration Client

* - *
- * ConfigurationAsyncClient client = ConfigurationAsyncClient.builder()
- *     .credentials(new ConfigurationClientCredentials(connectionString))
- *     .build();
- * 
+ * {@codesnippet com.azure.data.applicationconfig.async.configurationclient.instantiation} * - *

View {@link ConfigurationAsyncClientBuilder this} for additional ways to construct the client.

+ *

View {@link ConfigurationClientBuilder this} for additional ways to construct the client.

* - * @see ConfigurationAsyncClientBuilder + * @see ConfigurationClientBuilder * @see ConfigurationClientCredentials */ -@ServiceClient(builder = ConfigurationAsyncClientBuilder.class, isAsync = true, serviceInterfaces = ConfigurationService.class) +@ServiceClient(builder = ConfigurationClientBuilder.class, isAsync = true, serviceInterfaces = ConfigurationService.class) public final class ConfigurationAsyncClient { private final ClientLogger logger = new ClientLogger(ConfigurationAsyncClient.class); @@ -60,7 +56,7 @@ public final class ConfigurationAsyncClient { * Creates a ConfigurationAsyncClient that sends requests to the configuration service at {@code serviceEndpoint}. * Each service call goes through the {@code pipeline}. * - * @param serviceEndpoint URL for the Application configuration service. + * @param serviceEndpoint URL for the App Configuration service. * @param pipeline HttpPipeline that the HTTP requests and responses flow through. */ ConfigurationAsyncClient(URL serviceEndpoint, HttpPipeline pipeline) { @@ -68,15 +64,6 @@ public final class ConfigurationAsyncClient { this.serviceEndpoint = serviceEndpoint.toString(); } - /** - * Creates a builder that can configure options for the ConfigurationAsyncClient before creating an instance of it. - * - * @return A new {@link ConfigurationAsyncClientBuilder} to create a ConfigurationAsyncClient from. - */ - public static ConfigurationAsyncClientBuilder builder() { - return new ConfigurationAsyncClientBuilder(); - } - /** * Adds a configuration value in the service if that key does not exist. * @@ -163,10 +150,10 @@ Mono> addSetting(ConfigurationSetting setting, Co // This service method call is similar to setSetting except we're passing If-Not-Match = "*". If the service // finds any existing configuration settings, then its e-tag will match and the service will return an error. return service.setKey(serviceEndpoint, setting.key(), setting.label(), setting, null, getETagValue(ETAG_ANY), context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Adding ConfigurationSetting - {}", setting)) - .doOnSuccess(response -> logger.asInfo().log("Added ConfigurationSetting - {}", response.value())) + .doOnRequest(ignoredValue -> logger.info("Adding ConfigurationSetting - {}", setting)) + .doOnSuccess(response -> logger.info("Added ConfigurationSetting - {}", response.value())) .onErrorMap(ConfigurationAsyncClient::addSettingExceptionMapper) - .doOnError(error -> logger.asWarning().log("Failed to add ConfigurationSetting - {}", setting, error)); + .doOnError(error -> logger.warning("Failed to add ConfigurationSetting - {}", setting, error)); } /** @@ -300,9 +287,9 @@ Mono> setSetting(ConfigurationSetting setting, Co // old value locally. // If no etag value was passed in, then the value is always added or updated. return service.setKey(serviceEndpoint, setting.key(), setting.label(), setting, getETagValue(setting.etag()), null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Setting ConfigurationSetting - {}", setting)) - .doOnSuccess(response -> logger.asInfo().log("Set ConfigurationSetting - {}", response.value())) - .doOnError(error -> logger.asWarning().log("Failed to set ConfigurationSetting - {}", setting, error)); + .doOnRequest(ignoredValue -> logger.info("Setting ConfigurationSetting - {}", setting)) + .doOnSuccess(response -> logger.info("Set ConfigurationSetting - {}", response.value())) + .doOnError(error -> logger.warning("Failed to set ConfigurationSetting - {}", setting, error)); } /** @@ -400,9 +387,9 @@ Mono> updateSetting(ConfigurationSetting setting, String etag = setting.etag() == null ? ETAG_ANY : setting.etag(); return service.setKey(serviceEndpoint, setting.key(), setting.label(), setting, getETagValue(etag), null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Updating ConfigurationSetting - {}", setting)) - .doOnSuccess(response -> logger.asInfo().log("Updated ConfigurationSetting - {}", response.value())) - .doOnError(error -> logger.asWarning().log("Failed to update ConfigurationSetting - {}", setting, error)); + .doOnRequest(ignoredValue -> logger.info("Updating ConfigurationSetting - {}", setting)) + .doOnSuccess(response -> logger.info("Updated ConfigurationSetting - {}", response.value())) + .doOnError(error -> logger.warning("Failed to update ConfigurationSetting - {}", setting, error)); } /** @@ -486,9 +473,9 @@ Mono> getSetting(ConfigurationSetting setting, Co validateSetting(setting); return service.getKeyValue(serviceEndpoint, setting.key(), setting.label(), null, null, null, null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving ConfigurationSetting - {}", setting)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved ConfigurationSetting - {}", response.value())) - .doOnError(error -> logger.asWarning().log("Failed to get ConfigurationSetting - {}", setting, error)); + .doOnRequest(ignoredValue -> logger.info("Retrieving ConfigurationSetting - {}", setting)) + .doOnSuccess(response -> logger.info("Retrieved ConfigurationSetting - {}", response.value())) + .doOnError(error -> logger.warning("Failed to get ConfigurationSetting - {}", setting, error)); } /** @@ -586,9 +573,9 @@ Mono> deleteSetting(ConfigurationSetting setting, validateSetting(setting); return service.delete(serviceEndpoint, setting.key(), setting.label(), getETagValue(setting.etag()), null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Deleting ConfigurationSetting - {}", setting)) - .doOnSuccess(response -> logger.asInfo().log("Deleted ConfigurationSetting - {}", response.value())) - .doOnError(error -> logger.asWarning().log("Failed to delete ConfigurationSetting - {}", setting, error)); + .doOnRequest(ignoredValue -> logger.info("Deleting ConfigurationSetting - {}", setting)) + .doOnSuccess(response -> logger.info("Deleted ConfigurationSetting - {}", response.value())) + .doOnError(error -> logger.warning("Failed to delete ConfigurationSetting - {}", setting, error)); } /** @@ -639,18 +626,18 @@ private Mono> listNextPageSettings(Context c } return service.listKeyValues(serviceEndpoint, continuationToken, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving the next listing page - Page {}", continuationToken)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved the next listing page - Page {}", continuationToken)) - .doOnError(error -> logger.asWarning().log("Failed to retrieve the next listing page - Page {}", continuationToken, + .doOnRequest(ignoredValue -> logger.info("Retrieving the next listing page - Page {}", continuationToken)) + .doOnSuccess(response -> logger.info("Retrieved the next listing page - Page {}", continuationToken)) + .doOnError(error -> logger.warning("Failed to retrieve the next listing page - Page {}", continuationToken, error)); } private Mono> listFirstPageSettings(SettingSelector options, Context context) { if (options == null) { return service.listKeyValues(serviceEndpoint, null, null, null, null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Listing all ConfigurationSettings")) - .doOnSuccess(response -> logger.asInfo().log("Listed all ConfigurationSettings")) - .doOnError(error -> logger.asWarning().log("Failed to list all ConfigurationSetting", error)); + .doOnRequest(ignoredValue -> logger.info("Listing all ConfigurationSettings")) + .doOnSuccess(response -> logger.info("Listed all ConfigurationSettings")) + .doOnError(error -> logger.warning("Failed to list all ConfigurationSetting", error)); } String fields = ImplUtils.arrayToString(options.fields(), SettingFields::toStringMapper); @@ -658,9 +645,9 @@ private Mono> listFirstPageSettings(SettingS String labels = ImplUtils.arrayToString(options.labels(), label -> label); return service.listKeyValues(serviceEndpoint, keys, labels, fields, options.acceptDateTime(), context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Listing ConfigurationSettings - {}", options)) - .doOnSuccess(response -> logger.asInfo().log("Listed ConfigurationSettings - {}", options)) - .doOnError(error -> logger.asWarning().log("Failed to list ConfigurationSetting - {}", options, error)); + .doOnRequest(ignoredValue -> logger.info("Listing ConfigurationSettings - {}", options)) + .doOnSuccess(response -> logger.info("Listed ConfigurationSettings - {}", options)) + .doOnError(error -> logger.warning("Failed to list ConfigurationSetting - {}", options, error)); } @@ -718,14 +705,14 @@ Flux listSettingRevisions(SettingSelector selector, Contex String range = selector.range() != null ? String.format(RANGE_QUERY, selector.range()) : null; result = service.listKeyValueRevisions(serviceEndpoint, keys, labels, fields, selector.acceptDateTime(), range, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Listing ConfigurationSetting revisions - {}", selector)) - .doOnSuccess(response -> logger.asInfo().log("Listed ConfigurationSetting revisions - {}", selector)) - .doOnError(error -> logger.asWarning().log("Failed to list ConfigurationSetting revisions - {}", selector, error)); + .doOnRequest(ignoredValue -> logger.info("Listing ConfigurationSetting revisions - {}", selector)) + .doOnSuccess(response -> logger.info("Listed ConfigurationSetting revisions - {}", selector)) + .doOnError(error -> logger.warning("Failed to list ConfigurationSetting revisions - {}", selector, error)); } else { result = service.listKeyValueRevisions(serviceEndpoint, null, null, null, null, null, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Listing ConfigurationSetting revisions")) - .doOnSuccess(response -> logger.asInfo().log("Listed ConfigurationSetting revisions")) - .doOnError(error -> logger.asWarning().log("Failed to list all ConfigurationSetting revisions", error)); + .doOnRequest(ignoredValue -> logger.info("Listing ConfigurationSetting revisions")) + .doOnSuccess(response -> logger.info("Listed ConfigurationSetting revisions")) + .doOnError(error -> logger.warning("Failed to list all ConfigurationSetting revisions", error)); } return result.flatMapMany(r -> extractAndFetchConfigurationSettings(r, context)); @@ -742,9 +729,9 @@ Flux listSettingRevisions(SettingSelector selector, Contex */ private Flux listSettings(String nextPageLink, Context context) { Mono> result = service.listKeyValues(serviceEndpoint, nextPageLink, context) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving the next listing page - Page {}", nextPageLink)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved the next listing page - Page {}", nextPageLink)) - .doOnError(error -> logger.asWarning().log("Failed to retrieve the next listing page - Page {}", nextPageLink, error)); + .doOnRequest(ignoredValue -> logger.info("Retrieving the next listing page - Page {}", nextPageLink)) + .doOnSuccess(response -> logger.info("Retrieved the next listing page - Page {}", nextPageLink)) + .doOnError(error -> logger.warning("Failed to retrieve the next listing page - Page {}", nextPageLink, error)); return result.flatMapMany(r -> extractAndFetchConfigurationSettings(r, context)); } diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java similarity index 98% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java index a160a3e5007ed..51b2466e8ca51 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClient.java @@ -23,7 +23,7 @@ * *

Instantiating a synchronous Configuration Client

* - * {@codesnippet com.azure.applicationconfig.configurationclient.instantiation} + * {@codesnippet com.azure.data.applicationconfig.configurationclient.instantiation} * *

View {@link ConfigurationClientBuilder this} for additional ways to construct the client.

* @@ -44,15 +44,6 @@ public final class ConfigurationClient { this.client = client; } - /** - * Creates a builder that can configure options for the ConfigurationClient before creating an instance of it. - * - * @return A new {@link ConfigurationClientBuilder} to create a ConfigurationClient. - */ - public static ConfigurationClientBuilder builder() { - return new ConfigurationClientBuilder(); - } - /** * Adds a configuration value in the service if that key does not exist. * @@ -60,7 +51,7 @@ public static ConfigurationClientBuilder builder() { * *

Add a setting with the key "prodDBConnection" and value "db_connection".

* - * {@codesnippet com.azure.applicationconfig.configurationclient.addSetting#string-string} + * {@codesnippet com.azure.data.applicationconfig.configurationclient.addSetting#string-string} * * @param key The key of the configuration setting to add. * @param value The value associated with this configuration setting key. diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClientBuilder.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java similarity index 67% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClientBuilder.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java index c448915206003..8d4bd79e5d1ef 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationAsyncClientBuilder.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationClientBuilder.java @@ -32,37 +32,36 @@ import java.util.Objects; /** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link ConfigurationAsyncClient}, - * calling {@link ConfigurationAsyncClientBuilder#build() build} constructs an instance of the client. + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link ConfigurationAsyncClient} and {@link ConfigurationClient}, + * by calling {@link ConfigurationClientBuilder#buildAsyncClient() buildAsyncClient} and {@link ConfigurationClientBuilder#buildClient() buildClient} respectively + * to construct an instance of the desired client. * *

The client needs the service endpoint of the Azure App Configuration store and access credentials. * {@link ConfigurationClientCredentials} gives the builder the service endpoint and access credentials it requires to - * construct a client, set the ConfigurationClientCredentials with {@link ConfigurationAsyncClientBuilder#credentials(ConfigurationClientCredentials) this}.

+ * construct a client, set the ConfigurationClientCredentials with {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials) this}.

* - *
- * ConfigurationAsyncClient client = ConfigurationAsyncClient.builder()
- *     .credentials(new ConfigurationClientCredentials(connectionString))
- *     .build();
- * 
+ *

Instantiating an asynchronous Configuration Client

+ * + * {@codesnippet com.azure.data.applicationconfig.async.configurationclient.instantiation} + * + *

Instantiating a synchronous Configuration Client

+ * + * {@codesnippet com.azure.data.applicationconfig.configurationclient.instantiation} * *

Another way to construct the client is using a {@link HttpPipeline}. The pipeline gives the client an authenticated * way to communicate with the service but it doesn't contain the service endpoint. Set the pipeline with - * {@link ConfigurationAsyncClientBuilder#pipeline(HttpPipeline) this}, additionally set the service endpoint with - * {@link ConfigurationAsyncClientBuilder#serviceEndpoint(String) this}. Using a pipeline requires additional setup but - * allows for finer control on how the ConfigurationAsyncClient it built.

+ * {@link ConfigurationClientBuilder#pipeline(HttpPipeline) this}, additionally set the service endpoint with + * {@link ConfigurationClientBuilder#serviceEndpoint(String) this}. Using a pipeline requires additional setup but + * allows for finer control on how the {@link ConfigurationAsyncClient} and {@link ConfigurationClient} it built.

* - *
- * ConfigurationAsyncClient.builder()
- *     .pipeline(new HttpPipeline(policies))
- *     .serviceEndpoint(serviceEndpoint)
- *     .build();
- * 
+ * {@codesnippet com.azure.data.applicationconfig.configurationclient.pipeline.instantiation} * * @see ConfigurationAsyncClient + * @see ConfigurationClient * @see ConfigurationClientCredentials */ -@ServiceClientBuilder(serviceClients = ConfigurationAsyncClient.class) -public final class ConfigurationAsyncClientBuilder { +@ServiceClientBuilder(serviceClients = ConfigurationClient.class) +public final class ConfigurationClientBuilder { // This header tells the server to return the request id in the HTTP response. Useful for correlation with what // request was sent. private static final String ECHO_REQUEST_ID_HEADER = "x-ms-return-client-request-id"; @@ -82,7 +81,10 @@ public final class ConfigurationAsyncClientBuilder { private RetryPolicy retryPolicy; private Configuration configuration; - ConfigurationAsyncClientBuilder() { + /** + * The constructor with defaults. + */ + public ConfigurationClientBuilder() { retryPolicy = new RetryPolicy(); httpLogDetailLevel = HttpLogDetailLevel.NONE; policies = new ArrayList<>(); @@ -92,25 +94,44 @@ public final class ConfigurationAsyncClientBuilder { .put(CONTENT_TYPE_HEADER, CONTENT_TYPE_HEADER_VALUE) .put(ACCEPT_HEADER, ACCEPT_HEADER_VALUE); } + /** + * Creates a {@link ConfigurationClient} based on options set in the Builder. Every time {@code buildClient()} is + * called, a new instance of {@link ConfigurationClient} is created. + * + *

+ * If {@link ConfigurationClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} are used to create the + * {@link ConfigurationClient client}. All other builder settings are ignored.

+ * + * @return A ConfigurationClient with the options set from the builder. + * @throws NullPointerException If {@code serviceEndpoint} has not been set. This setting is automatically set when + * {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials) credentials} are set through + * the builder. Or can be set explicitly by calling {@link ConfigurationClientBuilder#serviceEndpoint(String)}. + * @throws IllegalStateException If {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials)} + * has not been set. + */ + public ConfigurationClient buildClient() { + return new ConfigurationClient(buildAsyncClient()); + } /** - * Creates a {@link ConfigurationAsyncClient} based on options set in the Builder. Every time {@code build()} is + * Creates a {@link ConfigurationAsyncClient} based on options set in the Builder. Every time {@code buildAsyncClient()} is * called, a new instance of {@link ConfigurationAsyncClient} is created. * *

- * If {@link ConfigurationAsyncClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link ConfigurationAsyncClientBuilder#serviceEndpoint(String) serviceEndpoint} are used to create the + * If {@link ConfigurationClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} are used to create the * {@link ConfigurationAsyncClient client}. All other builder settings are ignored. *

* * @return A ConfigurationAsyncClient with the options set from the builder. * @throws NullPointerException If {@code serviceEndpoint} has not been set. This setting is automatically set when - * {@link ConfigurationAsyncClientBuilder#credentials(ConfigurationClientCredentials) credentials} are set through - * the builder. Or can be set explicitly by calling {@link ConfigurationAsyncClientBuilder#serviceEndpoint(String)}. - * @throws IllegalStateException If {@link ConfigurationAsyncClientBuilder#credentials(ConfigurationClientCredentials)} + * {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials) credentials} are set through + * the builder. Or can be set explicitly by calling {@link ConfigurationClientBuilder#serviceEndpoint(String)}. + * @throws IllegalStateException If {@link ConfigurationClientBuilder#credentials(ConfigurationClientCredentials)} * has not been set. */ - public ConfigurationAsyncClient build() { + public ConfigurationAsyncClient buildAsyncClient() { Configuration buildConfiguration = (configuration == null) ? ConfigurationManager.getConfiguration().clone() : configuration; ConfigurationClientCredentials configurationCredentials = getConfigurationCredentials(buildConfiguration); URL buildServiceEndpoint = getBuildServiceEndpoint(configurationCredentials); @@ -155,23 +176,23 @@ public ConfigurationAsyncClient build() { * * @param serviceEndpoint The URL of the Azure App Configuration instance to send {@link ConfigurationSetting} * service requests to and receive responses from. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. * @throws MalformedURLException if {@code serviceEndpoint} is null or it cannot be parsed into a valid URL. */ - public ConfigurationAsyncClientBuilder serviceEndpoint(String serviceEndpoint) throws MalformedURLException { + public ConfigurationClientBuilder serviceEndpoint(String serviceEndpoint) throws MalformedURLException { this.serviceEndpoint = new URL(serviceEndpoint); return this; } /** * Sets the credentials to use when authenticating HTTP requests. Also, sets the - * {@link ConfigurationAsyncClientBuilder#serviceEndpoint(String) serviceEndpoint} for this ConfigurationAsyncClientBuilder. + * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} for this ConfigurationClientBuilder. * * @param credentials The credentials to use for authenticating HTTP requests. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. * @throws NullPointerException If {@code credentials} is {@code null}. */ - public ConfigurationAsyncClientBuilder credentials(ConfigurationClientCredentials credentials) { + public ConfigurationClientBuilder credentials(ConfigurationClientCredentials credentials) { Objects.requireNonNull(credentials); this.credentials = credentials; this.serviceEndpoint = credentials.baseUri(); @@ -182,22 +203,21 @@ public ConfigurationAsyncClientBuilder credentials(ConfigurationClientCredential * Sets the logging level for HTTP requests and responses. * * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. */ - public ConfigurationAsyncClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + public ConfigurationClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { httpLogDetailLevel = logLevel; return this; } /** - * Adds a policy to the set of existing policies that are executed after - * {@link ConfigurationAsyncClient} required policies. + * Adds a policy to the set of existing policies that are executed after required policies. * * @param policy The retry policy for service requests. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. * @throws NullPointerException If {@code policy} is {@code null}. */ - public ConfigurationAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { + public ConfigurationClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy); policies.add(policy); return this; @@ -207,10 +227,10 @@ public ConfigurationAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { * Sets the HTTP client to use for sending and receiving requests to and from the service. * * @param client The HTTP client to use for requests. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. * @throws NullPointerException If {@code client} is {@code null}. */ - public ConfigurationAsyncClientBuilder httpClient(HttpClient client) { + public ConfigurationClientBuilder httpClient(HttpClient client) { Objects.requireNonNull(client); this.httpClient = client; return this; @@ -220,12 +240,12 @@ public ConfigurationAsyncClientBuilder httpClient(HttpClient client) { * Sets the HTTP pipeline to use for the service client. * * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link ConfigurationAsyncClientBuilder#serviceEndpoint(String) serviceEndpoint} to build {@link ConfigurationAsyncClient}. + * {@link ConfigurationClientBuilder#serviceEndpoint(String) serviceEndpoint} to build {@link ConfigurationAsyncClient} or {@link ConfigurationClient}. * * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. */ - public ConfigurationAsyncClientBuilder pipeline(HttpPipeline pipeline) { + public ConfigurationClientBuilder pipeline(HttpPipeline pipeline) { Objects.requireNonNull(pipeline); this.pipeline = pipeline; return this; @@ -238,9 +258,9 @@ public ConfigurationAsyncClientBuilder pipeline(HttpPipeline pipeline) { * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. * * @param configuration The configuration store used to - * @return The updated ConfigurationAsyncClientBuilder object. + * @return The updated ConfigurationClientBuilder object. */ - public ConfigurationAsyncClientBuilder configuration(Configuration configuration) { + public ConfigurationClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; } diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationService.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationService.java similarity index 100% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/ConfigurationService.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/ConfigurationService.java diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java similarity index 96% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java index d2ddeb20db81b..5759ee76e2f71 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/ConfigurationClientCredentials.java @@ -2,7 +2,7 @@ // Licensed under the MIT License. package com.azure.data.appconfiguration.credentials; -import com.azure.data.appconfiguration.ConfigurationAsyncClientBuilder; +import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.data.appconfiguration.policy.ConfigurationCredentialsPolicy; import com.azure.core.implementation.util.ImplUtils; import io.netty.buffer.ByteBuf; @@ -29,12 +29,12 @@ import java.util.stream.Collectors; /** - * Credentials that authorizes requests to Azure Application Configuration. It uses content within the HTTP request to + * Credentials that authorizes requests to Azure App Configuration. It uses content within the HTTP request to * generate the correct "Authorization" header value. {@link ConfigurationCredentialsPolicy} ensures that the content * exists in the HTTP request so that a valid authorization value is generated. * * @see ConfigurationCredentialsPolicy - * @see ConfigurationAsyncClientBuilder + * @see ConfigurationClientBuilder */ public class ConfigurationClientCredentials { private static final String HOST_HEADER = "Host"; @@ -47,7 +47,7 @@ public class ConfigurationClientCredentials { private final AuthorizationHeaderProvider headerProvider; /** - * Creates an instance that is able to authorize requests to Azure Application Configuration service. + * Creates an instance that is able to authorize requests to Azure App Configuration service. * * @param connectionString Connection string in the format "endpoint={endpoint_value};id={id_value};secret={secret_value}" * @throws NoSuchAlgorithmException When the HMAC-SHA256 MAC algorithm cannot be instantiated. diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java similarity index 87% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java index 2bb81ada22b23..0e1949b58f4f0 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/credentials/package-info.java @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. /** - * Package containing classes used to authenticate with Azure Application Configuration service. + * Package containing classes used to authenticate with Azure App Configuration service. */ package com.azure.data.appconfiguration.credentials; diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/implementation/ConfigurationSettingPage.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/implementation/ConfigurationSettingPage.java similarity index 100% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/implementation/ConfigurationSettingPage.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/implementation/ConfigurationSettingPage.java diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java similarity index 84% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java index 986a8a5b60326..1c204d2ce1c38 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/implementation/package-info.java @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. /** - * Package containing implementation classes for communicating with Azure Application Configuration service. + * Package containing implementation classes for communicating with Azure App Configuration service. * Should not be used. */ package com.azure.data.appconfiguration.implementation; diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java similarity index 99% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java index d97d8a0c117be..24bf8709e7e9f 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/ConfigurationSetting.java @@ -168,7 +168,7 @@ public OffsetDateTime lastModified() { * Gets whether or not the configuration setting is locked. If the setting is locked, then no modifications can be * made to this setting. * - * This is a readonly property. It is populated from responses from the Azure Application Configuration + * This is a readonly property. It is populated from responses from the Azure App Configuration * service. * * @return true if locked; false otherwise. diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/Range.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/Range.java similarity index 97% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/Range.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/Range.java index fe0b67bb17645..93a166235d416 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/Range.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/Range.java @@ -8,7 +8,7 @@ /** * A configuration for selecting a range of revisions when retrieving configuration setting revisions from the - * Application Configuration service. + * App Configuration service. * * @see ConfigurationAsyncClient#listSettingRevisions(SettingSelector) * @see ConfigurationClient#listSettingRevisions(SettingSelector) diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/SettingFields.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/SettingFields.java similarity index 100% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/SettingFields.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/SettingFields.java diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java similarity index 99% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java index 95de7d24bc970..90856854f1aa4 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/SettingSelector.java @@ -10,7 +10,7 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; /** - * A set of options for selecting configuration settings from Application Configuration service. + * A set of options for selecting configuration settings from App Configuration service. * *
    *
  • diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/package-info.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/package-info.java similarity index 100% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/models/package-info.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/models/package-info.java diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/package-info.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/package-info.java similarity index 79% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/package-info.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/package-info.java index e9a6f1efe1f71..569ebf78d8c50 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/package-info.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/package-info.java @@ -2,6 +2,6 @@ // Licensed under the MIT License. /** * Package containing classes for creating a {@link com.azure.data.appconfiguration.ConfigurationAsyncClient} to - * perform operations on Azure Application Configuration service. + * perform operations on Azure App Configuration service. */ package com.azure.data.appconfiguration; diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java similarity index 90% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java index ea4490d2d2935..7d32848c20419 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/ConfigurationCredentialsPolicy.java @@ -3,7 +3,7 @@ package com.azure.data.appconfiguration.policy; import com.azure.data.appconfiguration.ConfigurationAsyncClient; -import com.azure.data.appconfiguration.ConfigurationAsyncClientBuilder; +import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; import com.azure.core.http.HttpPipelineCallContext; import com.azure.core.http.HttpPipelineNextPolicy; @@ -16,12 +16,12 @@ import reactor.core.publisher.Mono; /** - * A policy that authenticates requests with Azure Application Configuration service. The content added by this policy + * A policy that authenticates requests with Azure App Configuration service. The content added by this policy * is leveraged in {@link ConfigurationClientCredentials} to generate the correct "Authorization" header value. * * @see ConfigurationClientCredentials * @see ConfigurationAsyncClient - * @see ConfigurationAsyncClientBuilder + * @see ConfigurationClientBuilder */ public final class ConfigurationCredentialsPolicy implements HttpPipelinePolicy { // "Host", "Date", and "x-ms-content-sha256" are required to generate "Authorization" value in @@ -39,7 +39,7 @@ public ConfigurationCredentialsPolicy(ConfigurationClientCredentials credentials } /** - * Adds the required headers to authenticate a request to Azure Application Configuration service. + * Adds the required headers to authenticate a request to Azure App Configuration service. * * @param context The request context * @param next The next HTTP pipeline policy to process the {@code context's} request after this policy completes. diff --git a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/package-info.java b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/package-info.java similarity index 65% rename from appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/package-info.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/package-info.java index 74a7157d5eb5d..06b43f06f03d8 100644 --- a/appconfiguration/client/src/main/java/com/azure/data/appconfiguration/policy/package-info.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/main/java/com/azure/data/appconfiguration/policy/package-info.java @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. /** - * Package containing policies used by Azure Application Configuration service. + * Package containing policies used by Azure App Configuration service. */ package com.azure.data.appconfiguration.policy; diff --git a/appconfiguration/client/src/samples/java/ConfigurationSets.java b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/ConfigurationSets.java similarity index 95% rename from appconfiguration/client/src/samples/java/ConfigurationSets.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/ConfigurationSets.java index 5c379b17c7646..a818c8da36ebc 100644 --- a/appconfiguration/client/src/samples/java/ConfigurationSets.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/ConfigurationSets.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. import com.azure.data.appconfiguration.ConfigurationAsyncClient; +import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; import com.azure.data.appconfiguration.models.ConfigurationSetting; import com.azure.data.appconfiguration.models.SettingSelector; @@ -16,7 +17,7 @@ import java.security.NoSuchAlgorithmException; /** - * Sample demonstrates how to use Azure Application Configuration to switch between "beta" and "production" + * Sample demonstrates how to use Azure App Configuration to switch between "beta" and "production" * configuration sets. * *

    @@ -50,9 +51,9 @@ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidK String connectionString = "endpoint={endpoint_value};id={id_value};name={secret_value}"; // Instantiate a configuration client that will be used to call the configuration service. - ConfigurationAsyncClient client = ConfigurationAsyncClient.builder() + ConfigurationAsyncClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildAsyncClient(); // Demonstrates two different complex objects being stored in Azure App Configuration; one used for beta and the // other used for production. diff --git a/appconfiguration/client/src/samples/java/HelloWorld.java b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/HelloWorld.java similarity index 90% rename from appconfiguration/client/src/samples/java/HelloWorld.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/HelloWorld.java index 784a38a2b784f..15bc35ba8531b 100644 --- a/appconfiguration/client/src/samples/java/HelloWorld.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/HelloWorld.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. import com.azure.data.appconfiguration.ConfigurationAsyncClient; +import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; import com.azure.data.appconfiguration.models.ConfigurationSetting; @@ -26,14 +27,14 @@ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidK String connectionString = "endpoint={endpoint_value};id={id_value};name={secret_value}"; // Instantiate a client that will be used to call the service. - ConfigurationAsyncClient client = ConfigurationAsyncClient.builder() + ConfigurationAsyncClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) - .build(); + .buildAsyncClient(); // Name of the key to add to the configuration service. String key = "hello"; - // setSetting adds or updates a setting to Azure Application Configuration store. Alternatively, you can call + // setSetting adds or updates a setting to Azure App Configuration store. Alternatively, you can call // addSetting which only succeeds if the setting does not exist in the store. Or, you can call updateSetting to // update a setting that is already present in the store. // We subscribe and wait for the service call to complete then print out the contents of our newly added setting. diff --git a/appconfiguration/client/src/samples/java/PipelineSample.java b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/PipelineSample.java similarity index 96% rename from appconfiguration/client/src/samples/java/PipelineSample.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/PipelineSample.java index f10ca03aa48a5..dc876f7f4c42b 100644 --- a/appconfiguration/client/src/samples/java/PipelineSample.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/PipelineSample.java @@ -2,6 +2,7 @@ // Licensed under the MIT License. import com.azure.data.appconfiguration.ConfigurationAsyncClient; +import com.azure.data.appconfiguration.ConfigurationClientBuilder; import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; import com.azure.data.appconfiguration.models.ConfigurationSetting; import com.azure.data.appconfiguration.models.SettingSelector; @@ -42,11 +43,11 @@ public static void main(String[] args) throws NoSuchAlgorithmException, Invalid // Instantiate a client that will be used to call the service. // We add in a policy to track the type of HTTP method calls we make. // We also want to see the Header information of our HTTP requests, so we specify the detail level. - final ConfigurationAsyncClient client = ConfigurationAsyncClient.builder() + final ConfigurationAsyncClient client = new ConfigurationClientBuilder() .credentials(new ConfigurationClientCredentials(connectionString)) .addPolicy(new HttpMethodRequestTrackingPolicy(tracker)) .httpLogDetailLevel(HttpLogDetailLevel.HEADERS) - .build(); + .buildAsyncClient(); // Adding a couple of settings and then fetching all the settings in our repository. final List settings = Flux.concat(client.addSetting(new ConfigurationSetting().key("hello").value("world")), diff --git a/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..72bd7346b3e1c --- /dev/null +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/com/azure/data/appconfiguration/ConfigurationClientJavaDocCodeSnippets.java @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.data.appconfiguration; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.test.models.RecordedData; +import com.azure.core.test.policy.RecordNetworkCallPolicy; +import com.azure.data.appconfiguration.credentials.ConfigurationClientCredentials; +import com.azure.data.appconfiguration.models.ConfigurationSetting; + +import java.net.MalformedURLException; +import java.security.GeneralSecurityException; + +/** + * This class contains code samples for generating javadocs through doclets for {@link ConfigurationClient} + */ +public final class ConfigurationClientJavaDocCodeSnippets { + + /** + * Generates code sample for creating a {@link ConfigurationClient} + * @return An instance of {@link ConfigurationClient} + * @throws IllegalStateException If configuration credentials cannot be created. + * @throws MalformedURLException if service end point is malformed. + */ + public ConfigurationClient createAsyncConfigurationClientWithPipeline() throws MalformedURLException { + try { + String connectionString = getConnectionString(); + // BEGIN: com.azure.data.applicationconfig.configurationclient.pipeline.instantiation + RecordedData networkData = new RecordedData(); + HttpPipeline pipeline = HttpPipeline.builder().policies(new RecordNetworkCallPolicy(networkData)).build(); + + ConfigurationClient configurationClient = new ConfigurationClientBuilder() + .pipeline(pipeline) + .serviceEndpoint("https://myconfig.azure.net/") + .credentials(new ConfigurationClientCredentials(connectionString)) + .buildClient(); + // END: com.azure.data.applicationconfig.configurationclient.pipeline.instantiation + return configurationClient; + } catch (GeneralSecurityException ex) { + throw new IllegalStateException("Failed to create configuration client credentials", ex); + } + } + + /** + * Generates code sample for creating a {@link ConfigurationClient} + * @return An instance of {@link ConfigurationClient} + * @throws IllegalStateException If configuration credentials cannot be created + */ + public ConfigurationAsyncClient createAsyncConfigurationClient() { + try { + String connectionString = getConnectionString(); + // BEGIN: com.azure.data.applicationconfig.async.configurationclient.instantiation + ConfigurationAsyncClient configurationAsyncClient = new ConfigurationClientBuilder() + .credentials(new ConfigurationClientCredentials(connectionString)) + .buildAsyncClient(); + // END: com.azure.data.applicationconfig.async.configurationclient.instantiation + return configurationAsyncClient; + } catch (GeneralSecurityException ex) { + throw new IllegalStateException("Failed to create configuration client credentials", ex); + } + } + + /** + * Generates code sample for creating a {@link ConfigurationClient} + * @return An instance of {@link ConfigurationClient} + * @throws IllegalStateException If configuration credentials cannot be created + */ + public ConfigurationClient createSyncConfigurationClient() { + try { + String connectionString = getConnectionString(); + // BEGIN: com.azure.data.applicationconfig.configurationclient.instantiation + ConfigurationClient configurationClient = new ConfigurationClientBuilder() + .credentials(new ConfigurationClientCredentials(connectionString)) + .buildClient(); + // END: com.azure.data.applicationconfig.configurationclient.instantiation + return configurationClient; + } catch (GeneralSecurityException ex) { + throw new IllegalStateException("Failed to create configuration client credentials", ex); + } + } + + /** + * Generates code sample for using {@link ConfigurationClient#addSetting(String, String)} + */ + public void addSetting() { + ConfigurationClient configurationClient = createSyncConfigurationClient(); + // BEGIN: com.azure.data.applicationconfig.configurationclient.addSetting#string-string + ConfigurationSetting configurationSetting = configurationClient + .addSetting("prodDBConnection", "db_connection").value(); + System.out.printf("Key: %s, Value: %s %n", configurationSetting.key(), configurationSetting.value()); + // END: com.azure.data.applicationconfig.configurationclient.addSetting#string-string + } + + /** + * Implementation not provided for this method + * @return {@code null} + */ + private String getConnectionString() { + return null; + } +} diff --git a/appconfiguration/client/src/samples/java/com/azure/models/ComplexConfiguration.java b/sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/com/azure/models/ComplexConfiguration.java similarity index 100% rename from appconfiguration/client/src/samples/java/com/azure/models/ComplexConfiguration.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/samples/java/com/azure/models/ComplexConfiguration.java diff --git a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java similarity index 98% rename from appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java index e795e486879ae..32f2e059d4c9c 100644 --- a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationAsyncClientTest.java @@ -35,33 +35,33 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> ConfigurationAsyncClient.builder() + client = clientSetup(credentials -> new ConfigurationClientBuilder() .credentials(credentials) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildAsyncClient()); } else { - client = clientSetup(credentials -> ConfigurationAsyncClient.builder() + client = clientSetup(credentials -> new ConfigurationClientBuilder() .credentials(credentials) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildAsyncClient()); } } @Override protected void afterTest() { - logger.asInfo().log("Cleaning up created key values."); + logger.info("Cleaning up created key values."); client.listSettings(new SettingSelector().keys(keyPrefix + "*")) .flatMap(configurationSetting -> { - logger.asInfo().log("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); + logger.info("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); return client.deleteSetting(configurationSetting); }) .blockLast(); - logger.asInfo().log("Finished cleaning up values."); + logger.info("Finished cleaning up values."); } /** @@ -762,7 +762,7 @@ public void getSettingWhenValueNotUpdated() { public void deleteAllSettings() { client.listSettings(new SettingSelector().keys("*")) .flatMap(configurationSetting -> { - logger.asInfo().log("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); + logger.info("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); return client.deleteSetting(configurationSetting); }).blockLast(); } diff --git a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java similarity index 97% rename from appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java index f6b8933ae76be..49c08b0ba9869 100644 --- a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTest.java @@ -30,32 +30,32 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> ConfigurationClient.builder() + client = clientSetup(credentials -> new ConfigurationClientBuilder() .credentials(credentials) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildClient()); } else { - client = clientSetup(credentials -> ConfigurationClient.builder() + client = clientSetup(credentials -> new ConfigurationClientBuilder() .credentials(credentials) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildClient()); } } @Override protected void afterTest() { - logger.asInfo().log("Cleaning up created key values."); + logger.info("Cleaning up created key values."); for (ConfigurationSetting configurationSetting : client.listSettings(new SettingSelector().keys(keyPrefix + "*"))) { - logger.asInfo().log("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); + logger.info("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); client.deleteSetting(configurationSetting); } - logger.asInfo().log("Finished cleaning up values."); + logger.info("Finished cleaning up values."); } /** @@ -557,7 +557,7 @@ public void getSettingWhenValueNotUpdated() { public void deleteAllSettings() { for (ConfigurationSetting configurationSetting : client.listSettings(new SettingSelector().keys("*"))) { - logger.asInfo().log("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); + logger.info("Deleting key:label [{}:{}]. isLocked? {}", configurationSetting.key(), configurationSetting.label(), configurationSetting.isLocked()); client.deleteSetting(configurationSetting); } } diff --git a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java similarity index 99% rename from appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java index 6c1bb06a39088..78111b48aebfe 100644 --- a/appconfiguration/client/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java +++ b/sdk/appconfiguration/azure-data-appconfiguration/src/test/java/com/azure/data/appconfiguration/ConfigurationClientTestBase.java @@ -79,7 +79,7 @@ T clientSetup(Function clientBuilder) { try { client = clientBuilder.apply(new ConfigurationClientCredentials(connectionString)); } catch (InvalidKeyException | NoSuchAlgorithmException e) { - logger.asError().log("Could not create an configuration client credentials.", e); + logger.error("Could not create an configuration client credentials.", e); fail(); client = null; } diff --git a/appconfiguration/client/src/test/resources/session-records/addExistingSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addExistingSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/addExistingSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addExistingSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/addSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/addSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/addSettingEmptyKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingEmptyKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/addSettingEmptyKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingEmptyKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/addSettingEmptyValue.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingEmptyValue.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/addSettingEmptyValue.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingEmptyValue.json diff --git a/appconfiguration/client/src/test/resources/session-records/addSettingNullKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingNullKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/addSettingNullKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/addSettingNullKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/deleteSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/deleteSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/deleteSettingNotFound.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingNotFound.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/deleteSettingNotFound.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingNotFound.json diff --git a/appconfiguration/client/src/test/resources/session-records/deleteSettingNullKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingNullKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/deleteSettingNullKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingNullKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/deleteSettingWithETag.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingWithETag.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/deleteSettingWithETag.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/deleteSettingWithETag.json diff --git a/appconfiguration/client/src/test/resources/session-records/getSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/getSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/getSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/getSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/getSettingNotFound.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/getSettingNotFound.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/getSettingNotFound.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/getSettingNotFound.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisions.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisions.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisions.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisions.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsAcceptDateTime.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsAcceptDateTime.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsAcceptDateTime.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsAcceptDateTime.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsInvalidRange.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsInvalidRange.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsInvalidRange.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsInvalidRange.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsWithMultipleKeys.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithMultipleKeys.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsWithMultipleKeys.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithMultipleKeys.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsWithMultipleLabels.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithMultipleLabels.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsWithMultipleLabels.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithMultipleLabels.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsWithPagination.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithPagination.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsWithPagination.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithPagination.json diff --git a/appconfiguration/client/src/test/resources/session-records/listRevisionsWithRange.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithRange.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listRevisionsWithRange.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listRevisionsWithRange.json diff --git a/appconfiguration/client/src/test/resources/session-records/listSettingsAcceptDateTime.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsAcceptDateTime.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listSettingsAcceptDateTime.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsAcceptDateTime.json diff --git a/appconfiguration/client/src/test/resources/session-records/listSettingsSelectFields.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsSelectFields.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listSettingsSelectFields.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsSelectFields.json diff --git a/appconfiguration/client/src/test/resources/session-records/listSettingsWithPagination.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsWithPagination.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listSettingsWithPagination.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listSettingsWithPagination.json diff --git a/appconfiguration/client/src/test/resources/session-records/listWithKeyAndLabel.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithKeyAndLabel.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listWithKeyAndLabel.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithKeyAndLabel.json diff --git a/appconfiguration/client/src/test/resources/session-records/listWithMultipleKeys.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithMultipleKeys.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listWithMultipleKeys.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithMultipleKeys.json diff --git a/appconfiguration/client/src/test/resources/session-records/listWithMultipleLabels.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithMultipleLabels.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/listWithMultipleLabels.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/listWithMultipleLabels.json diff --git a/appconfiguration/client/src/test/resources/session-records/setSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/setSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/setSettingEmptyKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingEmptyKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/setSettingEmptyKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingEmptyKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/setSettingEmptyValue.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingEmptyValue.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/setSettingEmptyValue.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingEmptyValue.json diff --git a/appconfiguration/client/src/test/resources/session-records/setSettingIfEtag.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingIfEtag.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/setSettingIfEtag.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingIfEtag.json diff --git a/appconfiguration/client/src/test/resources/session-records/setSettingNullKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingNullKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/setSettingNullKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/setSettingNullKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/updateNoExistingSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateNoExistingSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/updateNoExistingSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateNoExistingSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/updateSetting.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSetting.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/updateSetting.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSetting.json diff --git a/appconfiguration/client/src/test/resources/session-records/updateSettingIfEtag.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingIfEtag.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/updateSettingIfEtag.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingIfEtag.json diff --git a/appconfiguration/client/src/test/resources/session-records/updateSettingNullKey.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingNullKey.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/updateSettingNullKey.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingNullKey.json diff --git a/appconfiguration/client/src/test/resources/session-records/updateSettingOverload.json b/sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingOverload.json similarity index 100% rename from appconfiguration/client/src/test/resources/session-records/updateSettingOverload.json rename to sdk/appconfiguration/azure-data-appconfiguration/src/test/resources/session-records/updateSettingOverload.json diff --git a/sdk/appconfiguration/ci.yml b/sdk/appconfiguration/ci.yml new file mode 100644 index 0000000000000..d4b965f3ea0bb --- /dev/null +++ b/sdk/appconfiguration/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/appconfiguration/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/appconfiguration/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: appconfiguration diff --git a/sdk/appconfiguration/pom.service.xml b/sdk/appconfiguration/pom.service.xml new file mode 100644 index 0000000000000..e33082c71b929 --- /dev/null +++ b/sdk/appconfiguration/pom.service.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + com.azure + azure-appconfiguration-service + pom + 1.0.0 + + azure-data-appconfiguration + ../../core + + diff --git a/sdk/appconfiguration/tests.yml b/sdk/appconfiguration/tests.yml new file mode 100644 index 0000000000000..53d1bd0ccd1fa --- /dev/null +++ b/sdk/appconfiguration/tests.yml @@ -0,0 +1,8 @@ +trigger: none + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-tests.yml + parameters: + ServiceDirectory: appconfiguration + EnvVars: + AZCONFIG_CONNECTION_STRING: $(java-azconfig-test-connection-string) diff --git a/sdk/authorization/ci.yml b/sdk/authorization/ci.yml new file mode 100644 index 0000000000000..3ca739a2628b0 --- /dev/null +++ b/sdk/authorization/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/authorization/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/authorization/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: authorization \ No newline at end of file diff --git a/authorization/msi-auth-token-provider-jar/pom.xml b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/pom.xml similarity index 100% rename from authorization/msi-auth-token-provider-jar/pom.xml rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/pom.xml diff --git a/authorization/msi-auth-token-provider-jar/readme.md b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/readme.md similarity index 100% rename from authorization/msi-auth-token-provider-jar/readme.md rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/readme.md diff --git a/authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/AzureMSICredentialException.java b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/AzureMSICredentialException.java similarity index 100% rename from authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/AzureMSICredentialException.java rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/AzureMSICredentialException.java diff --git a/authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForAppService.java b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForAppService.java similarity index 100% rename from authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForAppService.java rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForAppService.java diff --git a/authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForVirtualMachine.java b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForVirtualMachine.java similarity index 100% rename from authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForVirtualMachine.java rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIConfigurationForVirtualMachine.java diff --git a/authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSICredentials.java b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSICredentials.java similarity index 100% rename from authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSICredentials.java rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSICredentials.java diff --git a/authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIToken.java b/sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIToken.java similarity index 100% rename from authorization/msi-auth-token-provider-jar/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIToken.java rename to sdk/authorization/microsoft-azure-authentication-msi-token-provider/src/main/java/com/microsoft/azure/msiAuthTokenProvider/MSIToken.java diff --git a/sdk/authorization/pom.service.xml b/sdk/authorization/pom.service.xml new file mode 100644 index 0000000000000..bd6a9b28d5fe6 --- /dev/null +++ b/sdk/authorization/pom.service.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.azure + azure-authorization-service + pom + 1.0.0 + + microsoft-azure-authentication-msi-token-provider + + diff --git a/sdk/batch/microsoft-azure-batch/pom.xml b/sdk/batch/microsoft-azure-batch/pom.xml index 3bf92495e4fdc..43795fd55d08d 100644 --- a/sdk/batch/microsoft-azure-batch/pom.xml +++ b/sdk/batch/microsoft-azure-batch/pom.xml @@ -9,7 +9,7 @@ com.azure azure-data-sdk-parent - 1.0.0 + 1.1.0 ../../../pom.data.xml diff --git a/sdk/cosmos/CODEOWNERS b/sdk/cosmos/CODEOWNERS new file mode 100644 index 0000000000000..26da20e9f2cf2 --- /dev/null +++ b/sdk/cosmos/CODEOWNERS @@ -0,0 +1,10 @@ +# CODEOWNERS is a GitHub standard to specify who is automatically assigned pull requests to review. +# This helps to prevent pull requests from languishing without review. +# GitHub can also be configured to require review from code owners before a pull request can be merged. + +# Further reading is available from the following two URLs: +# https://blog.github.com/2017-07-06-introducing-code-owners/ +# https://help.github.com/articles/about-codeowners/ + +# Default owner for repo +* @moderakh @christopheranderson @kushagraThapar diff --git a/keyvault/data-plane/LICENSE b/sdk/cosmos/LICENSE similarity index 100% rename from keyvault/data-plane/LICENSE rename to sdk/cosmos/LICENSE diff --git a/sdk/cosmos/README.md b/sdk/cosmos/README.md new file mode 100644 index 0000000000000..b6ec762cc2cd3 --- /dev/null +++ b/sdk/cosmos/README.md @@ -0,0 +1,323 @@ +# Java SDK for SQL API of Azure Cosmos DB + +[![Maven Central](https://img.shields.io/maven-central/v/com.microsoft.azure/azure-cosmosdb.svg)](https://search.maven.org/artifact/com.microsoft.azure/azure-cosmosdb/2.4.3/jar) +[![Build Status](https://api.travis-ci.org/Azure/azure-cosmosdb-java.svg?branch=master)](https://travis-ci.org/Azure/azure-cosmosdb-java) +[![Known Vulnerabilities](https://snyk.io/test/github/Azure/azure-cosmosdb-java/badge.svg?targetFile=sdk%2Fpom.xml)](https://snyk.io/test/github/Azure/azure-cosmosdb-java?targetFile=sdk%2Fpom.xml) + + + + + +- [Consuming the official Microsoft Azure Cosmos DB Java SDK](#consuming-the-official-microsoft-azure-cosmos-db-java-sdk) +- [Prerequisites](#prerequisites) +- [API Documentation](#api-documentation) +- [Usage Code Sample](#usage-code-sample) +- [Guide for Prod](#guide-for-prod) +- [Future, CompletableFuture, and ListenableFuture](#future-completablefuture-and-listenablefuture) +- [Checking out the Source Code](#checking-out-the-source-code) +- [FAQ](#faq) +- [Release changes](#release-changes) +- [Contribution and Feedback](#contribution-and-feedback) +- [License](#license) + + + +## Consuming the official Microsoft Azure Cosmos DB Java SDK + +This project provides a SDK library in Java for interacting with [SQL API](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query) of [Azure Cosmos DB +Database Service](https://azure.microsoft.com/en-us/services/cosmos-db/). This project also includes samples, tools, and utilities. + +Jar dependency binary information for maven and gradle can be found here at [maven](https://mvnrepository.com/artifact/com.microsoft.azure/azure-cosmosdb/2.4.3). + +For example, using maven, you can add the following dependency to your maven pom file: + +```xml + + com.microsoft.azure + azure-cosmosdb + 2.4.3 + +``` + +Useful links: + +- [Sample Get Started APP](https://github.com/Azure-Samples/azure-cosmos-db-sql-api-async-java-getting-started) +- [Introduction to Resource Model of Azure Cosmos DB Service](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-resources) +- [Introduction to SQL API of Azure Cosmos DB Service](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-sql-query) +- [SDK JavaDoc API](https://azure.github.io/azure-cosmosdb-java/2.4.0/com/microsoft/azure/cosmosdb/rx/AsyncDocumentClient.html) +- [RxJava Observable JavaDoc API](http://reactivex.io/RxJava/1.x/javadoc/rx/Observable.html) +- [SDK FAQ](faq/) + +## Prerequisites + +- Java Development Kit 8 +- An active Azure account. If you don't have one, you can sign up for a [free account](https://azure.microsoft.com/free/). Alternatively, you can use the [Azure Cosmos DB Emulator](https://azure.microsoft.com/documentation/articles/documentdb-nosql-local-emulator) for development and testing. As emulator https certificate is self signed, you need to import its certificate to java trusted cert store as [explained here](https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator-export-ssl-certificates) +- (Optional) SLF4J is a logging facade. +- (Optional) [SLF4J binding](http://www.slf4j.org/manual.html) is used to associate a specific logging framework with SLF4J. +- (Optional) Maven + +SLF4J is only needed if you plan to use logging, please also download an SLF4J binding which will link the SLF4J API with the logging implementation of your choice. See the [SLF4J user manual](http://www.slf4j.org/manual.html) for more information. + +## API Documentation + +Javadoc is available [here](https://azure.github.io/azure-cosmosdb-java/2.4.0/com/microsoft/azure/cosmosdb/rx/AsyncDocumentClient.html). + +The SDK provide Reactive Extension Observable based async API. You can read more about RxJava and [Observable APIs here](http://reactivex.io/RxJava/1.x/javadoc/rx/Observable.html). + +## Usage Code Sample + +Code Sample for creating a Document: + +```java +import com.azure.data.cosmos.rx.*; +import com.azure.data.cosmos.*; + +ConnectionPolicy policy = new ConnectionPolicy(); +policy.setConnectionMode(ConnectionMode.Direct); + +AsyncDocumentClient asyncClient = new AsyncDocumentClient.Builder() + .withServiceEndpoint(HOST) + .withMasterKeyOrResourceToken(MASTER_KEY) + .withConnectionPolicy(policy) + .withConsistencyLevel(ConsistencyLevel.Eventual) + .build(); + +Document doc = new Document(String.format("{ 'id': 'doc%d', 'counter': '%d'}", 1, 1)); + +Observable> createDocumentObservable = + asyncClient.createDocument(collectionLink, doc, null, false); + createDocumentObservable + .single() // we know there will be one response + .subscribe( + + documentResourceResponse -> { + System.out.println(documentResourceResponse.getRequestCharge()); + }, + + error -> { + System.err.println("an error happened: " + error.getMessage()); + }); +``` + +We have a get started sample app available [here](https://github.com/Azure-Samples/azure-cosmos-db-sql-api-async-java-getting-started). + +Also We have more examples in form of standalone unit tests in [examples project](examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples). + +## Guide for Prod + +To achieve better performance and higher throughput there are a few tips that are helpful to follow: + +### Use Appropriate Scheduler (Avoid stealing Eventloop IO Netty threads) + +SDK uses [netty](https://netty.io/) for non-blocking IO. The SDK uses a fixed number of IO netty eventloop threads (as many CPU cores your machine has) for executing IO operations. + +The Observable returned by API emits the result on one of the shared IO eventloop netty threads. So it is important to not block the shared IO eventloop netty threads. Doing CPU intensive work or blocking operation on the IO eventloop netty thread may cause deadlock or significantly reduce SDK throughput. + +For example the following code executes a cpu intensive work on the eventloop IO netty thread: + +```java +Observable> createDocObs = asyncDocumentClient.createDocument( + collectionLink, document, null, true); + +createDocObs.subscribe( + resourceResponse -> { + //this is executed on eventloop IO netty thread. + //the eventloop thread is shared and is meant to return back quickly. + // + // DON'T do this on eventloop IO netty thread. + veryCpuIntensiveWork(); + }); + +``` + +After result is received if you want to do CPU intensive work on the result you should avoid doing so on eventloop IO netty thread. You can instead provide your own Scheduler to provide your own thread for running your work. + +```java +import rx.schedulers; + +Observable> createDocObs = asyncDocumentClient.createDocument( + collectionLink, document, null, true); + +createDocObs.subscribeOn(Schedulers.computation()) +subscribe( + resourceResponse -> { + // this is executed on threads provided by Scheduler.computation() + // Schedulers.computation() should be used only the work is cpu intensive and you are not doing blocking IO, thread sleep, etc. in this thread against other resources. + veryCpuIntensiveWork(); + }); + +``` + +Based on the type of your work you should use the appropriate existing RxJava Scheduler for your work. Please read here +[`Schedulers`](http://reactivex.io/RxJava/1.x/javadoc/rx/schedulers/Schedulers.html). + +### Disable netty's logging + +Netty library logging is very chatty and need to be turned off (suppressing log in the configuration may not be enough) to avoid additional CPU costs. +If you are not in debugging mode disable netty's logging altogether. So if you are using log4j to remove the additional CPU costs incurred by `org.apache.log4j.Category.callAppenders()` from netty add the following line to your codebase: + +```java +org.apache.log4j.Logger.getLogger("io.netty").setLevel(org.apache.log4j.Level.OFF); +``` + +### OS Open files Resource Limit + +Some Linux systems (like Redhat) have an upper limit on the number of open files and so the total number of connections. Run the following to view the current limits: + +```bash +ulimit -a +``` + +The number of open files (nofile) need to be large enough to have enough room for your configured connection pool size and other open files by the OS. It can be modified to allow for a larger connection pool size. + +Open the limits.conf file: + +```bash +vim /etc/security/limits.conf +``` + +Add/modify the following lines: + +``` +* - nofile 100000 +``` + +### Use native SSL implementation for netty + +Netty can use OpenSSL directly for SSL implementation stack to achieve better performance. +In the absence of this configuration netty will fall back to Java's default SSL implementation. + +on Ubuntu: + +```bash +sudo apt-get install openssl +sudo apt-get install libapr1 +``` + +and add the following dependency to your project maven dependencies: + +```xml + + io.netty + netty-tcnative + 2.0.20.Final + linux-x86_64 + +``` + +For other platforms (Redhat, Windows, Mac, etc) please refer to these instructions https://netty.io/wiki/forked-tomcat-native.html + +### Common Perf Tips + +There is a set of common perf tips written for our sync SDK. The majority of them also apply to the async SDK. It is available [here](https://docs.microsoft.com/en-us/azure/cosmos-db/performance-tips-java). + +## Future, CompletableFuture, and ListenableFuture + +The SDK provide Reactive Extension (Rx) [Observable](http://reactivex.io/RxJava/1.x/javadoc/rx/Observable.html) based async API. + +RX API has advantages over Future based APIs. But if you wish to use `Future` you can translate Observables to Java native Futures: + +```java +// You can convert an Observable to a ListenableFuture. +// ListenableFuture (part of google guava library) is a popular extension +// of Java's Future which allows registering listener callbacks: +// https://github.com/google/guava/wiki/ListenableFutureExplained + +import rx.observable.ListenableFutureObservable; + +Observable> createDocObservable = asyncClient.createDocument( + collectionLink, document, null, false); + +// NOTE: if you are going to do CPU intensive work +// on the result thread consider changing the scheduler see Use Proper Scheduler +// (Avoid Stealing Eventloop IO Netty threads) section +ListenableFuture> listenableFuture = + ListenableFutureObservable.to(createDocObservable); + +ResourceResponse rrd = listenableFuture.get(); +``` + +For this to work you will need [RxJava Guava library dependency ](https://mvnrepository.com/artifact/io.reactivex/rxjava-guava/1.0.3). More information available here https://github.com/ReactiveX/RxJavaGuava. + +You can see more details on how to convert Observables to Futures here: +https://dzone.com/articles/converting-between + +## Checking out the Source Code + +The SDK is open source and is available here [sdk](sdk/). + +Clone the Repo + +```bash +git clone https://github.com/Azure/azure-cosmosdb-java.git +cd azure-cosmosdb-java +``` + +### How to Build from Command Line + +- Run the following maven command to build: + +```bash +maven clean package -DskipTests +``` + +### How to generate directory structure for publishing + +- Run the following maven command to collect the jars needed for publishing + +```bash +mvn antrun:run -N +``` + +Note: the `-N` is required to assert this command is only run in the parent pom. + +Afterwards, you can upload the contents of `./target/collectedArtifactsForRelease` for publishing. + +#### Running Tests from Command Line + +Running tests require Azure Cosmos DB Endpoint credentials: + +```bash +mvn test -DACCOUNT_HOST="https://REPLACE_ME_WITH_YOURS.documents.azure.com:443/" -DACCOUNT_KEY="REPLACE_ME_WITH_YOURS" +``` + +### Import into Intellij or Eclipse + +- Load the main parent project pom file in Intellij/Eclipse (That should automatically load examples). +- For running the samples you need a proper Azure Cosmos DB Endpoint. The endpoints are picked up from [TestConfigurations.java](examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/TestConfigurations.java). There is a similar endpoint config file for the sdk tests [here](sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TestConfigurations.java). +- You can pass your endpoint credentials as VM Arguments in Eclipse JUnit Run Config: + +```bash + -DACCOUNT_HOST="https://REPLACE_ME.documents.azure.com:443/" -DACCOUNT_KEY="REPLACE_ME" +``` + +- or you can simply put your endpoint credentials in TestConfigurations.java +- The SDK tests are written using TestNG framework, if you use Eclipse you may have to + add TestNG plugin to your eclipse IDE as explained [here](http://testng.org/doc/eclipse.html). + Intellij has builtin support for TestNG. +- Now you can run the tests in your Intellij/Eclipse IDE. + +## FAQ + +We have a frequently asked questions which is maintained [here](faq/). + +## Release changes + +Release changelog is available [here](changelog/). + +## Contribution and Feedback + +This is an open source project and we welcome contributions. + +If you would like to become an active contributor to this project please follow the instructions provided in [Azure Projects Contribution Guidelines](http://azure.github.io/guidelines/). + +We have [travis build CI](https://travis-ci.org/Azure/azure-cosmosdb-java) which should pass for any PR. + +If you encounter any bugs with the SDK please file an [issue](https://github.com/Azure/azure-cosmosdb-java/issues) in the Issues section of the project. + +## License + +MIT License +Copyright (c) 2018 Copyright (c) Microsoft Corporation diff --git a/sdk/cosmos/benchmark/README.md b/sdk/cosmos/benchmark/README.md new file mode 100644 index 0000000000000..4f7aadcc7796e --- /dev/null +++ b/sdk/cosmos/benchmark/README.md @@ -0,0 +1,81 @@ +# Benchmark tool + +## Build the benchmarking tool + +```bash +git clone https://github.com/Azure/azure-cosmosdb-java.git +cd azure-cosmosdb-java + +mvn clean package -DskipTests +``` + +and then the package will be generated. + +## Run the WriteLatency workload + +```bash +java -jar benchmark/target/azure-cosmosdb-benchmark-2.4.1-SNAPSHOT-jar-with-dependencies.jar \ + -serviceEndpoint $endpoint -masterKey $masterkey \ + -databaseId $dbname -collectionId $colname \ + -consistencyLevel Eventual -concurrency 10 -numberOfOperations 1000000 \ + -operation WriteLatency -connectionMode Direct +``` + +## Sample Report: + +``` +2/13/19 9:32:39 PM ============================================================= + +-- Meters ---------------------------------------------------------------------- +#Successful Operations + count = 89934 + mean rate = 1798.56 events/second + 1-minute rate = 1718.45 events/second + 5-minute rate = 1630.17 events/second + 15-minute rate = 1610.01 events/second +#Unsuccessful Operations + count = 0 + mean rate = 0.00 events/second + 1-minute rate = 0.00 events/second + 5-minute rate = 0.00 events/second + 15-minute rate = 0.00 events/second + +-- Timers ---------------------------------------------------------------------- +Latency + count = 89938 + mean rate = 1798.64 calls/second + 1-minute rate = 1718.65 calls/second + 5-minute rate = 1630.37 calls/second + 15-minute rate = 1610.21 calls/second + min = 3.97 milliseconds + max = 22.81 milliseconds + mean = 5.37 milliseconds + stddev = 0.96 milliseconds + median = 5.26 milliseconds + 75% <= 5.70 milliseconds + 95% <= 6.40 milliseconds + 98% <= 6.93 milliseconds + 99% <= 7.51 milliseconds + 99.9% <= 17.37 milliseconds +``` + +## Other Currently Supported Workloads + +* ReadLatency, +* WriteLatency, +* ReadThroughput, +* WriteThroughput, +* QueryCross, +* QuerySingle, +* QuerySingleMany, +* QueryParallel, +* QueryOrderby, +* QueryAggregate, +* QueryAggregateTopOrderby, +* QueryTopOrderby, +* Mixed +* ReadMyWrites + + +You can provide ``--help`` to the tool to see the list of other work loads (read, etc) and other options. + diff --git a/sdk/cosmos/benchmark/pom.xml b/sdk/cosmos/benchmark/pom.xml new file mode 100644 index 0000000000000..491a48a51ee6b --- /dev/null +++ b/sdk/cosmos/benchmark/pom.xml @@ -0,0 +1,188 @@ + + + + 4.0.0 + + com.microsoft.azure + azure-cosmos-parent + 3.0.0 + + + azure-cosmos-benchmark + Async SDK for SQL API of Azure Cosmos DB Service - Benchmarking tool + Benchmarking tool for Async SDK for SQL API of Azure Cosmos DB Service + + + UTF-8 + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + com.azure.data.cosmos.benchmark.Main + + + + maven-assembly-plugin + 2.2 + + + jar-with-dependencies + + + + com.azure.data.cosmos.benchmark.Main + + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.8 + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8 + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + false + + + none + default-cli + + + + true + + + + + + + com.microsoft.azure + azure-cosmos + + + com.beust + jcommander + ${jcommander.version} + + + com.google.guava + guava + ${guava.version} + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + + + io.dropwizard.metrics + metrics-jvm + ${metrics.version} + + + io.dropwizard.metrics + metrics-graphite + ${metrics.version} + + + io.netty + netty-tcnative + ${netty-tcnative.version} + linux-x86_64 + + + log4j + log4j + ${log4j.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + + + org.testng + testng + ${testng.version} + test + + + diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncBenchmark.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncBenchmark.java new file mode 100644 index 0000000000000..f93c9a0b53a27 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncBenchmark.java @@ -0,0 +1,258 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.benchmark.Configuration.Operation; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.codahale.metrics.ConsoleReporter; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.ScheduledReporter; +import com.codahale.metrics.Timer; +import com.codahale.metrics.graphite.Graphite; +import com.codahale.metrics.graphite.GraphiteReporter; +import com.codahale.metrics.jvm.CachedThreadStatesGaugeSet; +import com.codahale.metrics.jvm.GarbageCollectorMetricSet; +import com.codahale.metrics.jvm.MemoryUsageGaugeSet; +import org.apache.commons.lang3.RandomStringUtils; +import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; + +import java.net.InetSocketAddress; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +abstract class AsyncBenchmark { + private final MetricRegistry metricsRegistry = new MetricRegistry(); + private final ScheduledReporter reporter; + private final String nameCollectionLink; + + private Meter successMeter; + private Meter failureMeter; + + final Logger logger; + final AsyncDocumentClient client; + final DocumentCollection collection; + final String partitionKey; + final Configuration configuration; + final List docsToRead; + final Semaphore concurrencyControlSemaphore; + Timer latency; + + AsyncBenchmark(Configuration cfg) { + client = new AsyncDocumentClient.Builder() + .withServiceEndpoint(cfg.getServiceEndpoint()) + .withMasterKeyOrResourceToken(cfg.getMasterKey()) + .withConnectionPolicy(cfg.getConnectionPolicy()) + .withConsistencyLevel(cfg.getConsistencyLevel()) + .build(); + + logger = LoggerFactory.getLogger(this.getClass()); + + Database database = DocDBUtils.getDatabase(client, cfg.getDatabaseId()); + collection = DocDBUtils.getCollection(client, database.selfLink(), cfg.getCollectionId()); + nameCollectionLink = String.format("dbs/%s/colls/%s", database.id(), collection.id()); + partitionKey = collection.getPartitionKey().paths().iterator().next().split("/")[1]; + concurrencyControlSemaphore = new Semaphore(cfg.getConcurrency()); + configuration = cfg; + + ArrayList> createDocumentObservables = new ArrayList<>(); + + if (configuration.getOperationType() != Operation.WriteLatency + && configuration.getOperationType() != Operation.WriteThroughput + && configuration.getOperationType() != Operation.ReadMyWrites) { + String dataFieldValue = RandomStringUtils.randomAlphabetic(cfg.getDocumentDataFieldSize()); + for (int i = 0; i < cfg.getNumberOfPreCreatedDocuments(); i++) { + String uuid = UUID.randomUUID().toString(); + Document newDoc = new Document(); + newDoc.id(uuid); + BridgeInternal.setProperty(newDoc, partitionKey, uuid); + BridgeInternal.setProperty(newDoc, "dataField1", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField2", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField3", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField4", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField5", dataFieldValue); + Flux obs = client.createDocument(collection.selfLink(), newDoc, null, false) + .map(ResourceResponse::getResource); + createDocumentObservables.add(obs); + } + } + + docsToRead = Flux.merge(Flux.fromIterable(createDocumentObservables), 100).collectList().block(); + init(); + + if (configuration.isEnableJvmStats()) { + metricsRegistry.register("gc", new GarbageCollectorMetricSet()); + metricsRegistry.register("threads", new CachedThreadStatesGaugeSet(10, TimeUnit.SECONDS)); + metricsRegistry.register("memory", new MemoryUsageGaugeSet()); + } + + if (configuration.getGraphiteEndpoint() != null) { + final Graphite graphite = new Graphite(new InetSocketAddress(configuration.getGraphiteEndpoint(), configuration.getGraphiteEndpointPort())); + reporter = GraphiteReporter.forRegistry(metricsRegistry) + .prefixedWith(configuration.getOperationType().name()) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .filter(MetricFilter.ALL) + .build(graphite); + } else { + reporter = ConsoleReporter.forRegistry(metricsRegistry).convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS).build(); + } + } + + protected void init() { + } + + void shutdown() { + client.close(); + } + + protected void onSuccess() { + } + + protected void onError(Throwable throwable) { + } + + protected String getCollectionLink() { + if (configuration.isUseNameLink()) { + return this.nameCollectionLink; + } else { + return collection.selfLink(); + } + } + + protected String getDocumentLink(Document doc) { + if (configuration.isUseNameLink()) { + return this.nameCollectionLink + "/docs/" + doc.id(); + } else { + return doc.selfLink(); + } + } + + protected abstract void performWorkload(BaseSubscriber baseSubscriber, long i) throws Exception; + + private boolean shouldContinue(long startTimeMillis, long iterationCount) { + Duration maxDurationTime = configuration.getMaxRunningTimeDuration(); + int maxNumberOfOperations = configuration.getNumberOfOperations(); + if (maxDurationTime == null) { + return iterationCount < maxNumberOfOperations; + } + + if (startTimeMillis + maxDurationTime.toMillis() < System.currentTimeMillis()) { + return false; + } + + if (maxNumberOfOperations < 0) { + return true; + } + + return iterationCount < maxNumberOfOperations; + } + + void run() throws Exception { + + successMeter = metricsRegistry.meter("#Successful Operations"); + failureMeter = metricsRegistry.meter("#Unsuccessful Operations"); + if (configuration.getOperationType() == Operation.ReadLatency + || configuration.getOperationType() == Operation.WriteLatency) + latency = metricsRegistry.timer("Latency"); + + reporter.start(configuration.getPrintingInterval(), TimeUnit.SECONDS); + + long startTime = System.currentTimeMillis(); + + AtomicLong count = new AtomicLong(0); + long i; + for ( i = 0; shouldContinue(startTime, i); i++) { + + BaseSubscriber baseSubscriber = new BaseSubscriber() { + @Override + protected void hookOnSubscribe(Subscription subscription) { + super.hookOnSubscribe(subscription); + } + + @Override + protected void hookOnNext(T value) { + + } + + @Override + protected void hookOnComplete() { + successMeter.mark(); + concurrencyControlSemaphore.release(); + AsyncBenchmark.this.onSuccess(); + + synchronized (count) { + count.incrementAndGet(); + count.notify(); + } + } + + @Override + protected void hookOnError(Throwable throwable) { + failureMeter.mark(); + logger.error("Encountered failure {} on thread {}" , + throwable.getMessage(), Thread.currentThread().getName(), throwable); + concurrencyControlSemaphore.release(); + AsyncBenchmark.this.onError(throwable); + + synchronized (count) { + count.incrementAndGet(); + count.notify(); + } + } + }; + + performWorkload(baseSubscriber, i); + } + + synchronized (count) { + while (count.get() < i) { + count.wait(); + } + } + + long endTime = System.currentTimeMillis(); + logger.info("[{}] operations performed in [{}] seconds.", + configuration.getNumberOfOperations(), (int) ((endTime - startTime) / 1000)); + + reporter.report(); + reporter.close(); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncMixedBenchmark.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncMixedBenchmark.java new file mode 100644 index 0000000000000..618d80556beee --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncMixedBenchmark.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import org.apache.commons.lang3.RandomStringUtils; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.util.Random; +import java.util.UUID; + +class AsyncMixedBenchmark extends AsyncBenchmark { + + private final String uuid; + private final String dataFieldValue; + private final Random r; + + AsyncMixedBenchmark(Configuration cfg) { + super(cfg); + uuid = UUID.randomUUID().toString(); + dataFieldValue = RandomStringUtils.randomAlphabetic(configuration.getDocumentDataFieldSize()); + r = new Random(); + } + + @Override + protected void performWorkload(BaseSubscriber documentBaseSubscriber, long i) throws InterruptedException { + Flux obs; + if (i % 10 == 0 && i % 100 != 0) { + + String idString = uuid + i; + Document newDoc = new Document(); + newDoc.id(idString); + BridgeInternal.setProperty(newDoc, partitionKey, idString); + BridgeInternal.setProperty(newDoc, "dataField1", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField2", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField3", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField4", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField5", dataFieldValue); + obs = client.createDocument(getCollectionLink(), newDoc, null, false).map(ResourceResponse::getResource); + + } else if (i % 100 == 0) { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(10); + options.enableCrossPartitionQuery(true); + + String sqlQuery = "Select top 100 * from c order by c._ts"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options) + .map(frp -> frp.results().get(0)); + } else { + + int index = r.nextInt(1000); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(docsToRead.get(index).id())); + + obs = client.readDocument(getDocumentLink(docsToRead.get(index)), options).map(ResourceResponse::getResource); + } + + concurrencyControlSemaphore.acquire(); + + obs.subscribeOn(Schedulers.parallel()).subscribe(documentBaseSubscriber); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQueryBenchmark.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQueryBenchmark.java new file mode 100644 index 0000000000000..ee592ad291eeb --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQueryBenchmark.java @@ -0,0 +1,110 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.util.Random; + +class AsyncQueryBenchmark extends AsyncBenchmark> { + + private int pageCount = 0; + + AsyncQueryBenchmark(Configuration cfg) { + super(cfg); + } + + @Override + protected void onSuccess() { + pageCount++; + if (pageCount % 10000 == 0) { + if (pageCount == 0) { + return; + } + logger.info("total pages so far: {}", pageCount); + } + } + + @Override + protected void performWorkload(BaseSubscriber> baseSubscriber, long i) throws InterruptedException { + + Flux> obs; + Random r = new Random(); + FeedOptions options = new FeedOptions(); + + if (configuration.getOperationType() == Configuration.Operation.QueryCross) { + + int index = r.nextInt(1000); + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select * from c where c._rid = \"" + docsToRead.get(index).resourceId() + "\""; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QuerySingle) { + + int index = r.nextInt(1000); + String pk = docsToRead.get(index).getString("pk"); + options.partitionKey(new PartitionKey(pk)); + String sqlQuery = "Select * from c where c.pk = \"" + pk + "\""; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QueryParallel) { + + options.maxItemCount(10); + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select * from c"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QueryOrderby) { + + options.maxItemCount(10); + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select * from c order by c._ts"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QueryAggregate) { + + options.maxItemCount(10); + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select value max(c._ts) from c"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QueryAggregateTopOrderby) { + + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select top 1 value count(c) from c order by c._ts"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else if (configuration.getOperationType() == Configuration.Operation.QueryTopOrderby) { + + options.enableCrossPartitionQuery(true); + String sqlQuery = "Select top 1000 * from c order by c._ts"; + obs = client.queryDocuments(getCollectionLink(), sqlQuery, options); + } else { + throw new IllegalArgumentException("Unsupported Operation: " + configuration.getOperationType()); + } + concurrencyControlSemaphore.acquire(); + + obs.subscribeOn(Schedulers.parallel()).subscribe(baseSubscriber); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQuerySinglePartitionMultiple.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQuerySinglePartitionMultiple.java new file mode 100644 index 0000000000000..a41280c5afe28 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncQuerySinglePartitionMultiple.java @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +class AsyncQuerySinglePartitionMultiple extends AsyncBenchmark> { + + private static final String SQL_QUERY = "Select * from c where c.pk = \"pk\""; + private FeedOptions options; + private int pageCount = 0; + + AsyncQuerySinglePartitionMultiple(Configuration cfg) { + super(cfg); + options = new FeedOptions(); + options.partitionKey(new PartitionKey("pk")); + options.maxItemCount(10); + } + + @Override + protected void onSuccess() { + pageCount++; + if (pageCount % 10000 == 0) { + if (pageCount == 0) { + return; + } + logger.info("total pages so far: {}", pageCount); + } + } + + @Override + protected void performWorkload(BaseSubscriber> baseSubscriber, long i) throws InterruptedException { + Flux> obs = client.queryDocuments(getCollectionLink(), SQL_QUERY, options); + + concurrencyControlSemaphore.acquire(); + + obs.subscribeOn(Schedulers.parallel()).subscribe(baseSubscriber); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncReadBenchmark.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncReadBenchmark.java new file mode 100644 index 0000000000000..0e8172ec35287 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncReadBenchmark.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.codahale.metrics.Timer; +import org.reactivestreams.Subscription; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +class AsyncReadBenchmark extends AsyncBenchmark> { + + class LatencySubscriber extends BaseSubscriber { + + Timer.Context context; + BaseSubscriber> baseSubscriber; + + LatencySubscriber(BaseSubscriber> baseSubscriber) { + this.baseSubscriber = baseSubscriber; + } + + @Override + protected void hookOnSubscribe(Subscription subscription) { + super.hookOnSubscribe(subscription); + } + + @Override + protected void hookOnNext(T value) { + } + + @Override + protected void hookOnComplete() { + context.stop(); + baseSubscriber.onComplete(); + } + + @Override + protected void hookOnError(Throwable throwable) { + context.stop(); + baseSubscriber.onError(throwable); + } + } + + AsyncReadBenchmark(Configuration cfg) { + super(cfg); + } + + @Override + protected void performWorkload(BaseSubscriber> baseSubscriber, long i) throws InterruptedException { + int index = (int) (i % docsToRead.size()); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(docsToRead.get(index).id())); + + Flux> obs = client.readDocument(getDocumentLink(docsToRead.get(index)), options); + + concurrencyControlSemaphore.acquire(); + + if (configuration.getOperationType() == Configuration.Operation.ReadThroughput) { + obs.subscribeOn(Schedulers.parallel()).subscribe(baseSubscriber); + } else { + LatencySubscriber> latencySubscriber = new LatencySubscriber<>(baseSubscriber); + latencySubscriber.context = latency.time(); + obs.subscribeOn(Schedulers.parallel()).subscribe(latencySubscriber); + } + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncWriteBenchmark.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncWriteBenchmark.java new file mode 100644 index 0000000000000..54af2e988b8e2 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/AsyncWriteBenchmark.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.codahale.metrics.Timer; +import org.apache.commons.lang3.RandomStringUtils; +import org.reactivestreams.Subscription; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.util.UUID; + +class AsyncWriteBenchmark extends AsyncBenchmark> { + + private final String uuid; + private final String dataFieldValue; + + class LatencySubscriber extends BaseSubscriber { + + Timer.Context context; + BaseSubscriber> baseSubscriber; + + LatencySubscriber(BaseSubscriber> baseSubscriber) { + this.baseSubscriber = baseSubscriber; + } + + @Override + protected void hookOnSubscribe(Subscription subscription) { + super.hookOnSubscribe(subscription); + } + + @Override + protected void hookOnNext(T value) { + } + + @Override + protected void hookOnComplete() { + context.stop(); + baseSubscriber.onComplete(); + } + + @Override + protected void hookOnError(Throwable throwable) { + context.stop(); + baseSubscriber.onError(throwable); + } + } + + AsyncWriteBenchmark(Configuration cfg) { + super(cfg); + uuid = UUID.randomUUID().toString(); + dataFieldValue = RandomStringUtils.randomAlphabetic(configuration.getDocumentDataFieldSize()); + } + + @Override + protected void performWorkload(BaseSubscriber> baseSubscriber, long i) throws InterruptedException { + + String idString = uuid + i; + Document newDoc = new Document(); + newDoc.id(idString); + BridgeInternal.setProperty(newDoc, partitionKey, idString); + BridgeInternal.setProperty(newDoc, "dataField1", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField2", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField3", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField4", dataFieldValue); + BridgeInternal.setProperty(newDoc, "dataField5", dataFieldValue); + Flux> obs = client.createDocument(getCollectionLink(), newDoc, null, + false); + + concurrencyControlSemaphore.acquire(); + + if (configuration.getOperationType() == Configuration.Operation.WriteThroughput) { + obs.subscribeOn(Schedulers.parallel()).subscribe(baseSubscriber); + } else { + LatencySubscriber> latencySubscriber = new LatencySubscriber<>(baseSubscriber); + latencySubscriber.context = latency.time(); + obs.subscribeOn(Schedulers.parallel()).subscribe(latencySubscriber); + } + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Configuration.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Configuration.java new file mode 100644 index 0000000000000..0a54017429e28 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Configuration.java @@ -0,0 +1,329 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.benchmark.Configuration.Operation.OperationTypeConverter; +import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParameterException; +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.time.Duration; +import java.util.Arrays; + +class Configuration { + private final static int GRAPHITE_SERVER_DEFAULT_PORT = 2003; + + @Parameter(names = "-serviceEndpoint", description = "Service Endpoint") + private String serviceEndpoint; + + @Parameter(names = "-masterKey", description = "Master Key") + private String masterKey; + + @Parameter(names = "-databaseId", description = "Database ID") + private String databaseId; + + @Parameter(names = "-collectionId", description = "Collection ID") + private String collectionId; + + @Parameter(names = "-useNameLink", description = "Use name Link") + private boolean useNameLink = false; + + @Parameter(names = "-documentDataFieldSize", description = "Length of a document data field in characters (16-bit)") + private int documentDataFieldSize = 20; + + @Parameter(names = "-maxConnectionPoolSize", description = "Max Connection Pool Size") + private Integer maxConnectionPoolSize = 1000; + + @Parameter(names = "-consistencyLevel", description = "Consistency Level", converter = ConsistencyLevelConverter.class) + private ConsistencyLevel consistencyLevel = ConsistencyLevel.SESSION; + + @Parameter(names = "-connectionMode", description = "Connection Mode") + private ConnectionMode connectionMode = ConnectionMode.DIRECT; + + @Parameter(names = "-graphiteEndpoint", description = "Graphite endpoint") + private String graphiteEndpoint; + + @Parameter(names = "-enableJvmStats", description = "Enables JVM Stats") + private boolean enableJvmStats; + + @Parameter(names = "-operation", description = "Type of Workload:\n" + + "\tReadThroughput- run a READ workload that prints only throughput *\n" + + "\tWriteThroughput - run a Write workload that prints only throughput\n" + + "\tReadLatency - run a READ workload that prints both throughput and latency *\n" + + "\tWriteLatency - run a Write workload that prints both throughput and latency\n" + + "\tQueryCross - run a 'Select * from c where c._rid = SOME_RID' workload that prints throughput\n" + + "\tQuerySingle - run a 'Select * from c where c.pk = SOME_PK' workload that prints throughput\n" + + "\tQuerySingleMany - run a 'Select * from c where c.pk = \"pk\"' workload that prints throughput\n" + + "\tQueryParallel - run a 'Select * from c' workload that prints throughput\n" + + "\tQueryOrderby - run a 'Select * from c order by c._ts' workload that prints throughput\n" + + "\tQueryAggregate - run a 'Select value max(c._ts) from c' workload that prints throughput\n" + + "\tQueryAggregateTopOrderby - run a 'Select top 1 value count(c) from c order by c._ts' workload that prints throughput\n" + + "\tQueryTopOrderby - run a 'Select top 1000 * from c order by c._ts' workload that prints throughput\n" + + "\tMixed - runa workload of 90 reads, 9 writes and 1 QueryTopOrderby per 100 operations *\n" + + "\tReadMyWrites - run a workflow of writes followed by reads and queries attempting to read the write.*\n" + + "\n\t* writes 10k documents initially, which are used in the reads", converter = OperationTypeConverter.class) + private Operation operation = Operation.WriteThroughput; + + @Parameter(names = "-concurrency", description = "Degree of Concurrency in Inserting Documents." + + " If this value is not specified, the max connection pool size will be used as the concurrency level.") + private Integer concurrency; + + @Parameter(names = "-numberOfOperations", description = "Total NUMBER Of Documents To Insert") + private int numberOfOperations = 100000; + + static class DurationConverter implements IStringConverter { + @Override + public Duration convert(String value) { + if (value == null) { + return null; + } + + return Duration.parse(value); + } + } + + @Parameter(names = "-maxRunningTimeDuration", description = "Max Running Time Duration", converter = DurationConverter.class) + private Duration maxRunningTimeDuration; + + @Parameter(names = "-printingInterval", description = "Interval of time after which Metrics should be printed (seconds)") + private int printingInterval = 10; + + @Parameter(names = "-numberOfPreCreatedDocuments", description = "Total NUMBER Of Documents To pre create for a read workload to use") + private int numberOfPreCreatedDocuments = 1000; + + @Parameter(names = {"-h", "-help", "--help"}, description = "Help", help = true) + private boolean help = false; + + enum Operation { + ReadThroughput, + WriteThroughput, + ReadLatency, + WriteLatency, + QueryCross, + QuerySingle, + QuerySingleMany, + QueryParallel, + QueryOrderby, + QueryAggregate, + QueryAggregateTopOrderby, + QueryTopOrderby, + Mixed, + ReadMyWrites; + + static Operation fromString(String code) { + + for (Operation output : Operation.values()) { + if (output.toString().equalsIgnoreCase(code)) { + return output; + } + } + + return null; + } + + static class OperationTypeConverter implements IStringConverter { + + /* + * (non-Javadoc) + * + * @see com.beust.jcommander.IStringConverter#convert(java.lang.STRING) + */ + @Override + public Operation convert(String value) { + Operation ret = fromString(value); + if (ret == null) { + throw new ParameterException("Value " + value + " can not be converted to ClientType. " + + "Available values are: " + Arrays.toString(Operation.values())); + } + return ret; + } + } + } + + private static ConsistencyLevel fromString(String code) { + for (ConsistencyLevel output : ConsistencyLevel.values()) { + if (output.toString().equalsIgnoreCase(code)) { + return output; + } + } + return null; + } + + static class ConsistencyLevelConverter implements IStringConverter { + + /* + * (non-Javadoc) + * + * @see com.beust.jcommander.IStringConverter#convert(java.lang.STRING) + */ + @Override + public ConsistencyLevel convert(String value) { + ConsistencyLevel ret = fromString(value); + if (ret == null) { + throw new ParameterException("Value " + value + " can not be converted to ClientType. " + + "Available values are: " + Arrays.toString(Operation.values())); + } + return ret; + } + } + + Duration getMaxRunningTimeDuration() { + return maxRunningTimeDuration; + } + + Operation getOperationType() { + return operation; + } + + int getNumberOfOperations() { + return numberOfOperations; + } + + String getServiceEndpoint() { + return serviceEndpoint; + } + + String getMasterKey() { + return masterKey; + } + + boolean isHelp() { + return help; + } + + int getDocumentDataFieldSize() { + return documentDataFieldSize; + } + + ConnectionPolicy getConnectionPolicy() { + ConnectionPolicy policy = new ConnectionPolicy(); + policy.connectionMode(connectionMode); + policy.maxPoolSize(maxConnectionPoolSize); + return policy; + } + + ConsistencyLevel getConsistencyLevel() { + return consistencyLevel; + } + + String getDatabaseId() { + return databaseId; + } + + String getCollectionId() { + return collectionId; + } + + int getNumberOfPreCreatedDocuments() { + return numberOfPreCreatedDocuments; + } + + int getPrintingInterval() { + return printingInterval; + } + + int getConcurrency() { + if (this.concurrency != null) { + return concurrency; + } else { + return this.maxConnectionPoolSize; + } + } + + boolean isUseNameLink() { + return useNameLink; + } + + public boolean isEnableJvmStats() { + return enableJvmStats; + } + + public String getGraphiteEndpoint() { + if (graphiteEndpoint == null) { + return null; + } + + return StringUtils.substringBeforeLast(graphiteEndpoint, ":"); + } + + public int getGraphiteEndpointPort() { + if (graphiteEndpoint == null) { + return -1; + } + + String portAsString = Strings.emptyToNull(StringUtils.substringAfterLast(graphiteEndpoint, ":")); + if (portAsString == null) { + return GRAPHITE_SERVER_DEFAULT_PORT; + } else { + return Integer.parseInt(portAsString); + } + } + + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); + } + + void tryGetValuesFromSystem() { + serviceEndpoint = StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("SERVICE_END_POINT")), + serviceEndpoint); + + masterKey = StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("MASTER_KEY")), masterKey); + + databaseId = StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("DATABASE_ID")), databaseId); + + collectionId = StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("COLLECTION_ID")), + collectionId); + + documentDataFieldSize = Integer.parseInt( + StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("DOCUMENT_DATA_FIELD_SIZE")), + Integer.toString(documentDataFieldSize))); + + maxConnectionPoolSize = Integer.parseInt( + StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("MAX_CONNECTION_POOL_SIZE")), + Integer.toString(maxConnectionPoolSize))); + + ConsistencyLevelConverter consistencyLevelConverter = new ConsistencyLevelConverter(); + consistencyLevel = consistencyLevelConverter.convert(StringUtils + .defaultString(Strings.emptyToNull(System.getenv().get("CONSISTENCY_LEVEL")), consistencyLevel.name())); + + OperationTypeConverter operationTypeConverter = new OperationTypeConverter(); + operation = operationTypeConverter.convert( + StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("OPERATION")), operation.name())); + + String concurrencyValue = StringUtils.defaultString(Strings.emptyToNull(System.getenv().get("CONCURRENCY")), + concurrency == null ? null : Integer.toString(concurrency)); + concurrency = concurrencyValue == null ? null : Integer.parseInt(concurrencyValue); + + String numberOfOperationsValue = StringUtils.defaultString( + Strings.emptyToNull(System.getenv().get("NUMBER_OF_OPERATIONS")), Integer.toString(numberOfOperations)); + numberOfOperations = Integer.parseInt(numberOfOperationsValue); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/DocDBUtils.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/DocDBUtils.java new file mode 100644 index 0000000000000..534603bd67031 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/DocDBUtils.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; + +class DocDBUtils { + + private DocDBUtils() { + } + + static Database getDatabase(AsyncDocumentClient client, String databaseId) { + FeedResponse feedResponsePages = client + .queryDatabases(new SqlQuerySpec("SELECT * FROM root r WHERE r.id=@id", + new SqlParameterList(new SqlParameter("@id", databaseId))), null) + .single().block(); + + if (feedResponsePages.results().isEmpty()) { + throw new RuntimeException("cannot find datatbase " + databaseId); + } + return feedResponsePages.results().get(0); + } + + static DocumentCollection getCollection(AsyncDocumentClient client, String databaseLink, + String collectionId) { + FeedResponse feedResponsePages = client + .queryCollections(databaseLink, + new SqlQuerySpec("SELECT * FROM root r WHERE r.id=@id", + new SqlParameterList(new SqlParameter("@id", collectionId))), + null) + .single().block(); + + if (feedResponsePages.results().isEmpty()) { + throw new RuntimeException("cannot find collection " + collectionId); + } + return feedResponsePages.results().get(0); + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Main.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Main.java new file mode 100644 index 0000000000000..edd3969c89f6e --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/Main.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Main { + + private final static Logger LOGGER = LoggerFactory.getLogger(Main.class); + + public static void main(String[] args) throws Exception { + org.apache.log4j.Logger.getLogger("io.netty").setLevel(org.apache.log4j.Level.OFF); + + try { + LOGGER.debug("Parsing the arguments ..."); + Configuration cfg = new Configuration(); + cfg.tryGetValuesFromSystem(); + + JCommander jcommander = new JCommander(cfg, args); + if (cfg.isHelp()) { + // prints out the usage help + jcommander.usage(); + return; + } + + AsyncBenchmark benchmark; + switch (cfg.getOperationType()) { + case WriteThroughput: + case WriteLatency: + benchmark = new AsyncWriteBenchmark(cfg); + break; + + case ReadThroughput: + case ReadLatency: + benchmark = new AsyncReadBenchmark(cfg); + break; + + case QueryCross: + case QuerySingle: + case QueryParallel: + case QueryOrderby: + case QueryAggregate: + case QueryTopOrderby: + case QueryAggregateTopOrderby: + benchmark = new AsyncQueryBenchmark(cfg); + break; + + case Mixed: + benchmark = new AsyncMixedBenchmark(cfg); + break; + + case QuerySingleMany: + benchmark = new AsyncQuerySinglePartitionMultiple(cfg); + break; + + case ReadMyWrites: + benchmark = new ReadMyWriteWorkflow(cfg); + break; + + default: + throw new RuntimeException(cfg.getOperationType() + " is not supported"); + } + + benchmark.run(); + benchmark.shutdown(); + + } catch (ParameterException e) { + // if any error in parsing the cmd-line options print out the usage help + System.err.println("INVALID Usage: " + e.getMessage()); + System.err.println("Try '-help' for more information."); + throw e; + } + } +} diff --git a/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/ReadMyWriteWorkflow.java b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/ReadMyWriteWorkflow.java new file mode 100644 index 0000000000000..233f177e3bb66 --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/java/com/azure/data/cosmos/benchmark/ReadMyWriteWorkflow.java @@ -0,0 +1,419 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.Utils; +import org.apache.commons.lang3.RandomUtils; +import reactor.core.publisher.BaseSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * This workflow is intended for session and above consistency levels. + *

    + * This workflow first will create some documents in cosmosdb and will store them all in its local cache. + * Then at each step will randomly will try to do a write, read its own write, or query for its own write. + */ +class ReadMyWriteWorkflow extends AsyncBenchmark { + private final static String QUERY_FIELD_NAME = "prop"; + private final static String ORDER_BY_FIELD_NAME = "_ts"; + private final static int MAX_TOP_QUERY_COUNT = 2000; + + private ConcurrentHashMap cache; + private int cacheSize; + + ReadMyWriteWorkflow(Configuration cfg) { + super(cfg); + } + + @Override + protected void init() { + this.cacheSize = configuration.getNumberOfPreCreatedDocuments(); + this.cache = new ConcurrentHashMap<>(); + this.populateCache(); + } + + @Override + protected void performWorkload(BaseSubscriber baseSubscriber, long i) throws Exception { + Flux obs; + boolean readyMyWrite = RandomUtils.nextBoolean(); + if (readyMyWrite) { + // will do a write and immediately upon success will either + // do a point read + // or single partition query + // or cross partition query to find the write. + int j = Math.toIntExact(Math.floorMod(i, 3)); + switch (j) { + case 0: + // write a random document to cosmodb and update the cache. + // then try to read the document which just was written + obs = writeDocument() + .flatMap(this::readDocument); + break; + case 1: + // write a random document to cosmodb and update the cache. + // then try to query for the document which just was written + obs = writeDocument() + .flatMap(d -> singlePartitionQuery(d) + .switchIfEmpty(Flux.error(new NotFoundException( + "couldn't find my write in a single partition query!")))); + break; + case 2: + // write a random document to cosmodb and update the cache. + // then try to query for the document which just was written + obs = writeDocument() + .flatMap(d -> xPartitionQuery(generateQuery(d)) + .switchIfEmpty(Flux.error(new NotFoundException( + "couldn't find my write in a cross partition query!")))); + break; + default: + assert false; + throw new IllegalStateException(); + } + } else { + // will either do + // a write + // a point read for a in memory cached document + // or single partition query for a in memory cached document + // or cross partition query for a in memory cached document + int j = Math.toIntExact(Math.floorMod(i, 4)); + switch (j) { + case 0: + // write a random document to cosmosdb and update the cache + obs = writeDocument(); + break; + case 1: + // randomly choose a document from the cache and do a single point read + obs = readDocument(cache.get(cacheKey())); + break; + case 2: + // randomly choose a document from the cache and do a single partition query + obs = singlePartitionQuery(cache.get(cacheKey())) + .switchIfEmpty(Flux.error(new NotFoundException( + "couldn't find my cached write in a single partition query!"))); + break; + case 3: + // randomly choose a document from the cache and do a cross partition query + obs = xPartitionQuery(generateRandomQuery()) + .switchIfEmpty(Flux.error(new NotFoundException( + "couldn't find my cached write in a cross partition query!"))); + break; + default: + assert false; + throw new IllegalStateException(); + } + } + + concurrencyControlSemaphore.acquire(); + + obs.subscribeOn(Schedulers.parallel()).subscribe(baseSubscriber); + } + + private void populateCache() { + ArrayList> list = new ArrayList<>(); + for (int i = 0; i < cacheSize; i++) { + Flux observable = writeDocument(i); + list.add(observable); + } + + logger.info("PRE-populating {} documents ....", cacheSize); + Flux.merge(Flux.fromIterable(list), configuration.getConcurrency()).then().block(); + logger.info("Finished pre-populating {} documents", cacheSize); + } + + /** + * Writes a random document to cosmosdb and store it in a random location in the cache. + * + * @return Observable of document + */ + private Flux writeDocument() { + return writeDocument(null); + } + + /** + * Writes a random document to cosmosdb and store it in the slot i-th in the cache. + * + * @return Observable of document + */ + private Flux writeDocument(Integer i) { + String idString = Utils.randomUUID().toString(); + String randomVal = Utils.randomUUID().toString(); + Document document = new Document(); + document.id(idString); + BridgeInternal.setProperty(document, partitionKey, idString); + BridgeInternal.setProperty(document, QUERY_FIELD_NAME, randomVal); + BridgeInternal.setProperty(document, "dataField1", randomVal); + BridgeInternal.setProperty(document, "dataField2", randomVal); + BridgeInternal.setProperty(document, "dataField3", randomVal); + BridgeInternal.setProperty(document, "dataField4", randomVal); + + Integer key = i == null ? cacheKey() : i; + return client.createDocument(getCollectionLink(), document, null, false) + .doOnNext(r -> cache.put(key, r.getResource())) + .map(ResourceResponse::getResource); + } + + /** + * given a document tries to read it from cosmosdb + * + * @param d document to be read + * @return Observable of document + */ + private Flux readDocument(Document d) { + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(d.getString(partitionKey))); + + return client.readDocument(getDocumentLink(d), options) + .map(ResourceResponse::getResource); + } + + /** + * Generates a random query + * + * @return a randomly generated query + */ + private SqlQuerySpec generateRandomQuery() { + int docCount = RandomUtils.nextInt(1, 2); + Set keys = new HashSet<>(); + for (int i = 0; i < docCount; i++) { + int key = RandomUtils.nextInt(0, cacheSize); + keys.add(key); + } + List documentList = null; + if (RandomUtils.nextBoolean()) { + documentList = keys.stream().map(cache::get).collect(Collectors.toList()); + } + + int top = RandomUtils.nextInt(0, MAX_TOP_QUERY_COUNT); + boolean useOrderBy = RandomUtils.nextBoolean(); + + return generateQuery(documentList, top > 1000 ? top : null, useOrderBy); + } + + /** + * given a query returns the corresponding observable result + * + * @param query to find document + * @return Observable document + */ + private Flux xPartitionQuery(SqlQuerySpec query) { + FeedOptions options = new FeedOptions(); + options.maxDegreeOfParallelism(-1); + options.enableCrossPartitionQuery(true); + + return client.queryDocuments(getCollectionLink(), query, options) + .flatMap(p -> Flux.fromIterable(p.results())); + } + + /** + * given a document returns the corresponding observable result of issuing a single partition query + * for the document. + * + * @param d document to be queried for. + * @return Observable document + */ + private Flux singlePartitionQuery(Document d) { + FeedOptions options = new FeedOptions(); + options.partitionKey(new PartitionKey(d.get(partitionKey))); + + SqlQuerySpec sqlQuerySpec = new SqlQuerySpec(String.format("Select top 100 * from c where c.%s = '%s'", + QUERY_FIELD_NAME, + d.getString(QUERY_FIELD_NAME))); + return client.queryDocuments(getCollectionLink(), sqlQuerySpec, options) + .flatMap(p -> Flux.fromIterable(p.results())); + } + + /** + * Given a document list generates a randomly generated sql query which can find only and only the documents + *

    + * The generated query may have a top, orderby, top and orderby. + * + * @param documentList list of documents to be queried for + * @return SqlQuerySpec + */ + private SqlQuerySpec generateQuery(Document... documentList) { + return generateQuery(Arrays.asList(documentList)); + } + + /** + * Given a document list generates a randomly generated sql query which can find only and only the documents + *

    + * The generated query may have a top, orderby, top and orderby. + * + * @param documentList list of documents to be queried for + * @return SqlQuerySpec + */ + private SqlQuerySpec generateQuery(List documentList) { + int top = RandomUtils.nextInt(0, MAX_TOP_QUERY_COUNT); + boolean useOrderBy = RandomUtils.nextBoolean(); + + return generateQuery(documentList, top >= documentList.size() ? top : null, useOrderBy); + } + + /** + * Given a document list generates sql query which can find only and only the documents + * + * @param documentList lists of documents to find + * @param topCount if a valid top count, the query will have a top count + * @param withOrderBy if not null, the query will have an orderby clause + * @return SqlQuerySpec + */ + private SqlQuerySpec generateQuery(List documentList, Integer topCount, boolean withOrderBy) { + QueryBuilder queryBuilder = new QueryBuilder(); + if (withOrderBy) { + queryBuilder.orderBy(ORDER_BY_FIELD_NAME); + } + if (documentList != null && !documentList.isEmpty()) { + if (topCount != null) { + topCount = Math.max(topCount, documentList.size()); + } + + queryBuilder.whereClause(QueryBuilder.WhereClause.InWhereClause.asInWhereClause(QUERY_FIELD_NAME, documentList)); + } + + if ((documentList == null || documentList.isEmpty()) && (topCount == null || topCount <= 0)) { + topCount = 100; + } + + if (topCount != null) { + queryBuilder.top(topCount); + } + + return queryBuilder.toSqlQuerySpec(); + } + + private int cacheKey() { + return RandomUtils.nextInt(0, cacheSize); + } + + /** + * This is used for making random query generation with different terms (top, orderby) easier. + */ + static class QueryBuilder { + private String orderByFieldName; + private Integer topCount; + private WhereClause whereClause; + + QueryBuilder top(int top) { + this.topCount = top; + return this; + } + + QueryBuilder orderBy(String fieldName) { + this.orderByFieldName = fieldName; + return this; + } + + QueryBuilder whereClause(WhereClause whereClause) { + this.whereClause = whereClause; + return this; + } + + static abstract class WhereClause { + static class InWhereClause extends WhereClause { + private final List parameters; + private final String whereCondition; + + static InWhereClause asInWhereClause(String fieldName, List documentList) { + List parameters = new ArrayList<>(documentList.size()); + for (int i = 0; i < documentList.size(); i++) { + Object value = documentList.get(i).get(fieldName); + SqlParameter sqlParameter = new SqlParameter("@param" + i, value); + parameters.add(sqlParameter); + } + + return new InWhereClause(fieldName, parameters); + } + + InWhereClause(String fieldName, List parameters) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(fieldName); + stringBuilder.append(" IN ("); + List params = parameters.stream().map(SqlParameter::name).collect(Collectors.toList()); + stringBuilder.append(String.join(", ", params)); + stringBuilder.append(")"); + + this.whereCondition = stringBuilder.toString(); + this.parameters = parameters; + } + + @Override + String getWhereCondition(String rootName) { + return rootName + "." + this.whereCondition; + } + + @Override + SqlParameterList getSqlParameterCollection() { + return new SqlParameterList(this.parameters); + } + } + + abstract String getWhereCondition(String rootName); + + abstract SqlParameterList getSqlParameterCollection(); + } + + SqlQuerySpec toSqlQuerySpec() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("SELECT"); + + if (topCount != null) { + stringBuilder.append(" TOP ").append(topCount); + } + + stringBuilder.append(" * FROM root"); + if (whereClause != null) { + stringBuilder.append(" WHERE "); + stringBuilder.append(whereClause.getWhereCondition("root")); + + } + + if (orderByFieldName != null) { + stringBuilder.append(" ORDER BY ").append("root.").append(orderByFieldName); + } + + return whereClause == null ? + new SqlQuerySpec(stringBuilder.toString()) : + new SqlQuerySpec(stringBuilder.toString(), whereClause.getSqlParameterCollection()); + } + } +} diff --git a/sdk/cosmos/benchmark/src/main/resources/log4j.properties b/sdk/cosmos/benchmark/src/main/resources/log4j.properties new file mode 100644 index 0000000000000..7a31b9cb1817a --- /dev/null +++ b/sdk/cosmos/benchmark/src/main/resources/log4j.properties @@ -0,0 +1,14 @@ +# this is the log4j configuration for tests + +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=INFO, A1 + +log4j.category.com.azure.data.cosmos.internal.directconnectivity.rntbd=WARN +log4j.category.io.netty=INFO +log4j.category.io.reactivex=INFO +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n \ No newline at end of file diff --git a/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/QueryBuilderTest.java b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/QueryBuilderTest.java new file mode 100644 index 0000000000000..6e0580ddcc018 --- /dev/null +++ b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/QueryBuilderTest.java @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.SqlParameter; +import com.google.common.collect.ImmutableList; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class QueryBuilderTest { + + @Test(groups = {"unit"}) + public void basic() { + ReadMyWriteWorkflow.QueryBuilder queryBuilder = new ReadMyWriteWorkflow.QueryBuilder(); + assertThat(queryBuilder.toSqlQuerySpec().queryText()) + .isEqualTo("SELECT * FROM root"); + } + + @Test(groups = {"unit"}) + public void top() { + ReadMyWriteWorkflow.QueryBuilder queryBuilder = new ReadMyWriteWorkflow.QueryBuilder(); + queryBuilder.top(50); + assertThat(queryBuilder.toSqlQuerySpec().queryText()) + .isEqualTo("SELECT TOP 50 * FROM root"); + } + + @Test(groups = {"unit"}) + public void orderBy() { + ReadMyWriteWorkflow.QueryBuilder queryBuilder = new ReadMyWriteWorkflow.QueryBuilder(); + queryBuilder.orderBy("prop"); + assertThat(queryBuilder.toSqlQuerySpec().queryText()) + .isEqualTo("SELECT * FROM root ORDER BY root.prop"); + } + + @Test(groups = {"unit"}) + public void whereInClause() { + ReadMyWriteWorkflow.QueryBuilder queryBuilder = new ReadMyWriteWorkflow.QueryBuilder(); + + ImmutableList parameters = ImmutableList.of(new SqlParameter("@param1", 1), + new SqlParameter("@param2", 2)); + queryBuilder.whereClause(new ReadMyWriteWorkflow.QueryBuilder.WhereClause.InWhereClause("colName", + parameters)); + assertThat(queryBuilder.toSqlQuerySpec().queryText()) + .isEqualTo("SELECT * FROM root WHERE root.colName IN (@param1, @param2)"); + assertThat(queryBuilder.toSqlQuerySpec().parameters()).containsExactlyElementsOf(parameters); + } + + @Test(groups = {"unit"}) + public void topOrderByWhereClause() { + ReadMyWriteWorkflow.QueryBuilder queryBuilder = new ReadMyWriteWorkflow.QueryBuilder(); + queryBuilder.orderBy("prop"); + queryBuilder.top(5); + + ImmutableList parameters = ImmutableList.of(new SqlParameter("@param1", 1), + new SqlParameter("@param2", 2)); + queryBuilder.whereClause(new ReadMyWriteWorkflow.QueryBuilder.WhereClause.InWhereClause("colName", + parameters)); + assertThat(queryBuilder.toSqlQuerySpec().queryText()) + .isEqualTo("SELECT TOP 5 * FROM root WHERE root.colName IN (@param1, @param2) ORDER BY root.prop"); + assertThat(queryBuilder.toSqlQuerySpec().parameters()).containsExactlyElementsOf(parameters); + } +} diff --git a/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/ReadMyWritesConsistencyTest.java b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/ReadMyWritesConsistencyTest.java new file mode 100644 index 0000000000000..fc7086a6e82da --- /dev/null +++ b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/ReadMyWritesConsistencyTest.java @@ -0,0 +1,226 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.TestConfigurations; +import com.beust.jcommander.JCommander; +import com.google.common.base.CaseFormat; +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ReadMyWritesConsistencyTest { + private final static Logger logger = LoggerFactory.getLogger(ReadMyWritesConsistencyTest.class); + private final int initialCollectionThroughput = 10_000; + private final int newCollectionThroughput = 100_000; + private final int delayForInitiationCollectionScaleUpInSeconds = 60; + private final Duration defaultMaxRunningTimeInSeconds = Duration.ofMinutes(45); + + private final String maxRunningTime = + System.getProperty("MAX_RUNNING_TIME", StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("MAX_RUNNING_TIME")), defaultMaxRunningTimeInSeconds.toString())); + + private final AtomicBoolean collectionScaleUpFailed = new AtomicBoolean(false); + private final String desiredConsistency = + System.getProperty("DESIRED_CONSISTENCY", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("DESIRED_CONSISTENCY")), "Session")); + + private final String numberOfOperationsAsString = + System.getProperty("NUMBER_OF_OPERATIONS", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("NUMBER_OF_OPERATIONS")), "-1")); + + private Database database; + private DocumentCollection collection; + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "e2e") + public void readMyWrites(boolean useNameLink) throws Exception { + int concurrency = 5; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel %s -concurrency %d" + + " -numberOfOperations %s" + + " -maxRunningTimeDuration %s" + + " -operation ReadMyWrites -connectionMode DIRECT -numberOfPreCreatedDocuments 100 " + + " -printingInterval 60"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, desiredConsistency), + concurrency, + numberOfOperationsAsString, + maxRunningTime) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + ReadMyWriteWorkflow wf = new ReadMyWriteWorkflow(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + // schedules a collection scale up after a delay + scheduleScaleUp(delayForInitiationCollectionScaleUpInSeconds, newCollectionThroughput); + + wf.run(); + wf.shutdown(); + + int numberOfOperations = Integer.parseInt(numberOfOperationsAsString); + + assertThat(error).hasValue(0); + assertThat(collectionScaleUpFailed).isFalse(); + + if (numberOfOperations > 0) { + assertThat(success).hasValue(numberOfOperations); + } + } + + @BeforeClass(groups = "e2e") + public void beforeClass() { + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(initialCollectionThroughput); + AsyncDocumentClient housekeepingClient = Utils.housekeepingClient(); + database = Utils.createDatabaseForTest(housekeepingClient); + collection = housekeepingClient.createCollection("dbs/" + database.id(), + getCollectionDefinitionWithRangeRangeIndex(), + options) + .single().block().getResource(); + housekeepingClient.close(); + } + + @DataProvider(name = "collectionLinkTypeArgProvider") + public Object[][] collectionLinkTypeArgProvider() { + return new Object[][]{ + // is namebased + {true}, + }; + } + + @AfterClass(groups = "e2e") + public void afterClass() { + AsyncDocumentClient housekeepingClient = Utils.housekeepingClient(); + Utils.safeCleanDatabases(housekeepingClient); + Utils.safeClean(housekeepingClient, database); + Utils.safeClose(housekeepingClient); + } + + DocumentCollection getCollectionDefinitionWithRangeRangeIndex() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.setIndexingPolicy(indexingPolicy); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + private void scheduleScaleUp(int delayStartInSeconds, int newThroughput) { + AsyncDocumentClient housekeepingClient = Utils.housekeepingClient(); + Flux.just(0L).delayElements(Duration.ofSeconds(delayStartInSeconds), Schedulers.newSingle("ScaleUpThread")).flatMap(aVoid -> { + + // increase throughput to max for a single partition collection to avoid throttling + // for bulk insert and later queries. + return housekeepingClient.queryOffers( + String.format("SELECT * FROM r WHERE r.offerResourceId = '%s'", + collection.resourceId()) + , null).flatMap(page -> Flux.fromIterable(page.results())) + .take(1).flatMap(offer -> { + logger.info("going to scale up collection, newThroughput {}", newThroughput); + offer.setThroughput(newThroughput); + return housekeepingClient.replaceOffer(offer); + }); + }).doOnTerminate(housekeepingClient::close) + .subscribe(aVoid -> { + }, e -> { + logger.error("collectionScaleUpFailed to scale up collection", e); + collectionScaleUpFailed.set(true); + }, + () -> { + logger.info("Collection Scale up request sent to the service"); + + } + ); + } +} \ No newline at end of file diff --git a/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/Utils.java b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/Utils.java new file mode 100644 index 0000000000000..641f85e3753a2 --- /dev/null +++ b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/Utils.java @@ -0,0 +1,143 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DatabaseForTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.RetryOptions; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.TestConfigurations; +import reactor.core.publisher.Flux; + +public class Utils { + public static AsyncDocumentClient housekeepingClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + RetryOptions options = new RetryOptions(); + options.maxRetryAttemptsOnThrottledRequests(100); + options.maxRetryWaitTimeInSeconds(60); + connectionPolicy.retryOptions(options); + return new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + } + + public static String getCollectionLink(Database db, DocumentCollection collection) { + return "dbs/" + db.id() + "/colls/" + collection; + } + + public static Database createDatabaseForTest(AsyncDocumentClient client) { + return DatabaseForTest.create(DatabaseManagerImpl.getInstance(client)).createdDatabase; + } + + public static void safeCleanDatabases(AsyncDocumentClient client) { + if (client != null) { + DatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(client)); + } + } + + public static void safeClean(AsyncDocumentClient client, Database database) { + if (database != null) { + safeClean(client, database.id()); + } + } + + public static void safeClean(AsyncDocumentClient client, String databaseId) { + if (client != null) { + if (databaseId != null) { + try { + client.deleteDatabase("/dbs/" + databaseId, null).then().block(); + } catch (Exception e) { + } + } + } + } + + public static String generateDatabaseId() { + return DatabaseForTest.generateId(); + } + + public static void safeClose(AsyncDocumentClient client) { + if (client != null) { + client.close(); + } + } + + private static class DatabaseManagerImpl implements DatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(AsyncDocumentClient client) { + return new DatabaseManagerImpl(client); + } + + private final AsyncDocumentClient client; + + private DatabaseManagerImpl(AsyncDocumentClient client) { + this.client = client; + } + + @Override + public Flux> queryDatabases(SqlQuerySpec query) { + return client.queryDatabases(query, null); + } + + @Override + public Flux> createDatabase(Database databaseDefinition) { + return client.createDatabase(databaseDefinition, null); + } + + @Override + public Flux> deleteDatabase(String id) { + + return client.deleteDatabase("dbs/" + id, null); + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/WorkflowTest.java b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/WorkflowTest.java new file mode 100644 index 0000000000000..57e611fec82cd --- /dev/null +++ b/sdk/cosmos/benchmark/src/test/java/com/azure/data/cosmos/benchmark/WorkflowTest.java @@ -0,0 +1,350 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.benchmark; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.TestConfigurations; +import com.beust.jcommander.JCommander; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WorkflowTest { + private static final int TIMEOUT = 120_000; // 2 minutes + private Database database; + private DocumentCollection collection; + + @Test(groups = "simple", timeOut = TIMEOUT) + public void readMyWritesCLI() throws Exception { + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations 123" + + " -operation ReadMyWrites -connectionMode DIRECT -numberOfPreCreatedDocuments 100"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id()); + Main.main(StringUtils.split(cmd)); + } + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "simple", timeOut = TIMEOUT) + public void readMyWrites(boolean useNameLink) throws Exception { + int numberOfOperations = 123; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations %s" + + " -operation ReadMyWrites -connectionMode DIRECT -numberOfPreCreatedDocuments 100"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + numberOfOperations) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + ReadMyWriteWorkflow wf = new ReadMyWriteWorkflow(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + wf.run(); + wf.shutdown(); + + assertThat(error).hasValue(0); + assertThat(success).hasValue(numberOfOperations); + } + + @Test(groups = "simple", timeOut = TIMEOUT) + public void writeLatencyCLI() throws Exception { + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations 1000" + + " -operation WriteLatency -connectionMode DIRECT"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id()); + Main.main(StringUtils.split(cmd)); + } + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "simple", timeOut = TIMEOUT) + public void writeLatency(boolean useNameLink) throws Exception { + int numberOfOperations = 123; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations %s" + + " -operation WriteLatency -connectionMode DIRECT"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + numberOfOperations) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + AsyncWriteBenchmark wf = new AsyncWriteBenchmark(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + wf.run(); + wf.shutdown(); + + assertThat(error).hasValue(0); + assertThat(success).hasValue(numberOfOperations); + } + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "simple", timeOut = TIMEOUT) + public void writeThroughput(boolean useNameLink) throws Exception { + int numberOfOperations = 123; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations %s" + + " -operation WriteThroughput -connectionMode DIRECT"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + numberOfOperations) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + AsyncWriteBenchmark wf = new AsyncWriteBenchmark(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + wf.run(); + wf.shutdown(); + + assertThat(error).hasValue(0); + assertThat(success).hasValue(numberOfOperations); + } + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "simple", timeOut = TIMEOUT) + public void readLatency(boolean useNameLink) throws Exception { + int numberOfOperations = 123; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations %s" + + " -operation ReadLatency -connectionMode DIRECT"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + numberOfOperations) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + AsyncReadBenchmark wf = new AsyncReadBenchmark(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + wf.run(); + wf.shutdown(); + + assertThat(error).hasValue(0); + assertThat(success).hasValue(numberOfOperations); + } + + @Test(dataProvider = "collectionLinkTypeArgProvider", groups = "simple", timeOut = TIMEOUT) + public void readThroughput(boolean useNameLink) throws Exception { + int numberOfOperations = 123; + String cmdFormat = "-serviceEndpoint %s -masterKey %s" + + " -databaseId %s -collectionId %s" + + " -consistencyLevel SESSION -concurrency 2 -numberOfOperations %s" + + " -operation ReadThroughput -connectionMode DIRECT"; + + String cmd = String.format(cmdFormat, + TestConfigurations.HOST, + TestConfigurations.MASTER_KEY, + database.id(), + collection.id(), + numberOfOperations) + + (useNameLink ? " -useNameLink" : ""); + + Configuration cfg = new Configuration(); + new JCommander(cfg, StringUtils.split(cmd)); + + AtomicInteger success = new AtomicInteger(); + AtomicInteger error = new AtomicInteger(); + + AsyncReadBenchmark wf = new AsyncReadBenchmark(cfg) { + @Override + protected void onError(Throwable throwable) { + error.incrementAndGet(); + } + + @Override + protected void onSuccess() { + success.incrementAndGet(); + } + }; + + wf.run(); + wf.shutdown(); + + assertThat(error).hasValue(0); + assertThat(success).hasValue(numberOfOperations); + } + + @BeforeClass(groups = "simple", timeOut = TIMEOUT) + public void beforeClass() { + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10000); + AsyncDocumentClient housekeepingClient = Utils.housekeepingClient(); + database = Utils.createDatabaseForTest(housekeepingClient); + collection = housekeepingClient.createCollection("dbs/"+ database.id(), + getCollectionDefinitionWithRangeRangeIndex(), + options) + .single().block().getResource(); + housekeepingClient.close(); + } + + @DataProvider(name = "collectionLinkTypeArgProvider") + public Object[][] collectionLinkTypeArgProvider() { + return new Object[][]{ + // is namebased + {true}, + {false}, + }; + } + + @AfterClass(groups = "simple", timeOut = TIMEOUT) + public void afterClass() { + AsyncDocumentClient housekeepingClient = Utils.housekeepingClient(); + Utils.safeCleanDatabases(housekeepingClient); + Utils.safeClean(housekeepingClient, database); + Utils.safeClose(housekeepingClient); + } + + DocumentCollection getCollectionDefinitionWithRangeRangeIndex() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.setIndexingPolicy(indexingPolicy); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } +} \ No newline at end of file diff --git a/sdk/cosmos/changelog/README.md b/sdk/cosmos/changelog/README.md new file mode 100644 index 0000000000000..7f145864521b5 --- /dev/null +++ b/sdk/cosmos/changelog/README.md @@ -0,0 +1,126 @@ +## Changelog + +### 2.4.3 + +- Fixed resource leak issue on closing client + +### 2.4.2 + +- Fixed bugs in continuation token support for cross partition queries + +### 2.4.1 + +- Fixed some bugs in Direct mode. +- Improved logging in Direct mode. +- Improved connection management. + +### 2.4.0 + +- Direct GA. +- Added support for QueryMetrics. +- Changed the APIs accepting java.util.Collection for which order is important to accept java.util.List instead. Now ConnectionPolicy#getPreferredLocations(), JsonSerialization, and PartitionKey(.) accept List. + +### 2.4.0-beta1 + +- Added support for Direct Https. +- Changed the APIs accepting java.util.Collection for which order is important to accept java.util.List instead. + Now ConnectionPolicy#getPreferredLocations(), JsonSerialization, and PartitionKey(.) accept List. +- Fixed a Session bug for Document query in Gateway mode. +- Upgraded dependencies (netty 0.4.20 [github #79](https://github.com/Azure/azure-cosmosdb-java/issues/79), RxJava 1.3.8). + +### 2.3.1 + +- Fix handling very large query responses. +- Fix resource token handling when instantiating client ([github #78](https://github.com/Azure/azure-cosmosdb-java/issues/78)). +- Upgraded vulnerable dependency jackson-databind ([github #77](https://github.com/Azure/azure-cosmosdb-java/pull/77)). + +### 2.3.0 + +- Fixed a resource leak bug. +- Added support for MultiPolygon +- Added support for custom headers in RequestOptions. + +### 2.2.2 + +- Fixed a packaging bug. + +### 2.2.1 + +- Fixed a NPE bug in write retry path. +- Fixed a NPE bug in endpoint management. +- Upgraded vulnerable dependencies ([github #68](https://github.com/Azure/azure-cosmosdb-java/issues/68)). +- Added support for Netty network logging for troubleshooting. + +### 2.2.0 + +- Added support for Multi-region write. + +### 2.1.0 + +- Added support for Proxy. +- Added support for resource token authorization. +- Fixed a bug in handling large partition keys ([github #63](https://github.com/Azure/azure-cosmosdb-java/issues/63)). +- Documentation improved. +- SDK restructured into more granular modules. + +### 2.0.1 + +- Fixed a bug for non-english locales ([github #51](https://github.com/Azure/azure-cosmosdb-java/issues/51)). +- Added helper methods for Conflict resource. + +### 2.0.0 + +- Replaced org.json dependency by jackson due to performance reasons and licensing ([github #29](https://github.com/Azure/azure-cosmosdb-java/issues/29)). +- Removed deprecated OfferV2 class. +- Added accessor method to Offer class for throughput content. +- Any method in Document/Resource returning org.json types changed to return a jackson object type. +- getObject(.) method of classes extending JsonSerializable changed to return a jackson ObjectNode type. +- getCollection(.) method changed to return Collection of ObjectNode. +- Removed JsonSerializable subclasses' constructors with org.json.JSONObject arg. +- JsonSerializable.toJson (SerializationFormattingPolicy.Indented) now uses two spaces for indentation. + +### 1.0.2 + +- Added support for Unique Index Policy. +- Added support for limiting response continuation token size in feed options. +- Added support for Partition Split in Cross Partition Query. +- Fixed a bug in Json timestamp serialization ([github #32](https://github.com/Azure/azure-cosmosdb-java/issues/32)). +- Fixed a bug in Json enum serialization. +- Fixed a bug in managing documents of 2MB size ([github #33](https://github.com/Azure/azure-cosmosdb-java/issues/33)). +- Dependency com.fasterxml.jackson.core:jackson-databind upgraded to 2.9.5 due to a bug ([jackson-databind: github #1599](https://github.com/FasterXML/jackson-databind/issues/1599)) +- Dependency on rxjava-extras upgraded to 0.8.0.17 due to a bug ([rxjava-extras: github #30](https://github.com/davidmoten/rxjava-extras/issues/30)). +- The metadata description in pom file updated to be inline with the rest of documentation. +- Syntax improvement ([github #41](https://github.com/Azure/azure-cosmosdb-java/issues/41)), ([github #40](https://github.com/Azure/azure-cosmosdb-java/issues/40)). + +### 1.0.1 + +- Added back-pressure support in query. +- Added support for partition key range id in query. +- Changed to allow larger continuation token in request header (bugfix github #24). +- netty dependency upgraded to 4.1.22.Final to ensure JVM shuts down after main thread finishes. +- Changed to avoid passing session token when reading master resources. +- Added more examples. +- Added more benchmarking scenarios. +- Fixed java header files for proper javadoc generation. + +### 1.0.0 + +- Release 1.0.0 has fully end to end support for non-blocking IO using netty library in Gateway mode. +- Dependency on `azure-documentdb` SDK removed. +- Artifact id changed to `azure-cosmosdb` from `azure-documentdb-rx` in 0.9.0-rc2. +- Java package name changed to `com.azure.data.cosmos` from `com.microsoft.azure.documentdb` in 0.9.0-rc2. + +### 0.9.0-rc2 + +- `FeedResponsePage` renamed to `FeedReponse` +- Some minor modifications to `ConnectionPolicy` configuration. + All time fields and methods in ConnectionPolicy suffixed with "InMillis" to be more precise of the time unit. +- `ConnectionPolicy#setProxy()` removed. +- `FeedOptions#pageSize` renamed to + `FeedOptions#maxItemCount` +- Release 1.0.0 deprecates 0.9.x releases. + +### 0.9.0-rc1 + +- First release of `azure-documentdb-rx` SDK. +- CRUD Document API fully non-blocking using netty. Query async API implemented as a wrapper using blocking SDK `azure-documentdb`. diff --git a/sdk/cosmos/examples/pom.xml b/sdk/cosmos/examples/pom.xml new file mode 100644 index 0000000000000..f7c52f9f530e5 --- /dev/null +++ b/sdk/cosmos/examples/pom.xml @@ -0,0 +1,159 @@ + + + + 4.0.0 + + com.microsoft.azure + azure-cosmos-parent + 3.0.0 + + + azure-cosmos-examples + Async SDK for SQL API of Azure Cosmos DB Service - Examples + Examples for Async SDK for SQL API of Azure Cosmos DB Service + + + UTF-8 + 1.7.6 + 1.2.17 + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.8 + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8 + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + com.azure.data.cosmos.benchmark.Main + + + + maven-assembly-plugin + 2.2 + + + jar-with-dependencies + + + + com.azure.data.cosmos.rx.examples.multimaster.samples.Main + + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + false + + + none + default-cli + + + + true + + + + + + + com.microsoft.azure + azure-cosmos + + + com.google.guava + guava + ${guava.version} + + + log4j + log4j + ${log4j.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.testng + testng + ${testng.version} + test + + + diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/AccountSettings.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/AccountSettings.java new file mode 100644 index 0000000000000..11b748b8710c3 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/AccountSettings.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.examples; + +import org.apache.commons.lang3.StringUtils; + +/** + * Contains the account configurations for Sample. + * + * For running tests, you can pass a customized endpoint configuration in one of the following + * ways: + *

      + *
    • -DACCOUNT_KEY="[your-key]" -ACCOUNT_HOST="[your-endpoint]" as JVM + * command-line option.
    • + *
    • You can set ACCOUNT_KEY and ACCOUNT_HOST as environment variables.
    • + *
    + * + * If none of the above is set, emulator endpoint will be used. + * Emulator http cert is self signed. If you are using emulator, + * make sure emulator https certificate is imported + * to java trusted cert store: + * https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator-export-ssl-certificates + */ +public class AccountSettings { + // REPLACE MASTER_KEY and HOST with values from your Azure Cosmos DB account. + // The default values are credentials of the local emulator, which are not used in any production environment. + public static String MASTER_KEY = + System.getProperty("ACCOUNT_KEY", + StringUtils.defaultString(StringUtils.trimToNull( + System.getenv().get("COSMOS_ACCOUNT_KEY")), + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==")); + + public static String HOST = + System.getProperty("ACCOUNT_HOST", + StringUtils.defaultString(StringUtils.trimToNull( + System.getenv().get("COSMOS_ACCOUNT_HOST")), + "https://localhost:8081/")); +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/BasicDemo.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/BasicDemo.java new file mode 100644 index 0000000000000..5af0ed8f6febd --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/BasicDemo.java @@ -0,0 +1,223 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.examples; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +public class BasicDemo { + + private static final String DATABASE_NAME = "test_db"; + private static final String CONTAINER_NAME = "test_container"; + + private CosmosClient client; + private CosmosDatabase database; + private CosmosContainer container; + + public static void main(String[] args) { + BasicDemo demo = new BasicDemo(); + demo.start(); + } + + private void start(){ + // Get client + client = CosmosClient.builder() + .endpoint(AccountSettings.HOST) + .key(AccountSettings.MASTER_KEY) + .build(); + + //CREATE a database and a container + createDbAndContainerBlocking(); + + //Get a proxy reference to container + container = client.getDatabase(DATABASE_NAME).getContainer(CONTAINER_NAME); + + CosmosContainer container = client.getDatabase(DATABASE_NAME).getContainer(CONTAINER_NAME); + TestObject testObject = new TestObject("item_new_id_1", "test", "test description", "US"); + TestObject testObject2 = new TestObject("item_new_id_2", "test2", "test description2", "CA"); + + //CREATE an Item async + Mono itemResponseMono = container.createItem(testObject); + //CREATE another Item async + Mono itemResponseMono1 = container.createItem(testObject2); + + //Wait for completion + try { + itemResponseMono.doOnError(throwable -> log("CREATE item 1", throwable)) + .mergeWith(itemResponseMono1) + .doOnError(throwable -> log("CREATE item 2 ", throwable)) + .doOnComplete(() -> log("Items created")) + .publishOn(Schedulers.elastic()) + .blockLast(); + }catch (RuntimeException e){ + log("Couldn't create items due to above exceptions"); + } + + createAndReplaceItem(); + + queryItems(); + + queryWithContinuationToken(); + + //Close client + client.close(); + log("Completed"); + } + + private void createAndReplaceItem() { + TestObject replaceObject = new TestObject("item_new_id_3", "test3", "test description3", "JP"); + CosmosItem cosmosItem = null; + //CREATE item sync + try { + cosmosItem = container.createItem(replaceObject) + .doOnError(throwable -> log("CREATE 3", throwable)) + .publishOn(Schedulers.elastic()) + .block() + .item(); + }catch (RuntimeException e){ + log("Couldn't create items due to above exceptions"); + } + if(cosmosItem != null) { + replaceObject.setName("new name test3"); + + //REPLACE the item and wait for completion + cosmosItem.replace(replaceObject).block(); + } + } + + private void createDbAndContainerBlocking() { + client.createDatabaseIfNotExists(DATABASE_NAME) + .doOnSuccess(cosmosDatabaseResponse -> log("Database: " + cosmosDatabaseResponse.database().id())) + .flatMap(dbResponse -> dbResponse.database().createContainerIfNotExists(new CosmosContainerProperties(CONTAINER_NAME, "/country"))) + .doOnSuccess(cosmosContainerResponse -> log("Container: " + cosmosContainerResponse.container().id())) + .doOnError(throwable -> log(throwable.getMessage())) + .publishOn(Schedulers.elastic()) + .block(); + } + + int count = 0; + private void queryItems(){ + log("+ Querying the collection "); + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(2); + Flux> queryFlux = container.queryItems(query, options); + + queryFlux.publishOn(Schedulers.elastic()).subscribe(cosmosItemFeedResponse -> {}, + throwable -> {}, + () -> {}); + + queryFlux.publishOn(Schedulers.elastic()) + .toIterable() + .forEach(cosmosItemFeedResponse -> + { + log(cosmosItemFeedResponse.results()); + }); + + } + + private void queryWithContinuationToken(){ + log("+ Query with paging using continuation token"); + String query = "SELECT * from root r "; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(true); + options.maxItemCount(1); + String continuation = null; + do{ + options.requestContinuation(continuation); + Flux> queryFlux = container.queryItems(query, options); + FeedResponse page = queryFlux.blockFirst(); + assert page != null; + log(page.results()); + continuation = page.continuationToken(); + }while(continuation!= null); + + } + + private void log(Object object) { + System.out.println(object); + } + + private void log(String msg, Throwable throwable){ + log(msg + ": " + ((CosmosClientException)throwable).statusCode()); + } + + class TestObject { + String id; + String name; + String description; + String country; + + public TestObject(String id, String name, String description, String country) { + this.id = id; + this.name = name; + this.description = description; + this.country = country; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleChangeFeedProcessor.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleChangeFeedProcessor.java new file mode 100644 index 0000000000000..9267879f9e0f2 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleChangeFeedProcessor.java @@ -0,0 +1,254 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.examples.ChangeFeed; + +import com.azure.data.cosmos.ChangeFeedProcessor; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerResponse; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.SerializationFormattingPolicy; +import org.apache.commons.lang3.RandomStringUtils; + +import java.time.Duration; + +/** + * Sample for Change Feed Processor. + * + */ +public class SampleChangeFeedProcessor { + + public static int WAIT_FOR_WORK = 60; + public static final String DATABASE_NAME = "db_" + RandomStringUtils.randomAlphabetic(7); + public static final String COLLECTION_NAME = "coll_" + RandomStringUtils.randomAlphabetic(7); + + private static ChangeFeedProcessor changeFeedProcessorInstance; + private static boolean isWorkCompleted = false; + + public static void main (String[]args) { + System.out.println("BEGIN Sample"); + + try { + + System.out.println("-->CREATE DocumentClient"); + CosmosClient client = getCosmosClient(); + + System.out.println("-->CREATE sample's database: " + DATABASE_NAME); + CosmosDatabase cosmosDatabase = createNewDatabase(client, DATABASE_NAME); + + System.out.println("-->CREATE container for documents: " + COLLECTION_NAME); + CosmosContainer feedContainer = createNewCollection(client, DATABASE_NAME, COLLECTION_NAME); + + System.out.println("-->CREATE container for lease: " + COLLECTION_NAME + "-leases"); + CosmosContainer leaseContainer = createNewLeaseCollection(client, DATABASE_NAME, COLLECTION_NAME + "-leases"); + + changeFeedProcessorInstance = getChangeFeedProcessor("SampleHost_1", feedContainer, leaseContainer); + + changeFeedProcessorInstance.start().subscribe(aVoid -> { + createNewDocuments(feedContainer, 10, Duration.ofSeconds(3)); + isWorkCompleted = true; + }); + + long remainingWork = WAIT_FOR_WORK; + while (!isWorkCompleted && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + + if (isWorkCompleted) { + if (changeFeedProcessorInstance != null) { + changeFeedProcessorInstance.stop().subscribe().wait(10000); + } + } else { + throw new RuntimeException("The change feed processor initialization and automatic create document feeding process did not complete in the expected time"); + } + + System.out.println("-->DELETE sample's database: " + DATABASE_NAME); + deleteDatabase(cosmosDatabase); + + Thread.sleep(500); + + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("END Sample"); + System.exit(0); + } + + public static ChangeFeedProcessor getChangeFeedProcessor(String hostName, CosmosContainer feedContainer, CosmosContainer leaseContainer) { + return ChangeFeedProcessor.Builder() + .hostName(hostName) + .feedContainer(feedContainer) + .leaseContainer(leaseContainer) + .handleChanges(docs -> { + System.out.println("--->handleChanges() START"); + + for (CosmosItemProperties document : docs) { + System.out.println("---->DOCUMENT RECEIVED: " + document.toJson(SerializationFormattingPolicy.INDENTED)); + } + System.out.println("--->handleChanges() END"); + + }) + .build(); + } + + public static CosmosClient getCosmosClient() { + + return CosmosClient.builder() + .endpoint(SampleConfigurations.HOST) + .key(SampleConfigurations.MASTER_KEY) + .connectionPolicy(ConnectionPolicy.defaultPolicy()) + .consistencyLevel(ConsistencyLevel.EVENTUAL) + .build(); + } + + public static CosmosDatabase createNewDatabase(CosmosClient client, String databaseName) { + return client.createDatabaseIfNotExists(databaseName).block().database(); + } + + public static void deleteDatabase(CosmosDatabase cosmosDatabase) { + cosmosDatabase.delete().block(); + } + + public static CosmosContainer createNewCollection(CosmosClient client, String databaseName, String collectionName) { + CosmosDatabase databaseLink = client.getDatabase(databaseName); + CosmosContainer collectionLink = databaseLink.getContainer(collectionName); + CosmosContainerResponse containerResponse = null; + + try { + containerResponse = collectionLink.read().block(); + + if (containerResponse != null) { + throw new IllegalArgumentException(String.format("Collection %s already exists in database %s.", collectionName, databaseName)); + } + } catch (RuntimeException ex) { + if (ex.getCause() instanceof CosmosClientException) { + CosmosClientException cosmosClientException = (CosmosClientException) ex.getCause(); + + if (cosmosClientException.statusCode() != 404) { + throw ex; + } + } else { + throw ex; + } + } + + CosmosContainerProperties containerSettings = new CosmosContainerProperties(collectionName, "/id"); + + CosmosContainerRequestOptions requestOptions = new CosmosContainerRequestOptions(); + + containerResponse = databaseLink.createContainer(containerSettings, 10000, requestOptions).block(); + + if (containerResponse == null) { + throw new RuntimeException(String.format("Failed to create collection %s in database %s.", collectionName, databaseName)); + } + + return containerResponse.container(); + } + + public static CosmosContainer createNewLeaseCollection(CosmosClient client, String databaseName, String leaseCollectionName) { + CosmosDatabase databaseLink = client.getDatabase(databaseName); + CosmosContainer leaseCollectionLink = databaseLink.getContainer(leaseCollectionName); + CosmosContainerResponse leaseContainerResponse = null; + + try { + leaseContainerResponse = leaseCollectionLink.read().block(); + + if (leaseContainerResponse != null) { + leaseCollectionLink.delete().block(); + + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + } catch (RuntimeException ex) { + if (ex.getCause() instanceof CosmosClientException) { + CosmosClientException cosmosClientException = (CosmosClientException) ex.getCause(); + + if (cosmosClientException.statusCode() != 404) { + throw ex; + } + } else { + throw ex; + } + } + + CosmosContainerProperties containerSettings = new CosmosContainerProperties(leaseCollectionName, "/id"); + CosmosContainerRequestOptions requestOptions = new CosmosContainerRequestOptions(); + + leaseContainerResponse = databaseLink.createContainer(containerSettings, 400,requestOptions).block(); + + if (leaseContainerResponse == null) { + throw new RuntimeException(String.format("Failed to create collection %s in database %s.", leaseCollectionName, databaseName)); + } + + return leaseContainerResponse.container(); + } + + public static void createNewDocuments(CosmosContainer containerClient, int count, Duration delay) { + String suffix = RandomStringUtils.randomAlphabetic(10); + for (int i = 0; i <= count; i++) { + CosmosItemProperties document = new CosmosItemProperties(); + document.id(String.format("0%d-%s", i, suffix)); + + containerClient.createItem(document).subscribe(doc -> { + System.out.println("---->DOCUMENT WRITE: " + doc.properties().toJson(SerializationFormattingPolicy.INDENTED)); + }); + + long remainingWork = delay.toMillis(); + try { + while (remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException iex) { + // exception caught + break; + } + } + } + + public static boolean ensureWorkIsDone(Duration delay) { + long remainingWork = delay.toMillis(); + try { + while (!isWorkCompleted && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException iex) { + return false; + } + + return remainingWork > 0; + } + +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleConfigurations.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleConfigurations.java new file mode 100644 index 0000000000000..9657dc22363ee --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/examples/ChangeFeed/SampleConfigurations.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.examples.ChangeFeed; + +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; + +/** + * Contains the configurations for tests. + *

    + * For running tests, you can pass a customized endpoint configuration in one of the following + * ways: + *

      + *
    • -DACCOUNT_KEY="[your-key]" -ACCOUNT_HOST="[your-endpoint]" as JVM + * command-line option.
    • + *
    • You can set ACCOUNT_KEY and ACCOUNT_HOST as environment variables.
    • + *
    + *

    + * If none of the above is set, emulator endpoint will be used. + */ +public final class SampleConfigurations { + // REPLACE MASTER_KEY and HOST with values from your Azure Cosmos DB account. + // The default values are credentials of the local emulator, which are not used in any production environment. + // + public static String MASTER_KEY = + System.getProperty("ACCOUNT_KEY", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_KEY")), + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==")); + + public static String HOST = + System.getProperty("ACCOUNT_HOST", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_HOST")), + "https://localhost:8081/")); +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/ConfigurationManager.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/ConfigurationManager.java new file mode 100644 index 0000000000000..4651739076c90 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/ConfigurationManager.java @@ -0,0 +1,32 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster; + +import java.util.Properties; + +public class ConfigurationManager { + public static Properties getAppSettings() { + return System.getProperties(); + } +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/Helpers.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/Helpers.java new file mode 100644 index 0000000000000..b6a02833768b2 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/Helpers.java @@ -0,0 +1,104 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.ResourceResponse; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class Helpers { + + static public String createDocumentCollectionUri(String databaseName, String collectionName) { + return String.format("/dbs/%s/colls/%s", databaseName, collectionName); + } + + static public String createDatabaseUri(String databaseName) { + return String.format("/dbs/%s", databaseName); + } + + static public Mono createDatabaseIfNotExists(AsyncDocumentClient client, String databaseName) { + + return client.readDatabase("/dbs/" + databaseName, null) + .onErrorResume( + e -> { + if (e instanceof CosmosClientException) { + CosmosClientException dce = (CosmosClientException) e; + if (dce.statusCode() == 404) { + // if doesn't exist create it + + Database d = new Database(); + d.id(databaseName); + + return client.createDatabase(d, null); + } + } + + return Flux.error(e); + } + ).map(ResourceResponse::getResource).single(); + } + + static public Mono createCollectionIfNotExists(AsyncDocumentClient client, String databaseName, String collectionName) { + return client.readCollection(createDocumentCollectionUri(databaseName, collectionName), null) + .onErrorResume( + e -> { + if (e instanceof CosmosClientException) { + CosmosClientException dce = (CosmosClientException) e; + if (dce.statusCode() == 404) { + // if doesn't exist create it + + DocumentCollection collection = new DocumentCollection(); + collection.id(collectionName); + + return client.createCollection(createDatabaseUri(databaseName), collection, null); + } + } + + return Flux.error(e); + } + ).map(ResourceResponse::getResource).single(); + } + + static public Mono createCollectionIfNotExists(AsyncDocumentClient client, String databaseName, DocumentCollection collection) { + return client.readCollection(createDocumentCollectionUri(databaseName, collection.id()), null) + .onErrorResume( + e -> { + if (e instanceof CosmosClientException) { + CosmosClientException dce = (CosmosClientException) e; + if (dce.statusCode() == 404) { + // if doesn't exist create it + + return client.createCollection(createDatabaseUri(databaseName), collection, null); + } + } + + return Flux.error(e); + } + ).map(ResourceResponse::getResource).single(); + } +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/ConflictWorker.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/ConflictWorker.java new file mode 100644 index 0000000000000..720bc936b0ecf --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/ConflictWorker.java @@ -0,0 +1,877 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster.samples; + +import com.azure.data.cosmos.AccessCondition; +import com.azure.data.cosmos.AccessConditionType; +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.ConflictResolutionPolicy; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.rx.examples.multimaster.Helpers; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class ConflictWorker { + private static Logger logger = LoggerFactory.getLogger(ConflictWorker.class); + + private final Scheduler schedulerForBlockingWork; + private final List clients; + private final String basicCollectionUri; + private final String manualCollectionUri; + private final String lwwCollectionUri; + private final String udpCollectionUri; + private final String databaseName; + private final String basicCollectionName; + private final String manualCollectionName; + private final String lwwCollectionName; + private final String udpCollectionName; + private final ExecutorService executor; + + public ConflictWorker(String databaseName, String basicCollectionName, String manualCollectionName, String lwwCollectionName, String udpCollectionName) { + this.clients = new ArrayList<>(); + this.basicCollectionUri = Helpers.createDocumentCollectionUri(databaseName, basicCollectionName); + this.manualCollectionUri = Helpers.createDocumentCollectionUri(databaseName, manualCollectionName); + this.lwwCollectionUri = Helpers.createDocumentCollectionUri(databaseName, lwwCollectionName); + this.udpCollectionUri = Helpers.createDocumentCollectionUri(databaseName, udpCollectionName); + + this.databaseName = databaseName; + this.basicCollectionName = basicCollectionName; + this.manualCollectionName = manualCollectionName; + this.lwwCollectionName = lwwCollectionName; + this.udpCollectionName = udpCollectionName; + + this.executor = Executors.newFixedThreadPool(100); + this.schedulerForBlockingWork = Schedulers.fromExecutor(executor); + } + + public void addClient(AsyncDocumentClient client) { + this.clients.add(client); + } + + private DocumentCollection createCollectionIfNotExists(AsyncDocumentClient createClient, String databaseName, DocumentCollection collection) { + return Helpers.createCollectionIfNotExists(createClient, this.databaseName, collection) + .subscribeOn(schedulerForBlockingWork).block(); + } + + private DocumentCollection createCollectionIfNotExists(AsyncDocumentClient createClient, String databaseName, String collectionName) { + + return Helpers.createCollectionIfNotExists(createClient, this.databaseName, this.basicCollectionName) + .subscribeOn(schedulerForBlockingWork).block(); + } + + private DocumentCollection getCollectionDefForManual(String id) { + DocumentCollection collection = new DocumentCollection(); + collection.id(id); + ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy(); + collection.setConflictResolutionPolicy(policy); + return collection; + } + + private DocumentCollection getCollectionDefForLastWinWrites(String id, String conflictResolutionPath) { + DocumentCollection collection = new DocumentCollection(); + collection.id(id); + ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy(conflictResolutionPath); + collection.setConflictResolutionPolicy(policy); + return collection; + } + + private DocumentCollection getCollectionDefForCustom(String id, String storedProc) { + DocumentCollection collection = new DocumentCollection(); + collection.id(id); + ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy(storedProc); + collection.setConflictResolutionPolicy(policy); + return collection; + } + + public void initialize() throws Exception { + AsyncDocumentClient createClient = this.clients.get(0); + + Helpers.createDatabaseIfNotExists(createClient, this.databaseName).subscribeOn(schedulerForBlockingWork).block(); + + DocumentCollection basic = createCollectionIfNotExists(createClient, this.databaseName, this.basicCollectionName); + + DocumentCollection manualCollection = createCollectionIfNotExists(createClient, + Helpers.createDatabaseUri(this.databaseName), getCollectionDefForManual(this.manualCollectionName)); + + DocumentCollection lwwCollection = createCollectionIfNotExists(createClient, + Helpers.createDatabaseUri(this.databaseName), getCollectionDefForLastWinWrites(this.lwwCollectionName, "/regionId")); + + DocumentCollection udpCollection = createCollectionIfNotExists(createClient, + Helpers.createDatabaseUri(this.databaseName), getCollectionDefForCustom(this.udpCollectionName, + String.format("dbs/%s/colls/%s/sprocs/%s", this.databaseName, this.udpCollectionName, "resolver"))); + + StoredProcedure lwwSproc = new StoredProcedure(); + lwwSproc.id("resolver"); + lwwSproc.setBody(IOUtils.toString( + getClass().getClassLoader().getResourceAsStream("resolver-storedproc.txt"), "UTF-8")); + + lwwSproc = + getResource(createClient.upsertStoredProcedure( + Helpers.createDocumentCollectionUri(this.databaseName, this.udpCollectionName), lwwSproc, null)); + + } + + private T getResource(Flux> obs) { + return obs.subscribeOn(schedulerForBlockingWork).single().block().getResource(); + } + + public void runManualConflict() throws Exception { + logger.info("\r\nInsert Conflict\r\n"); + this.runInsertConflictOnManual(); + + logger.info("\r\nUPDATE Conflict\r\n"); + this.runUpdateConflictOnManual(); + + logger.info("\r\nDELETE Conflict\r\n"); + this.runDeleteConflictOnManual(); + } + + public void runLWWConflict() throws Exception { + logger.info("\r\nInsert Conflict\r\n"); + this.runInsertConflictOnLWW(); + + logger.info("\r\nUPDATE Conflict\r\n"); + this.runUpdateConflictOnLWW(); + + logger.info("\r\nDELETE Conflict\r\n"); + this.runDeleteConflictOnLWW(); + } + + public void runUDPConflict() throws Exception { + logger.info("\r\nInsert Conflict\r\n"); + this.runInsertConflictOnUdp(); + + logger.info("\r\nUPDATE Conflict\r\n"); + this.runUpdateConflictOnUdp(); + + logger.info("\r\nDELETE Conflict\r\n"); + this.runDeleteConflictOnUdp(); + } + + public void runInsertConflictOnManual() throws Exception { + do { + logger.info("1) Performing conflicting insert across {} regions on {}", this.clients.size(), this.manualCollectionName); + + ArrayList> insertTask = new ArrayList<>(); + + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + insertTask.add(this.tryInsertDocument(client, this.manualCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(insertTask).collectList().subscribeOn(schedulerForBlockingWork).single().block(); + + if (conflictDocuments.size() == this.clients.size()) { + logger.info("2) Caused {} insert conflicts, verifying conflict resolution", conflictDocuments.size()); + + for (Document conflictingInsert : conflictDocuments) { + this.validateManualConflict(this.clients, conflictingInsert); + } + break; + } else { + logger.info("Retrying insert to induce conflicts"); + } + } while (true); + } + + public void runUpdateConflictOnManual() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + + conflictDocument = this.tryInsertDocument(clients.get(0), this.manualCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + TimeUnit.SECONDS.sleep(1);//1 Second for write to sync. + + + logger.info("1) Performing conflicting update across 3 regions on {}", this.manualCollectionName); + + ArrayList> updateTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + updateTask.add(this.tryUpdateDocument(client, this.manualCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(updateTask).collectList().single().block(); + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} updated conflicts, verifying conflict resolution", conflictDocuments.size()); + + for (Document conflictingUpdate : conflictDocuments) { + this.validateManualConflict(this.clients, conflictingUpdate); + } + break; + } else { + logger.info("Retrying update to induce conflicts"); + } + } while (true); + } + + public void runDeleteConflictOnManual() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + conflictDocument = this.tryInsertDocument(clients.get(0), this.manualCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + TimeUnit.SECONDS.sleep(10);//1 Second for write to sync. + + logger.info("1) Performing conflicting delete across 3 regions on {}", this.manualCollectionName); + + ArrayList> deleteTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + deleteTask.add(this.tryDeleteDocument(client, this.manualCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(deleteTask).collectList() + .subscribeOn(schedulerForBlockingWork) + .single().block(); + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} delete conflicts, verifying conflict resolution", conflictDocuments.size()); + + for (Document conflictingDelete : conflictDocuments) { + this.validateManualConflict(this.clients, conflictingDelete); + } + + break; + } else { + logger.info("Retrying update to induce conflicts"); + } + } while (true); + } + + public void runInsertConflictOnLWW() throws Exception { + do { + logger.info("Performing conflicting insert across 3 regions"); + + ArrayList> insertTask = new ArrayList<>(); + + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + insertTask.add(this.tryInsertDocument(client, this.lwwCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(insertTask).collectList().single().block(); + + + if (conflictDocuments.size() > 1) { + logger.info("Inserted {} conflicts, verifying conflict resolution", conflictDocuments.size()); + + this.validateLWW(this.clients, conflictDocuments); + + break; + } else { + logger.info("Retrying insert to induce conflicts"); + } + } while (true); + } + + public void runUpdateConflictOnLWW() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + conflictDocument = this.tryInsertDocument(clients.get(0), this.lwwCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + + TimeUnit.SECONDS.sleep(1); //1 Second for write to sync. + + logger.info("1) Performing conflicting update across {} regions on {}", this.clients.size(), this.lwwCollectionUri); + + ArrayList> insertTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + insertTask.add(this.tryUpdateDocument(client, this.lwwCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(insertTask).collectList().single().block(); + + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} update conflicts, verifying conflict resolution", conflictDocuments.size()); + + this.validateLWW(this.clients, conflictDocuments); + + break; + } else { + logger.info("Retrying insert to induce conflicts"); + } + } while (true); + } + + public void runDeleteConflictOnLWW() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + conflictDocument = this.tryInsertDocument(clients.get(0), this.lwwCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + + TimeUnit.SECONDS.sleep(1); //1 Second for write to sync. + + logger.info("1) Performing conflicting delete across {} regions on {}", this.clients.size(), this.lwwCollectionUri); + + ArrayList> insertTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + if (index % 2 == 1) { + //We delete from region 1, even though region 2 always win. + insertTask.add(this.tryDeleteDocument(client, this.lwwCollectionUri, conflictDocument, index++)); + } else { + insertTask.add(this.tryUpdateDocument(client, this.lwwCollectionUri, conflictDocument, index++)); + } + } + + List conflictDocuments = Flux.merge(insertTask).collectList().single().block(); + + if (conflictDocuments.size() > 1) { + logger.info("Inserted {} conflicts, verifying conflict resolution", conflictDocuments.size()); + + //DELETE should always win. irrespective of LWW. + this.validateLWW(this.clients, conflictDocuments, true); + break; + } else { + logger.info("Retrying update/delete to induce conflicts"); + } + } while (true); + } + + public void runInsertConflictOnUdp() throws Exception { + do { + logger.info("1) Performing conflicting insert across 3 regions on {}", this.udpCollectionName); + + ArrayList> insertTask = new ArrayList<>(); + + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + insertTask.add(this.tryInsertDocument(client, this.udpCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(insertTask).collectList().single().block(); + + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} insert conflicts, verifying conflict resolution", conflictDocuments.size()); + + this.validateUDPAsync(this.clients, conflictDocuments); + + break; + } else { + logger.info("Retrying insert to induce conflicts"); + } + } while (true); + } + + public void runUpdateConflictOnUdp() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + conflictDocument = this.tryInsertDocument(clients.get(0), this.udpCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + TimeUnit.SECONDS.sleep(1); //1 Second for write to sync. + + logger.info("1) Performing conflicting update across 3 regions on {}", this.udpCollectionUri); + + ArrayList> updateTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + updateTask.add(this.tryUpdateDocument(client, this.udpCollectionUri, conflictDocument, index++)); + } + + List conflictDocuments = Flux.merge(updateTask).collectList().single().block(); + + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} update conflicts, verifying conflict resolution", conflictDocuments.size()); + + this.validateUDPAsync(this.clients, conflictDocuments); + + break; + } else { + logger.info("Retrying update to induce conflicts"); + } + } while (true); + } + + public void runDeleteConflictOnUdp() throws Exception { + do { + Document conflictDocument = new Document(); + conflictDocument.id(UUID.randomUUID().toString()); + + conflictDocument = this.tryInsertDocument(clients.get(0), this.udpCollectionUri, conflictDocument, 0) + .singleOrEmpty().block(); + + TimeUnit.SECONDS.sleep(1); //1 Second for write to sync. + + logger.info("1) Performing conflicting update/delete across 3 regions on {}", this.udpCollectionUri); + + ArrayList> deleteTask = new ArrayList<>(); + + int index = 0; + for (AsyncDocumentClient client : this.clients) { + if (index % 2 == 1) { + //We delete from region 1, even though region 2 always win. + deleteTask.add(this.tryDeleteDocument(client, this.udpCollectionUri, conflictDocument, index++)); + } else { + deleteTask.add(this.tryUpdateDocument(client, this.udpCollectionUri, conflictDocument, index++)); + } + } + + List conflictDocuments = Flux.merge(deleteTask).collectList().single().block(); + + if (conflictDocuments.size() > 1) { + logger.info("2) Caused {} delete conflicts, verifying conflict resolution", conflictDocuments.size()); + + //DELETE should always win. irrespective of LWW. + this.validateUDPAsync(this.clients, conflictDocuments, true); + break; + } else { + logger.info("Retrying update/delete to induce conflicts"); + } + } while (true); + } + + private Flux tryInsertDocument(AsyncDocumentClient client, String collectionUri, Document document, int index) { + + logger.debug("region: {}", client.getWriteEndpoint()); + BridgeInternal.setProperty(document, "regionId", index); + BridgeInternal.setProperty(document, "regionEndpoint", client.getReadEndpoint()); + return client.createDocument(collectionUri, document, null, false) + .onErrorResume(e -> { + if (hasDocumentClientException(e, 409)) { + return Flux.empty(); + } else { + return Flux.error(e); + } + }).map(ResourceResponse::getResource); + } + + private boolean hasDocumentClientException(Throwable e, int statusCode) { + if (e instanceof CosmosClientException) { + CosmosClientException dce = (CosmosClientException) e; + return dce.statusCode() == statusCode; + } + + return false; + } + + private boolean hasDocumentClientExceptionCause(Throwable e) { + while (e != null) { + if (e instanceof CosmosClientException) { + return true; + } + + e = e.getCause(); + } + return false; + } + + private boolean hasDocumentClientExceptionCause(Throwable e, int statusCode) { + while (e != null) { + if (e instanceof CosmosClientException) { + CosmosClientException dce = (CosmosClientException) e; + return dce.statusCode() == statusCode; + } + + e = e.getCause(); + } + + return false; + } + + private Flux tryUpdateDocument(AsyncDocumentClient client, String collectionUri, Document document, int index) { + BridgeInternal.setProperty(document, "regionId", index); + BridgeInternal.setProperty(document, "regionEndpoint", client.getReadEndpoint()); + + RequestOptions options = new RequestOptions(); + options.setAccessCondition(new AccessCondition()); + options.getAccessCondition().type(AccessConditionType.IF_MATCH); + options.getAccessCondition().condition(document.etag()); + + + return client.replaceDocument(document.selfLink(), document, null).onErrorResume(e -> { + + // pre condition failed + if (hasDocumentClientException(e, 412)) { + //Lost synchronously or not document yet. No conflict is induced. + return Flux.empty(); + + } + return Flux.error(e); + }).map(ResourceResponse::getResource); + } + + private Flux tryDeleteDocument(AsyncDocumentClient client, String collectionUri, Document document, int index) { + BridgeInternal.setProperty(document, "regionId", index); + BridgeInternal.setProperty(document, "regionEndpoint", client.getReadEndpoint()); + + RequestOptions options = new RequestOptions(); + options.setAccessCondition(new AccessCondition()); + options.getAccessCondition().type(AccessConditionType.IF_MATCH); + options.getAccessCondition().condition(document.etag()); + + + return client.deleteDocument(document.selfLink(), options).onErrorResume(e -> { + + // pre condition failed + if (hasDocumentClientException(e, 412)) { + //Lost synchronously. No conflict is induced. + return Flux.empty(); + + } + return Flux.error(e); + }).map(rr -> document); + } + + private void validateManualConflict(List clients, Document conflictDocument) throws Exception { + boolean conflictExists = false; + for (AsyncDocumentClient client : clients) { + conflictExists = this.validateManualConflict(client, conflictDocument); + } + + if (conflictExists) { + this.deleteConflict(conflictDocument); + } + } + + private boolean isDelete(Conflict conflict) { + return StringUtils.equalsIgnoreCase(conflict.getOperationKind(), "delete"); + } + + + private boolean equals(String a, String b) { + return StringUtils.equals(a, b); + } + + private boolean validateManualConflict(AsyncDocumentClient client, Document conflictDocument) throws Exception { + while (true) { + FeedResponse response = client.readConflicts(this.manualCollectionUri, null) + .take(1).single().block(); + + for (Conflict conflict : response.results()) { + if (!isDelete(conflict)) { + Document conflictDocumentContent = conflict.getResource(Document.class); + if (equals(conflictDocument.id(), conflictDocumentContent.id())) { + if (equals(conflictDocument.resourceId(), conflictDocumentContent.resourceId()) && + equals(conflictDocument.etag(), conflictDocumentContent.etag())) { + logger.info("Document from Region {} lost conflict @ {}", + conflictDocument.id(), + conflictDocument.getInt("regionId"), + client.getReadEndpoint()); + return true; + } else { + try { + //Checking whether this is the winner. + Document winnerDocument = client.readDocument(conflictDocument.selfLink(), null) + .single().block().getResource(); + logger.info("Document from region {} won the conflict @ {}", + conflictDocument.getInt("regionId"), + client.getReadEndpoint()); + return false; + } + catch (Exception exception) { + if (hasDocumentClientException(exception, 404)) { + throw exception; + } else { + logger.info( + "Document from region {} not found @ {}", + conflictDocument.getInt("regionId"), + client.getReadEndpoint()); + } + } + } + } + } else { + if (equals(conflict.getSourceResourceId(), conflictDocument.resourceId())) { + logger.info("DELETE conflict found @ {}", + client.getReadEndpoint()); + return false; + } + } + } + + logger.error("Document {} is not found in conflict feed @ {}, retrying", + conflictDocument.id(), + client.getReadEndpoint()); + + TimeUnit.MILLISECONDS.sleep(500); + } + } + + private void deleteConflict(Document conflictDocument) { + AsyncDocumentClient delClient = clients.get(0); + + FeedResponse conflicts = delClient.readConflicts(this.manualCollectionUri, null).take(1).single().block(); + + for (Conflict conflict : conflicts.results()) { + if (!isDelete(conflict)) { + Document conflictContent = conflict.getResource(Document.class); + if (equals(conflictContent.resourceId(), conflictDocument.resourceId()) + && equals(conflictContent.etag(), conflictDocument.etag())) { + logger.info("Deleting manual conflict {} from region {}", + conflict.getSourceResourceId(), + conflictContent.getInt("regionId")); + delClient.deleteConflict(conflict.selfLink(), null) + .single().block(); + + } + } else if (equals(conflict.getSourceResourceId(), conflictDocument.resourceId())) { + logger.info("Deleting manual conflict {} from region {}", + conflict.getSourceResourceId(), + conflictDocument.getInt("regionId")); + delClient.deleteConflict(conflict.selfLink(), null) + .single().block(); + } + } + } + + private void validateLWW(List clients, List conflictDocument) throws Exception { + validateLWW(clients, conflictDocument, false); + } + + + private void validateLWW(List clients, List conflictDocument, boolean hasDeleteConflict) throws Exception { + for (AsyncDocumentClient client : clients) { + this.validateLWW(client, conflictDocument, hasDeleteConflict); + } + } + + private void validateLWW(AsyncDocumentClient client, List conflictDocument, boolean hasDeleteConflict) throws Exception { + FeedResponse response = client.readConflicts(this.lwwCollectionUri, null) + .take(1).single().block(); + + if (response.results().size() != 0) { + logger.error("Found {} conflicts in the lww collection", response.results().size()); + return; + } + + if (hasDeleteConflict) { + do { + try { + client.readDocument(conflictDocument.get(0).selfLink(), null).single().block(); + + logger.error("DELETE conflict for document {} didnt win @ {}", + conflictDocument.get(0).id(), + client.getReadEndpoint()); + + TimeUnit.MILLISECONDS.sleep(500); + } catch (Exception exception) { + if (!hasDocumentClientExceptionCause(exception)) { + throw exception; + } + + // NotFound + if (hasDocumentClientExceptionCause(exception, 404)) { + + logger.info("DELETE conflict won @ {}", client.getReadEndpoint()); + return; + } else { + logger.error("DELETE conflict for document {} didnt win @ {}", + conflictDocument.get(0).id(), + client.getReadEndpoint()); + + TimeUnit.MILLISECONDS.sleep(500); + } + } + } while (true); + } + + Document winnerDocument = null; + + for (Document document : conflictDocument) { + if (winnerDocument == null || + winnerDocument.getInt("regionId") <= document.getInt("regionId")) { + winnerDocument = document; + } + } + + logger.info("Document from region {} should be the winner", + winnerDocument.getInt("regionId")); + + while (true) { + try { + Document existingDocument = client.readDocument(winnerDocument.selfLink(), null) + .single().block().getResource(); + + if (existingDocument.getInt("regionId") == winnerDocument.getInt("regionId")) { + logger.info("Winner document from region {} found at {}", + existingDocument.getInt("regionId"), + client.getReadEndpoint()); + break; + } else { + logger.error("Winning document version from region {} is not found @ {}, retrying...", + winnerDocument.getInt("regionId"), + client.getWriteEndpoint()); + TimeUnit.MILLISECONDS.sleep(500); + } + } catch (Exception e) { + logger.error("Winner document from region {} is not found @ {}, retrying...", + winnerDocument.getInt("regionId"), + client.getWriteEndpoint()); + TimeUnit.MILLISECONDS.sleep(500); + } + } + } + + private void validateUDPAsync(List clients, List conflictDocument) throws Exception { + validateUDPAsync(clients, conflictDocument, false); + } + + private void validateUDPAsync(List clients, List conflictDocument, boolean hasDeleteConflict) throws Exception { + for (AsyncDocumentClient client : clients) { + this.validateUDPAsync(client, conflictDocument, hasDeleteConflict); + } + } + + private String documentNameLink(String collectionId, String documentId) { + return String.format("dbs/%s/colls/%s/docs/%s", databaseName, collectionId, documentId); + } + + private void validateUDPAsync(AsyncDocumentClient client, List conflictDocument, boolean hasDeleteConflict) throws Exception { + FeedResponse response = client.readConflicts(this.udpCollectionUri, null).take(1).single().block(); + + if (response.results().size() != 0) { + logger.error("Found {} conflicts in the udp collection", response.results().size()); + return; + } + + if (hasDeleteConflict) { + do { + try { + client.readDocument( + documentNameLink(udpCollectionName, conflictDocument.get(0).id()), null) + .single().block(); + + logger.error("DELETE conflict for document {} didnt win @ {}", + conflictDocument.get(0).id(), + client.getReadEndpoint()); + + TimeUnit.MILLISECONDS.sleep(500); + + } catch (Exception exception) { + if (hasDocumentClientExceptionCause(exception, 404)) { + logger.info("DELETE conflict won @ {}", client.getReadEndpoint()); + return; + } else { + logger.error("DELETE conflict for document {} didnt win @ {}", + conflictDocument.get(0).id(), + client.getReadEndpoint()); + + TimeUnit.MILLISECONDS.sleep(500); + } + } + } while (true); + } + + Document winnerDocument = null; + + for (Document document : conflictDocument) { + if (winnerDocument == null || + winnerDocument.getInt("regionId") <= document.getInt("regionId")) { + winnerDocument = document; + } + } + + logger.info("Document from region {} should be the winner", + winnerDocument.getInt("regionId")); + + while (true) { + try { + + Document existingDocument = client.readDocument( + documentNameLink(udpCollectionName, winnerDocument.id()), null) + .single().block().getResource(); + + if (existingDocument.getInt("regionId") == winnerDocument.getInt( + ("regionId"))) { + logger.info("Winner document from region {} found at {}", + existingDocument.getInt("regionId"), + client.getReadEndpoint()); + break; + } else { + logger.error("Winning document version from region {} is not found @ {}, retrying...", + winnerDocument.getInt("regionId"), + client.getWriteEndpoint()); + TimeUnit.MILLISECONDS.sleep(500); + } + } catch (Exception e) { + logger.error("Winner document from region {} is not found @ {}, retrying...", + winnerDocument.getInt("regionId"), + client.getWriteEndpoint()); + TimeUnit.MILLISECONDS.sleep(500); + } + } + } + + public void shutdown() { + this.executor.shutdown(); + for(AsyncDocumentClient client: clients) { + client.close(); + } + } +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Main.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Main.java new file mode 100644 index 0000000000000..b05e012dda6b1 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Main.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster.samples; + +import com.azure.data.cosmos.rx.examples.multimaster.ConfigurationManager; +import org.apache.commons.io.IOUtils; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + + +public class Main { + public static void main(String[] args) throws Exception { + + if (args.length != 1) { + help(); + System.exit(1); + } + + try (InputStream inputStream = new FileInputStream(args[0])) { + ConfigurationManager.getAppSettings().load(inputStream); + System.out.println("Using file " + args[0] + " for the setting."); + } + + Main.runScenarios(); + } + + private static void runScenarios() throws Exception { + MultiMasterScenario scenario = new MultiMasterScenario(); + scenario.initialize(); + + scenario.runBasic(); + + scenario.runManualConflict(); + scenario.runLWW(); + scenario.runUDP(); + + System.out.println("Finished"); + + //shutting down the active the resources + scenario.shutdown(); + } + + private static void help() throws IOException { + System.out.println("Provide the path to setting file in the following format: "); + try (InputStream inputStream = + Main.class.getClassLoader() + .getResourceAsStream("multi-master-sample-config.properties")) { + + IOUtils.copy(inputStream, System.out); + + System.out.println(); + } catch (Exception e) { + throw e; + } + } +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/MultiMasterScenario.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/MultiMasterScenario.java new file mode 100644 index 0000000000000..42d31123a67bd --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/MultiMasterScenario.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster.samples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.rx.examples.multimaster.ConfigurationManager; +import com.google.common.base.Preconditions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class MultiMasterScenario { + + private final static Logger logger = LoggerFactory.getLogger(MultiMasterScenario.class); + + final private String accountEndpoint; + final private String accountKey; + final private List workers; + final private ConflictWorker conflictWorker; + + public MultiMasterScenario() { + this.accountEndpoint = ConfigurationManager.getAppSettings().getProperty("endpoint"); + this.accountKey = ConfigurationManager.getAppSettings().getProperty("key"); + + String databaseName = ConfigurationManager.getAppSettings().getProperty("databaseName"); + String manualCollectionName = ConfigurationManager.getAppSettings().getProperty("manualCollectionName"); + String lwwCollectionName = ConfigurationManager.getAppSettings().getProperty("lwwCollectionName"); + String udpCollectionName = ConfigurationManager.getAppSettings().getProperty("udpCollectionName"); + String basicCollectionName = ConfigurationManager.getAppSettings().getProperty("basicCollectionName"); + String regionsAsString = ConfigurationManager.getAppSettings().getProperty("regions"); + Preconditions.checkNotNull(regionsAsString, "regions is required"); + String[] regions = regionsAsString.split(";"); + Preconditions.checkArgument(regions.length > 0, "at least one region is required"); + Preconditions.checkNotNull(accountEndpoint, "accountEndpoint is required"); + Preconditions.checkNotNull(accountKey, "accountKey is required"); + Preconditions.checkNotNull(databaseName, "databaseName is required"); + Preconditions.checkNotNull(manualCollectionName, "manualCollectionName is required"); + Preconditions.checkNotNull(lwwCollectionName, "lwwCollectionName is required"); + Preconditions.checkNotNull(udpCollectionName, "udpCollectionName is required"); + Preconditions.checkNotNull(basicCollectionName, "basicCollectionName is required"); + + this.workers = new ArrayList<>(); + this.conflictWorker = new ConflictWorker(databaseName, basicCollectionName, manualCollectionName, lwwCollectionName, udpCollectionName); + + for (String region : regions) { + ConnectionPolicy policy = new ConnectionPolicy(); + policy.usingMultipleWriteLocations(true); + policy.preferredLocations(Collections.singletonList(region)); + + AsyncDocumentClient client = + new AsyncDocumentClient.Builder() + .withMasterKeyOrResourceToken(this.accountKey) + .withServiceEndpoint(this.accountEndpoint) + .withConsistencyLevel(ConsistencyLevel.EVENTUAL) + .withConnectionPolicy(policy).build(); + + + workers.add(new Worker(client, databaseName, basicCollectionName)); + + conflictWorker.addClient(client); + } + } + + public void initialize() throws Exception { + this.conflictWorker.initialize(); + logger.info("Initialized collections."); + } + + public void runBasic() throws Exception { + logger.info("\n####################################################"); + logger.info("Basic Active-Active"); + logger.info("####################################################"); + + logger.info("1) Starting insert loops across multiple regions ..."); + + List> basicTask = new ArrayList<>(); + + int documentsToInsertPerWorker = 100; + + for (Worker worker : this.workers) { + basicTask.add(worker.runLoopAsync(documentsToInsertPerWorker)); + } + + Mono.when(basicTask).block(); + + basicTask.clear(); + + logger.info("2) Reading from every region ..."); + + int expectedDocuments = this.workers.size() * documentsToInsertPerWorker; + for (Worker worker : this.workers) { + basicTask.add(worker.readAllAsync(expectedDocuments)); + } + + Mono.when(basicTask).block(); + + basicTask.clear(); + + logger.info("3) Deleting all the documents ..."); + + this.workers.get(0).deleteAll(); + + logger.info("####################################################"); + } + + public void runManualConflict() throws Exception { + logger.info("\n####################################################"); + logger.info("Manual Conflict Resolution"); + logger.info("####################################################"); + + this.conflictWorker.runManualConflict(); + logger.info("####################################################"); + } + + public void runLWW() throws Exception { + logger.info("\n####################################################"); + logger.info("LWW Conflict Resolution"); + logger.info("####################################################"); + + this.conflictWorker.runLWWConflict(); + logger.info("####################################################"); + } + + public void runUDP() throws Exception { + logger.info("\n####################################################"); + logger.info("UDP Conflict Resolution"); + logger.info("####################################################"); + + this.conflictWorker.runUDPConflict(); + logger.info("####################################################"); + } + + public void shutdown() { + conflictWorker.shutdown(); + for(Worker worker: this.workers) { + worker.shutdown(); + } + } +} diff --git a/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Worker.java b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Worker.java new file mode 100644 index 0000000000000..f5d7657f89762 --- /dev/null +++ b/sdk/cosmos/examples/src/main/java/com/azure/data/cosmos/rx/examples/multimaster/samples/Worker.java @@ -0,0 +1,186 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples.multimaster.samples; + + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class Worker { + private final static Logger logger = LoggerFactory.getLogger(Worker.class); + + private final AsyncDocumentClient client; + private final String documentCollectionUri; + + // scheduler for blocking work + private final Scheduler schedulerForBlockingWork; + private final ExecutorService executor; + + public Worker(AsyncDocumentClient client, String databaseName, String collectionName) { + this.client = client; + this.documentCollectionUri = String.format("/dbs/%s/colls/%s", databaseName, collectionName); + this.executor = Executors.newSingleThreadExecutor(); + this.schedulerForBlockingWork = Schedulers.fromExecutor(executor); + } + + public Mono runLoopAsync(int documentsToInsert) { + return Mono.defer(() -> { + + int iterationCount = 0; + + List latency = new ArrayList<>(); + while (iterationCount++ < documentsToInsert) { + long startTick = System.currentTimeMillis(); + + Document d = new Document(); + d.id(UUID.randomUUID().toString()); + + this.client.createDocument(this.documentCollectionUri, d, null, false) + .subscribeOn(schedulerForBlockingWork).single().block(); + + long endTick = System.currentTimeMillis(); + + latency.add(endTick - startTick); + } + + Collections.sort(latency); + int p50Index = (latency.size() / 2); + + logger.info("Inserted {} documents at {} with p50 {} ms", + documentsToInsert, + this.client.getWriteEndpoint(), + latency.get(p50Index)); + + return Mono.empty(); + + }); + + } + + + public Mono readAllAsync(int expectedNumberOfDocuments) { + + return Mono.defer(() -> { + + while (true) { + int totalItemRead = 0; + FeedResponse response = null; + do { + + FeedOptions options = new FeedOptions(); + options.requestContinuation(response != null ? response.continuationToken() : null); + + response = this.client.readDocuments(this.documentCollectionUri, options).take(1) + .subscribeOn(schedulerForBlockingWork).single().block(); + + totalItemRead += response.results().size(); + } while (response.continuationToken() != null); + + if (totalItemRead < expectedNumberOfDocuments) { + logger.info("Total item read {} from {} is less than {}, retrying reads", + totalItemRead, + this.client.getReadEndpoint(), + expectedNumberOfDocuments); + + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + logger.info("interrupted"); + break; + } + continue; + } else { + logger.info("READ {} items from {}", totalItemRead, this.client.getReadEndpoint()); + break; + } + } + + return Mono.empty(); + }); + } + + void deleteAll() { + List documents = new ArrayList<>(); + FeedResponse response = null; + do { + + FeedOptions options = new FeedOptions(); + options.requestContinuation(response != null ? response.continuationToken() : null); + + response = this.client.readDocuments(this.documentCollectionUri, options).take(1) + .subscribeOn(schedulerForBlockingWork).single().block(); + + documents.addAll(response.results()); + } while (response.continuationToken() != null); + + for (Document document : documents) { + try { + this.client.deleteDocument(document.selfLink(), null) + .subscribeOn(schedulerForBlockingWork).single().block(); + } catch (RuntimeException exEx) { + CosmosClientException dce = getDocumentClientExceptionCause(exEx); + + if (dce.statusCode() != 404) { + logger.info("Error occurred while deleting {} from {}", dce, client.getWriteEndpoint()); + } + } + } + + logger.info("Deleted all documents from region {}", this.client.getWriteEndpoint()); + } + + private CosmosClientException getDocumentClientExceptionCause(Throwable e) { + while (e != null) { + + if (e instanceof CosmosClientException) { + return (CosmosClientException) e; + } + + e = e.getCause(); + } + + return null; + } + + public void shutdown() { + executor.shutdown(); + client.close(); + } +} diff --git a/sdk/cosmos/examples/src/main/resources/log4j.properties b/sdk/cosmos/examples/src/main/resources/log4j.properties new file mode 100644 index 0000000000000..a8f16e5dee315 --- /dev/null +++ b/sdk/cosmos/examples/src/main/resources/log4j.properties @@ -0,0 +1,23 @@ +# this is the log4j configuration for tests + +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=WARN, A1 + +log4j.category.io.netty=INFO +log4j.category.io.reactivex=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.samples.ConflictWorker=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.samples.Main=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.samples.Worker=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.samples.MultiMasterScenario=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.ConfigurationManager=INFO +log4j.category.com.azure.data.cosmos.rx.examples.multimaster.Helpers=INFO + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +#log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p - %m%n + +log4j.appender.A1.layout.ConversionPattern=%m%n + diff --git a/sdk/cosmos/examples/src/main/resources/multi-master-sample-config.properties b/sdk/cosmos/examples/src/main/resources/multi-master-sample-config.properties new file mode 100644 index 0000000000000..42c20302edc12 --- /dev/null +++ b/sdk/cosmos/examples/src/main/resources/multi-master-sample-config.properties @@ -0,0 +1,8 @@ +endpoint= +key= +regions=North Central US;North Europe;Southeast Asia +databaseName=multiMasterDemoDB +manualCollectionName=myManualCollection +lwwCollectionName=myLwwCollection +udpCollectionName=myUdpCollection +basicCollectionName=myBasicCollection \ No newline at end of file diff --git a/sdk/cosmos/examples/src/main/resources/resolver-storedproc.txt b/sdk/cosmos/examples/src/main/resources/resolver-storedproc.txt new file mode 100644 index 0000000000000..e856721a979ac --- /dev/null +++ b/sdk/cosmos/examples/src/main/resources/resolver-storedproc.txt @@ -0,0 +1,45 @@ +function resolver(incomingRecord, existingRecord, isTombstone, conflictingRecords) { + var collection = getContext().getCollection(); + if (!incomingRecord) { + if (existingRecord) { + collection.deleteDocument(existingRecord._self, {}, function(err, responseOptions) { + if (err) throw err; + }); + } + } else if (isTombstone) { + // delete always wins. + } else { + var documentToUse = incomingRecord; + if (existingRecord) { + if (documentToUse.regionId < existingRecord.regionId) { + documentToUse = existingRecord; + } + } + var i; + for (i = 0; i < conflictingRecords.length; i++) { + if (documentToUse.regionId < conflictingRecords[i].regionId) { + documentToUse = conflictingRecords[i]; + } + } + tryDelete(conflictingRecords, incomingRecord, existingRecord, documentToUse); + } + function tryDelete(documents, incoming, existing, documentToInsert) { + if (documents.length > 0) { + collection.deleteDocument(documents[0]._self, {}, function(err, responseOptions) { + if (err) throw err; + documents.shift(); + tryDelete(documents, incoming, existing, documentToInsert); + }); + } else if (existing) { + collection.replaceDocument(existing._self, documentToInsert, + function(err, documentCreated) { + if (err) throw err; + }); + } else { + collection.createDocument(collection.getSelfLink(), documentToInsert, + function(err, documentCreated) { + if (err) throw err; + }); + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/DocumentClientTest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/DocumentClientTest.java new file mode 100644 index 0000000000000..2a537e8ed9b39 --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/DocumentClientTest.java @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.google.common.base.Strings; +import org.testng.ITest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import java.lang.reflect.Method; + +public abstract class DocumentClientTest implements ITest { + + private final AsyncDocumentClient.Builder clientBuilder; + private String testName; + + public DocumentClientTest() { + this(new AsyncDocumentClient.Builder()); + } + + public DocumentClientTest(AsyncDocumentClient.Builder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + public final AsyncDocumentClient.Builder clientBuilder() { + return this.clientBuilder; + } + + @Override + public final String getTestName() { + return this.testName; + } + + @BeforeMethod(alwaysRun = true) + public final void setTestName(Method method) { + + String connectionMode = this.clientBuilder.getConnectionPolicy().connectionMode() == ConnectionMode.DIRECT + ? "Direct " + this.clientBuilder.getConfigs().getProtocol() + : "Gateway"; + + this.testName = Strings.lenientFormat("%s::%s[%s with %s consistency]", + method.getDeclaringClass().getSimpleName(), + method.getName(), + connectionMode, + clientBuilder.getDesiredConsistencyLevel()); + } + + @AfterMethod(alwaysRun = true) + public final void unsetTestName() { + this.testName = null; + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/CollectionCRUDAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/CollectionCRUDAsyncAPITest.java new file mode 100644 index 0000000000000..7a882bc6540db --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/CollectionCRUDAsyncAPITest.java @@ -0,0 +1,415 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; + +/** + * This integration test class demonstrates how to use Async API to create, + * delete, replace, and update Document Collections. + *

    + * NOTE: you can use rxJava based async api with java8 lambda expression. Use of + * rxJava based async APIs with java8 lambda expressions is much prettier. + *

    + * You can also use the async API without java8 lambda expression support. + *

    + * For example + *

      + *
    • {@link #createCollection_MultiPartition_Async()} demonstrates how to use async api + * with java8 lambda expression. + * + *
    • {@link #createCollection_Async_withoutLambda()} demonstrates how to + * do the same thing without lambda expression. + *
    + *

    + * Also if you need to work with Future or CompletableFuture it is possible to + * transform a flux to CompletableFuture. Please see + * {@link #transformObservableToCompletableFuture()} + *

    + * To Modify the Collection's throughput after it has been created, you need to + * update the corresponding Offer. Please see + * {@see com.azure.data.cosmos.rx.examples.OfferCRUDAsyncAPITest#testUpdateOffer()} + */ +public class CollectionCRUDAsyncAPITest extends DocumentClientTest { + + private final static int TIMEOUT = 120000; + private Database createdDatabase; + private AsyncDocumentClient client; + private DocumentCollection collectionDefinition; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + createdDatabase = Utils.createDatabaseForTest(client); + } + + @BeforeMethod(groups = "samples", timeOut = TIMEOUT) + public void before() { + collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * CREATE a document collection using async api. + * If you want a single partition collection with 10,000 RU/s throughput, + * the only way to do so is to create a single partition collection with lower + * throughput (400) and then increase the throughput. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createCollection_SinglePartition_Async() throws Exception { + RequestOptions singlePartitionRequestOptions = new RequestOptions(); + singlePartitionRequestOptions.setOfferThroughput(400); + Flux> createCollectionObservable = client + .createCollection(getDatabaseLink(), collectionDefinition, singlePartitionRequestOptions); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + createCollectionObservable.single() // We know there is only single result + .subscribe(collectionResourceResponse -> { + System.out.println(collectionResourceResponse.getActivityId()); + countDownLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while creating the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + }); + + // Wait till collection creation completes + countDownLatch.await(); + } + + /** + * CREATE a document collection using async api. + * This test uses java8 lambda expression. + * See testCreateCollection_Async_withoutLambda for usage without lambda + * expressions. + * Set the throughput to be > 10,000 RU/s + * to create a multi partition collection. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createCollection_MultiPartition_Async() throws Exception { + RequestOptions multiPartitionRequestOptions = new RequestOptions(); + multiPartitionRequestOptions.setOfferThroughput(20000); + + Flux> createCollectionObservable = client.createCollection( + getDatabaseLink(), getMultiPartitionCollectionDefinition(), multiPartitionRequestOptions); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + createCollectionObservable.single() // We know there is only single result + .subscribe(collectionResourceResponse -> { + System.out.println(collectionResourceResponse.getActivityId()); + countDownLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while creating the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + }); + + // Wait till collection creation completes + countDownLatch.await(); + } + + /** + * CREATE a document Collection using async api, without java8 lambda expressions + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createCollection_Async_withoutLambda() throws Exception { + Flux> createCollectionObservable = client + .createCollection(getDatabaseLink(), collectionDefinition, null); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + Consumer> onCollectionCreationAction = new Consumer>() { + + @Override + public void accept(ResourceResponse resourceResponse) { + // Collection is created + System.out.println(resourceResponse.getActivityId()); + countDownLatch.countDown(); + } + }; + + Consumer onError = new Consumer() { + @Override + public void accept(Throwable error) { + System.err.println( + "an error occurred while creating the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + } + }; + + createCollectionObservable.single() // We know there is only a single event + .subscribe(onCollectionCreationAction, onError); + + // Wait till collection creation completes + countDownLatch.await(); + } + + /** + * CREATE a collection in a blocking manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createCollection_toBlocking() { + Flux> createCollectionObservable = client + .createCollection(getDatabaseLink(), collectionDefinition, null); + + // single() converts the flux to a mono. + // block() gets the only result. + createCollectionObservable.single().block(); + } + + /** + * Attempt to create a Collection which already exists + * - First create a Collection + * - Using the async api generate an async collection creation observable + * - Converts the Observable to blocking using Observable.toBlocking() api + * - Catch already exist failure (409) + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createCollection_toBlocking_CollectionAlreadyExists_Fails() { + client.createCollection(getDatabaseLink(), collectionDefinition, null).single().block(); + + // CREATE the collection for test. + Flux> collectionForTestObservable = client + .createCollection(getDatabaseLink(), collectionDefinition, null); + + try { + collectionForTestObservable.single() // Gets the single result + .block(); // Blocks + assertThat("Should not reach here", false); + } catch (Exception e) { + assertThat("Collection already exists.", ((CosmosClientException) e.getCause()).statusCode(), + equalTo(409)); + } + } + + /** + * You can convert a Flux to a CompletableFuture. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void transformObservableToCompletableFuture() throws Exception { + Flux> createCollectionObservable = client + .createCollection(getDatabaseLink(), collectionDefinition, null); + CompletableFuture> future = createCollectionObservable.single().toFuture(); + + ResourceResponse rrd = future.get(); + + assertThat(rrd.getRequestCharge(), greaterThan((double) 0)); + System.out.println(rrd.getRequestCharge()); + } + + /** + * READ a Collection in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createAndReadCollection() throws Exception { + // CREATE a Collection + DocumentCollection documentCollection = client + .createCollection(getDatabaseLink(), collectionDefinition, null).single().block() + .getResource(); + + // READ the created collection using async api + Flux> readCollectionObservable = client + .readCollection(getCollectionLink(documentCollection), null); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + readCollectionObservable.single() // We know there is only single result + .subscribe(collectionResourceResponse -> { + System.out.println(collectionResourceResponse.getActivityId()); + countDownLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while reading the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + }); + + // Wait till read collection completes + countDownLatch.await(); + } + + /** + * DELETE a Collection in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createAndDeleteCollection() throws Exception { + // CREATE a Collection + DocumentCollection documentCollection = client + .createCollection(getDatabaseLink(), collectionDefinition, null).single().block() + .getResource(); + + // DELETE the created collection using async api + Flux> deleteCollectionObservable = client + .deleteCollection(getCollectionLink(documentCollection), null); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + deleteCollectionObservable.single() // We know there is only single result + .subscribe(collectionResourceResponse -> { + System.out.println(collectionResourceResponse.getActivityId()); + countDownLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while deleting the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + }); + + // Wait till collection deletion completes + countDownLatch.await(); + } + + /** + * Query a Collection in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void collectionCreateAndQuery() throws Exception { + // CREATE a Collection + DocumentCollection collection = client + .createCollection(getDatabaseLink(), collectionDefinition, null).single().block() + .getResource(); + + // Query the created collection using async api + Flux> queryCollectionObservable = client.queryCollections( + getDatabaseLink(), String.format("SELECT * FROM r where r.id = '%s'", collection.id()), + null); + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + queryCollectionObservable.collectList().subscribe(collectionFeedResponseList -> { + // toList() should return a list of size 1 + assertThat(collectionFeedResponseList.size(), equalTo(1)); + + // First element of the list should have only 1 result + FeedResponse collectionFeedResponse = collectionFeedResponseList.get(0); + assertThat(collectionFeedResponse.results().size(), equalTo(1)); + + // This collection should have the same id as the one we created + DocumentCollection foundCollection = collectionFeedResponse.results().get(0); + assertThat(foundCollection.id(), equalTo(collection.id())); + + System.out.println(collectionFeedResponse.activityId()); + countDownLatch.countDown(); + }, error -> { + System.err.println("an error occurred while querying the collection: actual cause: " + error.getMessage()); + countDownLatch.countDown(); + }); + + // Wait till collection query completes + countDownLatch.await(); + } + + private String getDatabaseLink() { + return "dbs/" + createdDatabase.id(); + } + + private String getCollectionLink(DocumentCollection collection) { + return "dbs/" + createdDatabase.id() + "/colls/" + collection.id(); + } + + private DocumentCollection getMultiPartitionCollectionDefinition() { + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + + // Set the partitionKeyDefinition for a partitioned collection. + // Here, we are setting the partitionKey of the Collection to be /city + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + List paths = new ArrayList<>(); + paths.add("/city"); + partitionKeyDefinition.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDefinition); + + // Set indexing policy to be range range for string and number + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + collectionDefinition.setIndexingPolicy(indexingPolicy); + + return collectionDefinition; + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/ConflictAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/ConflictAPITest.java new file mode 100644 index 0000000000000..b6523b40f163f --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/ConflictAPITest.java @@ -0,0 +1,177 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.HttpConstants; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; + +/** + * This integration test class demonstrates how to use Async API for + * Conflicts. + *

    + * Also if you need to work with Future or CompletableFuture it is possible to + * transform a flux to CompletableFuture. Please see + * {@link #transformObservableToCompletableFuture()} + */ +public class ConflictAPITest extends DocumentClientTest { + private final static int TIMEOUT = 60000; + + private AsyncDocumentClient client; + private DocumentCollection createdCollection; + private Database createdDatabase; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + + // CREATE collection + createdCollection = client + .createCollection("/dbs/" + createdDatabase.id(), collectionDefinition, null) + .single().block().getResource(); + + int numberOfDocuments = 20; + // Add documents + for (int i = 0; i < numberOfDocuments; i++) { + Document doc = new Document(String.format("{ 'id': 'loc%d', 'counter': %d}", i, i)); + client.createDocument(getCollectionLink(), doc, null, true).single().block(); + } + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * READ conflicts + * Converts the conflict read feed observable to blocking observable and + * uses that to find all conflicts + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void readConflicts_toBlocking_toIterator() { + // read all conflicts + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + + Flux> conflictReadFeedObservable = client + .readConflicts(getCollectionLink(), options); + + // Covert the flux to an iterable, and then to iterator + Iterator> it = conflictReadFeedObservable.toIterable().iterator(); + + int expectedNumberOfConflicts = 0; + + int numberOfResults = 0; + while (it.hasNext()) { + FeedResponse page = it.next(); + System.out.println("items: " + page.results()); + String pageSizeAsString = page.responseHeaders().get(HttpConstants.HttpHeaders.ITEM_COUNT); + assertThat("header item count must be present", pageSizeAsString, notNullValue()); + int pageSize = Integer.valueOf(pageSizeAsString); + assertThat("Result size must match header item count", page.results(), hasSize(pageSize)); + numberOfResults += pageSize; + } + assertThat("number of total results", numberOfResults, equalTo(expectedNumberOfConflicts)); + } + + /** + * You can convert a Flux to a CompletableFuture. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void transformObservableToCompletableFuture() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + + Flux> conflictReadFeedObservable = client + .readConflicts(getCollectionLink(), options); + + // Convert to observable of list of pages + Mono>> allPagesObservable = conflictReadFeedObservable.collectList(); + + // Convert the observable of list of pages to a Future + CompletableFuture>> future = allPagesObservable.toFuture(); + + List> pageList = future.get(); + + int totalNumberOfRetrievedConflicts = 0; + for (FeedResponse page : pageList) { + totalNumberOfRetrievedConflicts += page.results().size(); + } + assertThat(0, equalTo(totalNumberOfRetrievedConflicts)); + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } +} + diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DatabaseCRUDAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DatabaseCRUDAsyncAPITest.java new file mode 100644 index 0000000000000..02805f1ab1e76 --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DatabaseCRUDAsyncAPITest.java @@ -0,0 +1,316 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.ResourceResponse; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; + +/** + * This integration test class demonstrates how to use Async API to create, + * delete, replace, and update Databases. + *

    + * NOTE: you can use rxJava based async api with java8 lambda expression. Use of + * rxJava based async APIs with java8 lambda expressions is much prettier. + *

    + * You can also use the async API without java8 lambda expression support. + *

    + * For example + *

      + *
    • {@link #createDatabase_Async()} demonstrates how to use async api + * with java8 lambda expression. + * + *
    • {@link #createDatabase_Async_withoutLambda()} demonstrates how to + * do the same thing without lambda expression. + *
    + *

    + * Also if you need to work with Future or CompletableFuture it is possible to + * transform a flux to CompletableFuture. Please see + * {@link #transformObservableToCompletableFuture()} + */ +public class DatabaseCRUDAsyncAPITest extends DocumentClientTest { + private final static int TIMEOUT = 60000; + private final List databaseIds = new ArrayList<>(); + + private AsyncDocumentClient client; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + } + + private Database getDatabaseDefinition() { + Database databaseDefinition = new Database(); + databaseDefinition.id(Utils.generateDatabaseId()); + + databaseIds.add(databaseDefinition.id()); + + return databaseDefinition; + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + for (String id : databaseIds) { + Utils.safeClean(client, id); + } + Utils.safeClose(client); + } + + /** + * CREATE a database using async api. + * This test uses java8 lambda expression. + * See testCreateDatabase_Async_withoutLambda for usage without lambda. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDatabase_Async() throws Exception { + Flux> createDatabaseObservable = client.createDatabase(getDatabaseDefinition(), + null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + createDatabaseObservable.single() // We know there is only single result + .subscribe(databaseResourceResponse -> { + System.out.println(databaseResourceResponse.getActivityId()); + completionLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while creating the database: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + // Wait till database creation completes + completionLatch.await(); + } + + /** + * CREATE a database using async api, without java8 lambda expressions + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDatabase_Async_withoutLambda() throws Exception { + Flux> createDatabaseObservable = client.createDatabase(getDatabaseDefinition(), + null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + Consumer> onDatabaseCreationAction = new Consumer>() { + + @Override + public void accept(ResourceResponse resourceResponse) { + // Database is created + System.out.println(resourceResponse.getActivityId()); + completionLatch.countDown(); + } + }; + + Consumer onError = new Consumer() { + @Override + public void accept(Throwable error) { + System.err + .println("an error occurred while creating the database: actual cause: " + error.getMessage()); + completionLatch.countDown(); + } + }; + + createDatabaseObservable.single() // We know there is only a single event + .subscribe(onDatabaseCreationAction, onError); + + // Wait till database creation completes + completionLatch.await(); + } + + /** + * CREATE a database in a blocking manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDatabase_toBlocking() { + Flux> createDatabaseObservable = client.createDatabase(getDatabaseDefinition(), + null); + + // toBlocking() converts to a blocking observable. + // single() gets the only result. + createDatabaseObservable.single().block(); + } + + /** + * Attempt to create a database which already exists + * - First create a database + * - Using the async api generate an async database creation observable + * - Converts the Observable to blocking using Observable.toBlocking() api + * - Catch already exist failure (409) + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDatabase_toBlocking_DatabaseAlreadyExists_Fails() { + Database databaseDefinition = getDatabaseDefinition(); + client.createDatabase(databaseDefinition, null).single().block(); + + // CREATE the database for test. + Flux> databaseForTestObservable = client + .createDatabase(databaseDefinition, null); + + try { + databaseForTestObservable.single() // Single + .block(); // Blocks to get the result + assertThat("Should not reach here", false); + } catch (Exception e) { + assertThat("Database already exists.", ((CosmosClientException) e.getCause()).statusCode(), + equalTo(409)); + } + } + + /** + * You can convert a Flux to a CompletableFuture. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void transformObservableToCompletableFuture() throws Exception { + Flux> createDatabaseObservable = client.createDatabase(getDatabaseDefinition(), + null); + CompletableFuture> future = createDatabaseObservable.single().toFuture(); + + ResourceResponse rrd = future.get(); + + assertThat(rrd.getRequestCharge(), greaterThan((double) 0)); + System.out.print(rrd.getRequestCharge()); + } + + /** + * READ a Database in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createAndReadDatabase() throws Exception { + // CREATE a database + Database database = client.createDatabase(getDatabaseDefinition(), null).single().block().getResource(); + + // READ the created database using async api + Flux> readDatabaseObservable = client.readDatabase("dbs/" + database.id(), + null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + readDatabaseObservable.single() // We know there is only single result + .subscribe(databaseResourceResponse -> { + System.out.println(databaseResourceResponse.getActivityId()); + completionLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while reading the database: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + // Wait till read database completes + completionLatch.await(); + } + + /** + * DELETE a Database in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createAndDeleteDatabase() throws Exception { + // CREATE a database + Database database = client.createDatabase(getDatabaseDefinition(), null).single().block().getResource(); + + // DELETE the created database using async api + Flux> deleteDatabaseObservable = client + .deleteDatabase("dbs/" + database.id(), null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + deleteDatabaseObservable.single() // We know there is only single result + .subscribe(databaseResourceResponse -> { + System.out.println(databaseResourceResponse.getActivityId()); + completionLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while deleting the database: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + // Wait till database deletion completes + completionLatch.await(); + } + + /** + * Query a Database in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void databaseCreateAndQuery() throws Exception { + // CREATE a database + Database databaseDefinition = getDatabaseDefinition(); + client.createDatabase(databaseDefinition, null).single().block().getResource(); + + // Query the created database using async api + Flux> queryDatabaseObservable = client + .queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseDefinition.id()), null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + queryDatabaseObservable.collectList().subscribe(databaseFeedResponseList -> { + // toList() should return a list of size 1 + assertThat(databaseFeedResponseList.size(), equalTo(1)); + + // First element of the list should have only 1 result + FeedResponse databaseFeedResponse = databaseFeedResponseList.get(0); + assertThat(databaseFeedResponse.results().size(), equalTo(1)); + + // This database should have the same id as the one we created + Database foundDatabase = databaseFeedResponse.results().get(0); + assertThat(foundDatabase.id(), equalTo(databaseDefinition.id())); + + System.out.println(databaseFeedResponse.activityId()); + completionLatch.countDown(); + }, error -> { + System.err.println("an error occurred while querying the database: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + // Wait till database query completes + completionLatch.await(); + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentCRUDAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentCRUDAsyncAPITest.java new file mode 100644 index 0000000000000..6232cb561f2fc --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentCRUDAsyncAPITest.java @@ -0,0 +1,542 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.RandomUtils; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; + +/** + * This integration test class demonstrates how to use Async API to create, + * delete, replace, and upsert Documents. If you are interested in examples for + * querying for documents please see {@link DocumentQueryAsyncAPITest} + *

    + * NOTE: you can use rxJava based async api with java8 lambda expression. Use + * of rxJava based async APIs with java8 lambda expressions is much prettier. + *

    + * You can also use the async API without java8 lambda expression. + *

    + * For example + *

      + *
    • {@link #createDocument_Async()} demonstrates how to use async api + * with java8 lambda expression. + * + *
    • {@link #createDocument_Async_withoutLambda()} demonstrates how to do + * the same thing without lambda expression. + *
    + *

    + * Also if you need to work with Future or CompletableFuture it is possible to + * transform a flux to CompletableFuture. Please see + * {@link #transformObservableToCompletableFuture()} + */ +public class DocumentCRUDAsyncAPITest extends DocumentClientTest { + + private final static String PARTITION_KEY_PATH = "/mypk"; + private final static int TIMEOUT = 60000; + + private AsyncDocumentClient client; + private Database createdDatabase; + private DocumentCollection createdCollection; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + ArrayList partitionKeyPaths = new ArrayList(); + partitionKeyPaths.add(PARTITION_KEY_PATH); + partitionKeyDefinition.paths(partitionKeyPaths); + collectionDefinition.setPartitionKey(partitionKeyDefinition); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + + // CREATE collection + createdCollection = client + .createCollection("dbs/" + createdDatabase.id(), collectionDefinition, null) + .single().block().getResource(); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * CREATE a document using java8 lambda expressions + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocument_Async() throws Exception { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, true); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + // Subscribe to Document resource response emitted by the observable + createDocumentObservable.single() // We know there will be one response + .subscribe(documentResourceResponse -> { + System.out.println(documentResourceResponse.getActivityId()); + completionLatch.countDown(); + }, error -> { + System.err.println( + "an error occurred while creating the document: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + // Wait till document creation completes + completionLatch.await(); + } + + /** + * CREATE a document without java8 lambda expressions + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocument_Async_withoutLambda() throws Exception { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, true); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + Consumer> onNext = new Consumer>() { + + @Override + public void accept(ResourceResponse documentResourceResponse) { + System.out.println(documentResourceResponse.getActivityId()); + completionLatch.countDown(); + } + }; + + Consumer onError = new Consumer() { + + @Override + public void accept(Throwable error) { + System.err + .println("an error occurred while creating the document: actual cause: " + error.getMessage()); + completionLatch.countDown(); + } + }; + + // Subscribe to Document resource response emitted by the observable + createDocumentObservable.single() // We know there will be one response + .subscribe(onNext, onError); + + // Wait till document creation completes + completionLatch.await(); + } + + /** + * CREATE a document in a blocking manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocument_toBlocking() { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, true); + + // toBlocking() converts to a blocking observable. + // single() gets the only result. + createDocumentObservable.single().block(); + } + + /** + * CREATE a document with a programmatically set definition, in an Async manner + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocumentWithProgrammableDocumentDefinition() throws Exception { + Document documentDefinition = new Document(); + documentDefinition.id("test-document"); + BridgeInternal.setProperty(documentDefinition, "counter", 1); + + // CREATE a document + Document createdDocument = client + .createDocument(getCollectionLink(), documentDefinition, null, false).single().block() + .getResource(); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + // READ the created document + Flux> readDocumentObservable = client + .readDocument(getDocumentLink(createdDocument), null); + + final CountDownLatch completionLatch = new CountDownLatch(1); + + readDocumentObservable.subscribe(documentResourceResponse -> { + Document readDocument = documentResourceResponse.getResource(); + + // The read document must be the same as the written document + assertThat(readDocument.id(), equalTo("test-document")); + assertThat(readDocument.getInt("counter"), equalTo(1)); + System.out.println(documentResourceResponse.getActivityId()); + completionLatch.countDown(); + }, error -> { + System.err.println("an error occured while creating the document: actual cause: " + error.getMessage()); + completionLatch.countDown(); + }); + + completionLatch.await(); + } + + /** + * CREATE 10 documents and sum up all the documents creation request charges + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void documentCreation_SumUpRequestCharge() throws Exception { + // CREATE 10 documents + List>> listOfCreateDocumentObservables = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), i)); + + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, false); + listOfCreateDocumentObservables.add(createDocumentObservable); + } + + // Merge all document creation observables into one observable + Flux> mergedObservable = Flux.merge(listOfCreateDocumentObservables); + + // CREATE a new observable emitting the total charge of creating all 10 + // documents. + Flux totalChargeObservable = mergedObservable + .map(ResourceResponse::getRequestCharge) + // Map to request charge + .reduce(Double::sum).flux(); + // Sum up all the charges + + final CountDownLatch completionLatch = new CountDownLatch(1); + + // Subscribe to the total request charge observable + totalChargeObservable.subscribe(totalCharge -> { + // Print the total charge + System.out.println(totalCharge); + completionLatch.countDown(); + }, e -> completionLatch.countDown() + ); + + completionLatch.await(); + } + + /** + * Attempt to create a document which already exists + * - First create a document + * - Using the async api generate an async document creation observable + * - Converts the Observable to blocking using Observable.toBlocking() api + * - Catch already exist failure (409) + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocument_toBlocking_DocumentAlreadyExists_Fails() { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + client.createDocument(getCollectionLink(), doc, null, false).single().block(); + + // CREATE the document + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, false); + + try { + createDocumentObservable.single() // Converts the observable to a single observable + .block(); // Blocks and gets the result + Assert.fail("Document Already Exists. Document Creation must fail"); + } catch (Exception e) { + assertThat("Document already exists.", ((CosmosClientException) e.getCause()).statusCode(), + equalTo(409)); + } + } + + /** + * Attempt to create a document which already exists + * - First create a document + * - Using the async api generate an async document creation observable + * - Converts the Observable to blocking using Observable.toBlocking() api + * - Catch already exist failure (409) + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void createDocument_Async_DocumentAlreadyExists_Fails() throws Exception { + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + client.createDocument(getCollectionLink(), doc, null, false).single().block(); + + // CREATE the document + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, false); + + List errorList = Collections.synchronizedList(new ArrayList<>()); + + createDocumentObservable.subscribe(resourceResponse -> { + }, error -> { + errorList.add(error); + System.err.println("failed to create a document due to: " + error.getMessage()); + }); + + Thread.sleep(2000); + assertThat(errorList, hasSize(1)); + assertThat(errorList.get(0), is(instanceOf(CosmosClientException.class))); + assertThat(((CosmosClientException) errorList.get(0)).statusCode(), equalTo(409)); + } + + /** + * REPLACE a document + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void documentReplace_Async() throws Exception { + // CREATE a document + Document createdDocument = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + createdDocument = client.createDocument(getCollectionLink(), createdDocument, null, false).single() + .block().getResource(); + + // Try to replace the existing document + Document replacingDocument = new Document( + String.format("{ 'id': 'doc%s', 'counter': '%d', 'new-prop' : '2'}", createdDocument.id(), 1)); + Flux> replaceDocumentObservable = client + .replaceDocument(getDocumentLink(createdDocument), replacingDocument, null); + + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + + replaceDocumentObservable.subscribe(resourceResponse -> { + capturedResponse.add(resourceResponse); + }); + + Thread.sleep(2000); + + assertThat(capturedResponse, hasSize(1)); + assertThat(capturedResponse.get(0).getResource().get("new-prop"), equalTo("2")); + } + + /** + * Upsert a document + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void documentUpsert_Async() throws Exception { + // CREATE a document + Document doc = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d'}", UUID.randomUUID().toString(), 1)); + client.createDocument(getCollectionLink(), doc, null, false).single().block(); + + // Upsert the existing document + Document upsertingDocument = new Document( + String.format("{ 'id': 'doc%s', 'counter': '%d', 'new-prop' : '2'}", doc.id(), 1)); + Flux> upsertDocumentObservable = client + .upsertDocument(getCollectionLink(), upsertingDocument, null, false); + + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + + upsertDocumentObservable.subscribe(resourceResponse -> { + capturedResponse.add(resourceResponse); + }); + + Thread.sleep(4000); + + assertThat(capturedResponse, hasSize(1)); + assertThat(capturedResponse.get(0).getResource().get("new-prop"), equalTo("2")); + } + + /** + * DELETE a document + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void documentDelete_Async() throws Exception { + // CREATE a document + Document createdDocument = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d', 'mypk' : '%s'}", UUID.randomUUID().toString(), 1, UUID.randomUUID().toString())); + createdDocument = client.createDocument(getCollectionLink(), createdDocument, null, false).single() + .block().getResource(); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(createdDocument.getString("mypk"))); + + // DELETE the existing document + Flux> deleteDocumentObservable = client + .deleteDocument(getDocumentLink(createdDocument), options); + + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + + deleteDocumentObservable.subscribe(resourceResponse -> { + capturedResponse.add(resourceResponse); + }); + + Thread.sleep(2000); + + assertThat(capturedResponse, hasSize(1)); + + // Assert document is deleted + FeedOptions queryOptions = new FeedOptions(); + queryOptions.enableCrossPartitionQuery(true); + List listOfDocuments = client + .queryDocuments(getCollectionLink(), String.format("SELECT * FROM r where r.id = '%s'", createdDocument.id()), queryOptions) + .map(FeedResponse::results) // Map page to its list of documents + .concatMap(Flux::fromIterable) // Flatten the observable + .collectList() // Transform to a observable + .single() // Gets the Mono> + .block(); // Block + + // Assert that there is no document found + assertThat(listOfDocuments, hasSize(0)); + } + + /** + * READ a document + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void documentRead_Async() throws Exception { + // CREATE a document + Document createdDocument = new Document(String.format("{ 'id': 'doc%s', 'counter': '%d', 'mypk' : '%s'}", UUID.randomUUID().toString(), 1, UUID.randomUUID().toString())); + createdDocument = client.createDocument(getCollectionLink(), createdDocument, null, false).single() + .block().getResource(); + + // READ the document + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(createdDocument.getString("mypk"))); + Flux> readDocumentObservable = client + .readDocument(getDocumentLink(createdDocument), options); + + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + + readDocumentObservable.subscribe(resourceResponse -> { + capturedResponse.add(resourceResponse); + }); + + Thread.sleep(2000); + + // Assert document is retrieved + assertThat(capturedResponse, hasSize(1)); + } + + private static class TestObject { + @JsonProperty("mypk") + private String mypk; + + @JsonProperty("id") + private String id; + + @JsonProperty("prop") + private String prop; + } + + @Test(groups = {"samples"}, timeOut = TIMEOUT) + public void customSerialization() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + + TestObject testObject = new TestObject(); + testObject.id = UUID.randomUUID().toString(); + testObject.mypk = UUID.randomUUID().toString(); + testObject.prop = UUID.randomUUID().toString(); + String itemAsJsonString = mapper.writeValueAsString(testObject); + Document doc = new Document(itemAsJsonString); + + Document createdDocument = client + .createDocument(getCollectionLink(), doc, null, false) + .single() + .block() + .getResource(); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(testObject.mypk)); + + Document readDocument = client + .readDocument(createdDocument.selfLink(), options) + .single() + .block() + .getResource(); + + TestObject readObject = mapper.readValue(readDocument.toJson(), TestObject.class); + assertThat(readObject.prop, equalTo(testObject.prop)); + } + + /** + * You can convert a Flux to a CompletableFuture. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void transformObservableToCompletableFuture() throws Exception { + Document doc = new Document(String.format("{ 'id': 'doc%d', 'counter': '%d'}", RandomUtils.nextInt(), 1)); + Flux> createDocumentObservable = client + .createDocument(getCollectionLink(), doc, null, false); + CompletableFuture> listenableFuture = createDocumentObservable.single().toFuture(); + + ResourceResponse rrd = listenableFuture.get(); + + assertThat(rrd.getRequestCharge(), greaterThan((double) 0)); + System.out.print(rrd.getRequestCharge()); + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } + + private String getDocumentLink(Document createdDocument) { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id() + "/docs/" + createdDocument.id(); + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentQueryAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentQueryAsyncAPITest.java new file mode 100644 index 0000000000000..733097ab8cd7e --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/DocumentQueryAsyncAPITest.java @@ -0,0 +1,496 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.HttpConstants; +import org.apache.commons.lang3.RandomStringUtils; +import org.reactivestreams.Subscription; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; + +/** + * This integration test class demonstrates how to use Async API to query for + * Documents. + *

    + * NOTE: you can use rxJava based async api with java8 lambda expression. Use + * of rxJava based async APIs with java8 lambda expressions is much prettier. + *

    + * You can also use the async API without java8 lambda expression. + *

    + * For example + *

      + *
    • {@link #queryDocuments_Async()} demonstrates how to use async api + * with java8 lambda expression. + * + *
    • {@link #queryDocuments_Async_withoutLambda()} demonstrates how to do + * the same thing without lambda expression. + *
    + *

    + * Also if you need to work with Future or CompletableFuture it is possible to + * transform a flux to CompletableFuture. Please see + * {@link #transformObservableToCompletableFuture()} + */ +public class DocumentQueryAsyncAPITest extends DocumentClientTest { + + private final static int TIMEOUT = 3 * 60000; + + private AsyncDocumentClient client; + private DocumentCollection createdCollection; + private Database createdDatabase; + private int numberOfDocuments; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + + // CREATE database + + createdDatabase = Utils.createDatabaseForTest(client); + + // CREATE collection + createdCollection = client + .createCollection("dbs/" + createdDatabase.id(), collectionDefinition, null) + .single().block().getResource(); + + numberOfDocuments = 20; + // Add documents + for (int i = 0; i < numberOfDocuments; i++) { + Document doc = new Document(String.format("{ 'id': 'loc%d', 'counter': %d}", i, i)); + client.createDocument(getCollectionLink(), doc, null, true).single().block(); + } + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * Query for documents using java8 lambda expressions + * Creates a document query observable and verifies the async behavior + * of document query observable + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_Async() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux> documentQueryObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); + + final CountDownLatch mainThreadBarrier = new CountDownLatch(1); + + final CountDownLatch resultsCountDown = new CountDownLatch(numberOfDocuments); + + documentQueryObservable.subscribe(page -> { + try { + // Waits on the barrier + mainThreadBarrier.await(); + } catch (InterruptedException e) { + } + + for (@SuppressWarnings("unused") + Document d : page.results()) { + resultsCountDown.countDown(); + } + }); + + // The following code will run concurrently + System.out.println("action is subscribed to the observable"); + + // Release main thread barrier + System.out.println("after main thread barrier is released, subscribed observable action can continue"); + mainThreadBarrier.countDown(); + + System.out.println("waiting for all the results using result count down latch"); + + resultsCountDown.await(); + } + + /** + * Query for documents, without using java8 lambda expressions + * Creates a document query observable and verifies the async behavior + * of document query observable + * NOTE: does the same thing as testQueryDocuments_Async without java8 lambda + * expression + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_Async_withoutLambda() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux> documentQueryObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); + + final CountDownLatch mainThreadBarrier = new CountDownLatch(1); + + final CountDownLatch resultsCountDown = new CountDownLatch(numberOfDocuments); + + Consumer> actionPerPage = new Consumer>() { + + @SuppressWarnings("unused") + @Override + public void accept(FeedResponse t) { + + try { + // waits on the barrier + mainThreadBarrier.await(); + } catch (InterruptedException e) { + } + + for (Document d : t.results()) { + resultsCountDown.countDown(); + } + } + }; + + documentQueryObservable.subscribe(actionPerPage); + // The following code will run concurrently + + System.out.println("action is subscribed to the observable"); + + // Release main thread barrier + System.out.println("after main thread barrier is released, subscribed observable action can continue"); + mainThreadBarrier.countDown(); + + System.out.println("waiting for all the results using result count down latch"); + + resultsCountDown.await(); + } + + /** + * Queries for documents and sum up the total request charge + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_findTotalRequestCharge() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux totalChargeObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options) + .map(FeedResponse::requestCharge) // Map the page to its request charge + .reduce(Double::sum).flux(); // Sum up all the request charges + + final CountDownLatch successfulCompletionLatch = new CountDownLatch(1); + + totalChargeObservable.subscribe(totalCharge -> { + System.out.println(totalCharge); + successfulCompletionLatch.countDown(); + }); + + successfulCompletionLatch.await(); + } + + /** + * Subscriber unsubscribes after first page + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_unsubscribeAfterFirstPage() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux> requestChargeObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); + + AtomicInteger onNextCounter = new AtomicInteger(); + AtomicInteger onCompletedCounter = new AtomicInteger(); + AtomicInteger onErrorCounter = new AtomicInteger(); + + // Subscribe to the pages of Documents emitted by the observable + AtomicReference s = new AtomicReference<>(); + requestChargeObservable.subscribe(documentFeedResponse -> { + onNextCounter.incrementAndGet(); + s.get().cancel(); + }, error -> { + onErrorCounter.incrementAndGet(); + }, onCompletedCounter::incrementAndGet, subscription -> { + s.set(subscription); + subscription.request(1); + }); + + Thread.sleep(4000); + + // After subscriber unsubscribes, it doesn't receive any more pages. + assertThat(onNextCounter.get(), equalTo(1)); + assertThat(onCompletedCounter.get(), equalTo(0)); + assertThat(onErrorCounter.get(), equalTo(0)); + } + + /** + * Queries for documents and filter out the fetched results + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_filterFetchedResults() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Predicate isPrimeNumber = new Predicate() { + + @Override + public boolean test(Document doc) { + int n = doc.getInt("counter"); + if (n <= 1) + return false; + for (int i = 2; 2 * i < n; i++) { + if (n % i == 0) + return false; + } + return true; + } + }; + + List resultList = Collections.synchronizedList(new ArrayList()); + + client.queryDocuments(getCollectionLink(), "SELECT * FROM root", options) + .map(FeedResponse::results) // Map the page to the list of documents + .concatMap(Flux::fromIterable) // Flatten the Flux> to Flux + .filter(isPrimeNumber) // Filter documents using isPrimeNumber predicate + .subscribe(doc -> resultList.add(doc)); // Collect the results + + Thread.sleep(4000); + + int expectedNumberOfPrimes = 0; + // Find all the documents with prime number counter + for (int i = 0; i < numberOfDocuments; i++) { + boolean isPrime = true; + if (i <= 1) + isPrime = false; + for (int j = 2; 2 * j < i; j++) { + if (i % j == 0) { + isPrime = false; + break; + } + } + + if (isPrime) { + expectedNumberOfPrimes++; + } + } + + // Assert that we only collected what's expected + assertThat(resultList, hasSize(expectedNumberOfPrimes)); + } + + /** + * Queries for documents + * Converts the document query observable to blocking observable and + * uses that to find all documents + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void queryDocuments_toBlocking_toIterator() { + // Query for documents + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux> documentQueryObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); + + // Covert the observable to a blocking observable, then convert the blocking + // observable to an iterator + Iterator> it = documentQueryObservable.toIterable().iterator(); + + int pageCounter = 0; + int numberOfResults = 0; + while (it.hasNext()) { + FeedResponse page = it.next(); + pageCounter++; + + String pageSizeAsString = page.responseHeaders().get(HttpConstants.HttpHeaders.ITEM_COUNT); + assertThat("header item count must be present", pageSizeAsString, notNullValue()); + int pageSize = Integer.valueOf(pageSizeAsString); + assertThat("Result size must match header item count", page.results(), hasSize(pageSize)); + numberOfResults += pageSize; + } + assertThat("number of total results", numberOfResults, equalTo(numberOfDocuments)); + assertThat("number of result pages", pageCounter, + equalTo((numberOfDocuments + requestPageSize - 1) / requestPageSize)); + } + + /** + * Queries for documents using an Orderby query. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void qrderBy_Async() throws Exception { + // CREATE a partitioned collection + String collectionId = UUID.randomUUID().toString(); + DocumentCollection multiPartitionCollection = createMultiPartitionCollection("dbs/" + createdDatabase.id(), + collectionId, "/key"); + + // Insert documents + int totalNumberOfDocumentsInMultiPartitionCollection = 10; + for (int i = 0; i < totalNumberOfDocumentsInMultiPartitionCollection; i++) { + + Document doc = new Document(String.format("{\"id\":\"documentId%d\",\"key\":\"%s\",\"prop\":%d}", i, + RandomStringUtils.randomAlphabetic(2), i)); + client.createDocument("dbs/" + createdDatabase.id() + "/colls/" + multiPartitionCollection.id(), + doc, null, true).single().block(); + } + + // Query for the documents order by the prop field + SqlQuerySpec query = new SqlQuerySpec("SELECT r.id FROM r ORDER BY r.prop", new SqlParameterList()); + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(5); + + // Max degree of parallelism determines the number of partitions that + // the SDK establishes simultaneous connections to. + options.maxDegreeOfParallelism(2); + + // Get the observable order by query documents + Flux> documentQueryObservable = client.queryDocuments( + "dbs/" + createdDatabase.id() + "/colls/" + multiPartitionCollection.id(), query, options); + + List resultList = Collections.synchronizedList(new ArrayList<>()); + + documentQueryObservable.map(FeedResponse::results) + // Map the logical page to the list of documents in the page + .concatMap(Flux::fromIterable) // Flatten the list of documents + .map(Resource::id) // Map to the document Id + .subscribe(resultList::add); // Add each document Id to the resultList + + Thread.sleep(4000); + + // Assert we found all the results + assertThat(resultList, hasSize(totalNumberOfDocumentsInMultiPartitionCollection)); + for (int i = 0; i < totalNumberOfDocumentsInMultiPartitionCollection; i++) { + String docId = resultList.get(i); + // Assert that the order of the documents are valid + assertThat(docId, equalTo("documentId" + i)); + } + } + + /** + * You can convert a Flux to a CompletableFuture. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void transformObservableToCompletableFuture() throws Exception { + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux> documentQueryObservable = client + .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); + + // Convert to observable of list of pages + Mono>> allPagesObservable = documentQueryObservable.collectList(); + + // Convert the observable of list of pages to a Future + CompletableFuture>> future = allPagesObservable.toFuture(); + + List> pageList = future.get(); + + int totalNumberOfRetrievedDocuments = 0; + for (FeedResponse page : pageList) { + totalNumberOfRetrievedDocuments += page.results().size(); + } + assertThat(numberOfDocuments, equalTo(totalNumberOfRetrievedDocuments)); + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } + + private DocumentCollection createMultiPartitionCollection(String databaseLink, String collectionId, + String partitionKeyPath) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add(partitionKeyPath); + partitionKeyDef.paths(paths); + + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10100); + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(collectionId); + collectionDefinition.setPartitionKey(partitionKeyDef); + DocumentCollection createdCollection = client.createCollection(databaseLink, collectionDefinition, options) + .single().block().getResource(); + + return createdCollection; + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/InMemoryGroupbyTest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/InMemoryGroupbyTest.java new file mode 100644 index 0000000000000..333edfe75b0c2 --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/InMemoryGroupbyTest.java @@ -0,0 +1,188 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.GroupedFlux; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class InMemoryGroupbyTest extends DocumentClientTest { + + private final static int TIMEOUT = 60000; + + private AsyncDocumentClient client; + private Database createdDatabase; + private DocumentCollection createdCollection; + + @BeforeClass(groups = "samples", timeOut = 2 * TIMEOUT) + public void setUp() throws Exception { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + + // CREATE collection + createdCollection = client + .createCollection("dbs/" + createdDatabase.id(), collectionDefinition, null) + .single().block().getResource(); + + int numberOfPayers = 10; + int numberOfDocumentsPerPayer = 10; + + for (int i = 0; i < numberOfPayers; i++) { + + for (int j = 0; j < numberOfDocumentsPerPayer; j++) { + + LocalDateTime currentTime = LocalDateTime.now(); + + Document doc = new Document(String.format("{ " + + "'id' : '%s'," + + "'site_id': 'ABC', " + + "'payer_id': %d, " + + " 'created_time' : %d " + + "}", UUID.randomUUID().toString(), i, currentTime.getSecond())); + client.createDocument(getCollectionLink(), doc, null, true).single().block(); + + Thread.sleep(100); + } + } + System.out.println("finished inserting documents"); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + client.close(); + } + + /** + * Queries Documents and performs Group by operation after fetching the Documents. + * If you want to understand the steps in more details see {@link #groupByInMemory_MoreDetail()} + * @throws Exception + */ + @Test(groups = "samples", timeOut = 2 * TIMEOUT) + public void groupByInMemory() { + // If you want to understand the steps in more details see groupByInMemoryMoreDetail() + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux documentsObservable = client + .queryDocuments(getCollectionLink(), + new SqlQuerySpec("SELECT * FROM root r WHERE r.site_id=@site_id", + new SqlParameterList(new SqlParameter("@site_id", "ABC"))), + options) + .flatMap(page -> Flux.fromIterable(page.results())); + + final LocalDateTime now = LocalDateTime.now(); + + List> resultsGroupedAsLists = documentsObservable + .filter(doc -> Math.abs(now.getSecond() - doc.getInt("created_time")) <= 90) + .groupBy(doc -> doc.getInt("payer_id")).flatMap(Flux::collectList) + .collectList() + .block(); + + for(List resultsForEachPayer :resultsGroupedAsLists) { + System.out.println("documents with payer_id : " + resultsForEachPayer.get(0).getInt("payer_id") + " are " + resultsForEachPayer); + } + } + + /** + * This does the same thing as {@link #groupByInMemory_MoreDetail()} but with pedagogical details + * @throws Exception + */ + @Test(groups = "samples", timeOut = 2 * TIMEOUT) + public void groupByInMemory_MoreDetail() { + + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + options.enableCrossPartitionQuery(true); + + Flux documentsObservable = client + .queryDocuments(getCollectionLink(), + new SqlQuerySpec("SELECT * FROM root r WHERE r.site_id=@site_id", + new SqlParameterList(new SqlParameter("@site_id", "ABC"))), + options) + .flatMap(page -> Flux.fromIterable(page.results())); + + final LocalDateTime now = LocalDateTime.now(); + + Flux> groupedByPayerIdObservable = documentsObservable + .filter(doc -> Math.abs(now.getSecond() - doc.getInt("created_time")) <= 90) + .groupBy(doc -> doc.getInt("payer_id")); + + Flux> docsGroupedAsList = groupedByPayerIdObservable.flatMap(grouped -> { + Flux> list = grouped.collectList().flux(); + return list; + }); + + List> resultsGroupedAsLists = docsGroupedAsList.collectList().single().block(); + + for(List resultsForEachPayer : resultsGroupedAsLists) { + System.out.println("documents with payer_id : " + resultsForEachPayer.get(0).getInt("payer_id") + " are " + resultsForEachPayer); + } + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/OfferCRUDAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/OfferCRUDAsyncAPITest.java new file mode 100644 index 0000000000000..bfbd72ab5232c --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/OfferCRUDAsyncAPITest.java @@ -0,0 +1,177 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2017 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.internal.Offer; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * This integration test class demonstrates how to use Async API to query and + * replace an Offer. + */ +public class OfferCRUDAsyncAPITest extends DocumentClientTest { + private final static int TIMEOUT = 60000; + private Database createdDatabase; + private AsyncDocumentClient client; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * Query for all the offers existing in the database account. + * REPLACE the required offer so that it has a higher throughput. + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void updateOffer() throws Exception { + + int initialThroughput = 10200; + int newThroughput = 10300; + + // Set the throughput to be 10,200 + RequestOptions multiPartitionRequestOptions = new RequestOptions(); + multiPartitionRequestOptions.setOfferThroughput(initialThroughput); + + // CREATE the collection + DocumentCollection createdCollection = client.createCollection("dbs/" + createdDatabase.id(), + getMultiPartitionCollectionDefinition(), multiPartitionRequestOptions).single().block() + .getResource(); + + final CountDownLatch successfulCompletionLatch = new CountDownLatch(1); + + // Find offer associated with this collection + client.queryOffers( + String.format("SELECT * FROM r where r.offerResourceId = '%s'", createdCollection.resourceId()), + null).flatMap(offerFeedResponse -> { + List offerList = offerFeedResponse.results(); + // NUMBER of offers returned should be 1 + assertThat(offerList.size(), equalTo(1)); + + // This offer must correspond to the collection we created + Offer offer = offerList.get(0); + int currentThroughput = offer.getThroughput(); + assertThat(offer.getString("offerResourceId"), equalTo(createdCollection.resourceId())); + assertThat(currentThroughput, equalTo(initialThroughput)); + System.out.println("initial throughput: " + currentThroughput); + + // UPDATE the offer's throughput + offer.setThroughput(newThroughput); + + // REPLACE the offer + return client.replaceOffer(offer); + }).subscribe(offerResourceResponse -> { + Offer offer = offerResourceResponse.getResource(); + int currentThroughput = offer.getThroughput(); + + // The current throughput of the offer must be equal to the new throughput value + assertThat(offer.getString("offerResourceId"), equalTo(createdCollection.resourceId())); + assertThat(currentThroughput, equalTo(newThroughput)); + + System.out.println("updated throughput: " + currentThroughput); + successfulCompletionLatch.countDown(); + }, error -> { + System.err + .println("an error occurred while updating the offer: actual cause: " + error.getMessage()); + }); + + successfulCompletionLatch.await(); + } + + private DocumentCollection getMultiPartitionCollectionDefinition() { + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + + // Set the partitionKeyDefinition for a partitioned collection + // Here, we are setting the partitionKey of the Collection to be /city + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + List paths = new ArrayList<>(); + paths.add("/city"); + partitionKeyDefinition.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDefinition); + + // Set indexing policy to be range range for string and number + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + collectionDefinition.setIndexingPolicy(indexingPolicy); + + return collectionDefinition; + } +} \ No newline at end of file diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/StoredProcedureAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/StoredProcedureAsyncAPITest.java new file mode 100644 index 0000000000000..e0159e7510340 --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/StoredProcedureAsyncAPITest.java @@ -0,0 +1,274 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2017 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.internal.HttpConstants; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CountDownLatch; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.core.Is.is; + +/** + * This integration test class demonstrates how to use Async API to create + * and execute Stored Procedures. + */ +public class StoredProcedureAsyncAPITest extends DocumentClientTest { + private final static int TIMEOUT = 60000; + + private Database createdDatabase; + private DocumentCollection createdCollection; + private AsyncDocumentClient client; + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + createdDatabase = Utils.createDatabaseForTest(client); + + createdCollection = client + .createCollection("dbs/" + createdDatabase.id(), getMultiPartitionCollectionDefinition(), null) + .single().block().getResource(); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + /** + * Execute Stored Procedure and retrieve the Script Log + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void scriptConsoleLogEnabled() throws Exception { + // CREATE a stored procedure + StoredProcedure storedProcedure = new StoredProcedure( + "{" + + " 'id':'storedProcedureSample'," + + " 'body':" + + " 'function() {" + + " var mytext = \"x\";" + + " var myval = 1;" + + " try {" + + " console.log(\"The value of %s is %s.\", mytext, myval);" + + " getContext().getResponse().setBody(\"Success!\");" + + " }" + + " catch(err) {" + + " getContext().getResponse().setBody(\"inline err: [\" + err.number + \"] \" + err);" + + " }" + + " }'" + + "}"); + + storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedure, null) + .single().block().getResource(); + + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setScriptLoggingEnabled(true); + requestOptions.setPartitionKey(new PartitionKey("Seattle")); + + final CountDownLatch successfulCompletionLatch = new CountDownLatch(1); + + // Execute the stored procedure + client.executeStoredProcedure(getSprocLink(storedProcedure), requestOptions, new Object[]{}) + .subscribe(storedProcedureResponse -> { + String logResult = "The value of x is 1."; + try { + assertThat(URLDecoder.decode(storedProcedureResponse.getScriptLog(), "UTF-8"), is(logResult)); + assertThat(URLDecoder.decode(storedProcedureResponse.getResponseHeaders() + .get(HttpConstants.HttpHeaders.SCRIPT_LOG_RESULTS), "UTF-8"), is(logResult)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + successfulCompletionLatch.countDown(); + System.out.println(storedProcedureResponse.getActivityId()); + }, error -> { + System.err.println("an error occurred while executing the stored procedure: actual cause: " + + error.getMessage()); + }); + + successfulCompletionLatch.await(); + } + + /** + * Execute Stored Procedure that takes arguments + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void executeStoredProcWithArgs() throws Exception { + // CREATE stored procedure + StoredProcedure storedProcedure = new StoredProcedure( + "{" + + " 'id': 'multiplySample'," + + " 'body':" + + " 'function (value, num) {" + + " getContext().getResponse().setBody(" + + " \"2*\" + value + \" is \" + num * 2 );" + + " }'" + + "}"); + + storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedure, null) + .single().block().getResource(); + + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey("Seattle")); + + final CountDownLatch successfulCompletionLatch = new CountDownLatch(1); + + // Execute the stored procedure + Object[] storedProcedureArgs = new Object[]{"a", 123}; + client.executeStoredProcedure(getSprocLink(storedProcedure), requestOptions, storedProcedureArgs) + .subscribe(storedProcedureResponse -> { + String storedProcResultAsString = storedProcedureResponse.getResponseAsString(); + assertThat(storedProcResultAsString, equalTo("\"2*a is 246\"")); + successfulCompletionLatch.countDown(); + System.out.println(storedProcedureResponse.getActivityId()); + }, error -> { + System.err.println("an error occurred while executing the stored procedure: actual cause: " + + error.getMessage()); + }); + + successfulCompletionLatch.await(); + } + + /** + * Execute Stored Procedure that takes arguments, passing a Pojo object + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void executeStoredProcWithPojoArgs() throws Exception { + // create stored procedure + StoredProcedure storedProcedure = new StoredProcedure( + "{" + + " 'id': 'storedProcedurePojoSample'," + + " 'body':" + + " 'function (value) {" + + " getContext().getResponse().setBody(" + + " \"a is \" + value.temp);" + + " }'" + + "}"); + + storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedure, null) + .single().block().getResource(); + + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey("Seattle")); + + final CountDownLatch successfulCompletionLatch = new CountDownLatch(1); + + // POJO + class SamplePojo { + public String temp = "my temp value"; + } + SamplePojo samplePojo = new SamplePojo(); + + // Execute the stored procedure + Object[] storedProcedureArgs = new Object[]{samplePojo}; + client.executeStoredProcedure(getSprocLink(storedProcedure), requestOptions, storedProcedureArgs) + .subscribe(storedProcedureResponse -> { + String storedProcResultAsString = storedProcedureResponse.getResponseAsString(); + assertThat(storedProcResultAsString, equalTo("\"a is my temp value\"")); + successfulCompletionLatch.countDown(); + System.out.println(storedProcedureResponse.getActivityId()); + }, error -> { + System.err.println("an error occurred while executing the stored procedure: actual cause: " + + error.getMessage()); + }); + + successfulCompletionLatch.await(); + } + + private static DocumentCollection getMultiPartitionCollectionDefinition() { + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + + // Set the partitionKeyDefinition for a partitioned collection + // Here, we are setting the partitionKey of the Collection to be /city + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + List paths = new ArrayList(); + paths.add("/city"); + partitionKeyDefinition.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDefinition); + + // Set indexing policy to be range range for string and number + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + List indexes = new ArrayList(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + collectionDefinition.setIndexingPolicy(indexingPolicy); + + return collectionDefinition; + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } + + private String getSprocLink(StoredProcedure sproc) { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id() + "/sprocs/" + sproc.id(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TestConfigurations.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TestConfigurations.java new file mode 100644 index 0000000000000..7054ca8e7a08d --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TestConfigurations.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; + +/** + * Contains the configurations for tests. + *

    + * For running tests, you can pass a customized endpoint configuration in one of the following + * ways: + *

      + *
    • -DACCOUNT_KEY="[your-key]" -ACCOUNT_HOST="[your-endpoint]" as JVM + * command-line option.
    • + *
    • You can set ACCOUNT_KEY and ACCOUNT_HOST as environment variables.
    • + *
    + *

    + * If none of the above is set, emulator endpoint will be used. + */ +public final class TestConfigurations { + // REPLACE MASTER_KEY and HOST with values from your Azure Cosmos DB account. + // The default values are credentials of the local emulator, which are not used in any production environment. + // + public static String MASTER_KEY = + System.getProperty("ACCOUNT_KEY", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_KEY")), + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==")); + + public static String HOST = + System.getProperty("ACCOUNT_HOST", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_HOST")), + "https://localhost:443/")); +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TokenResolverTest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TokenResolverTest.java new file mode 100644 index 0000000000000..810d8409a0105 --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/TokenResolverTest.java @@ -0,0 +1,342 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosResourceType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.Permission; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.TokenResolver; +import com.azure.data.cosmos.internal.User; +import com.google.common.collect.ImmutableMap; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.core.IsInstanceOf.instanceOf; + +public class TokenResolverTest extends DocumentClientTest { + + private final static int TIMEOUT = 180000; + private final static String USER_ID = "userId"; + private AsyncDocumentClient client; + private Database createdDatabase; + private DocumentCollection createdCollection; + private Map userToReadOnlyResourceTokenMap = new HashMap<>(); + private Map documentToReadUserMap = new HashMap<>(); + + private Map documentToReadWriteUserMap = new HashMap<>(); + private Map userToReadWriteResourceTokenMap = new HashMap<>(); + + + /** + * This Example walks you through how to use a token resolver to + * control authorization and access to Cosmos DB resources. + */ + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + + // CREATE collection + createdCollection = client + .createCollection("dbs/" + createdDatabase.id(), collectionDefinition, null) + .single().block().getResource(); + + for (int i = 0; i < 10; i++) { + // CREATE a document + Document documentDefinition = new Document(); + documentDefinition.id(UUID.randomUUID().toString()); + Document createdDocument = client.createDocument(createdCollection.selfLink(), documentDefinition, null, true).blockFirst().getResource(); + + // CREATE a User who is meant to only read this document + User readUserDefinition = new User(); + readUserDefinition.id(UUID.randomUUID().toString()); + User createdReadUser = client.createUser(createdDatabase.selfLink(), readUserDefinition, null).blockFirst().getResource(); + + // CREATE a read only permission for the above document + Permission readOnlyPermissionDefinition = new Permission(); + readOnlyPermissionDefinition.id(UUID.randomUUID().toString()); + readOnlyPermissionDefinition.setResourceLink(createdDocument.selfLink()); + readOnlyPermissionDefinition.setPermissionMode(PermissionMode.READ); + + // Assign the permission to the above user + Permission readOnlyCreatedPermission = client.createPermission(createdReadUser.selfLink(), readOnlyPermissionDefinition, null).blockFirst().getResource(); + userToReadOnlyResourceTokenMap.put(createdReadUser.id(), readOnlyCreatedPermission.getToken()); + + documentToReadUserMap.put(createdDocument.selfLink(), createdReadUser.id()); + + // CREATE a User who can both read and write this document + User readWriteUserDefinition = new User(); + readWriteUserDefinition.id(UUID.randomUUID().toString()); + User createdReadWriteUser = client.createUser(createdDatabase.selfLink(), readWriteUserDefinition, null).blockFirst().getResource(); + + // CREATE a read/write permission for the above document + Permission readWritePermissionDefinition = new Permission(); + readWritePermissionDefinition.id(UUID.randomUUID().toString()); + readWritePermissionDefinition.setResourceLink(createdDocument.selfLink()); + readWritePermissionDefinition.setPermissionMode(PermissionMode.ALL); + + // Assign the permission to the above user + Permission readWriteCreatedPermission = client.createPermission(createdReadWriteUser.selfLink(), readWritePermissionDefinition, null).blockFirst().getResource(); + userToReadWriteResourceTokenMap.put(createdReadWriteUser.id(), readWriteCreatedPermission.getToken()); + + documentToReadWriteUserMap.put(createdDocument.selfLink(), createdReadWriteUser.id()); + } + } + + /** + * READ a document with a user having read permission + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void readDocumentThroughTokenResolver() throws Exception { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolverForRead()) + .build(); + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + for (String documentLink : documentToReadUserMap.keySet()) { + + // Each document has one User who can only read it. Pass that User Id in the item. + // The token resolver will resolve the token for that User based on 'userId'. + ImmutableMap properties = ImmutableMap. builder() + .put(USER_ID, documentToReadUserMap.get(documentLink)) + .build(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setProperties(properties); + requestOptions.setPartitionKey(PartitionKey.None); + Flux> readDocumentObservable = asyncClientWithTokenResolver + .readDocument(documentLink, requestOptions); + readDocumentObservable.collectList().block().forEach(capturedResponse::add); + } + System.out.println("capturedResponse.size() = " + capturedResponse.size()); + assertThat(capturedResponse, hasSize(10)); + } finally { + Utils.safeClose(asyncClientWithTokenResolver); + } + } + + /** + * DELETE a document with a user having all permission + */ + @Test(groups = "samples", timeOut = TIMEOUT, dependsOnMethods = {"readDocumentThroughTokenResolver"}) + public void deleteDocumentThroughTokenResolver() throws Exception { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolverForReadWrite()) + .build(); + List> capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + for (String documentLink : documentToReadWriteUserMap.keySet()) { + + // Each document has one User who can read and write it. Pass that User Id in the item. + // The token resolver will resolve the token for that User based on 'userId'. + ImmutableMap properties = ImmutableMap. builder() + .put(USER_ID, documentToReadWriteUserMap.get(documentLink)) + .build(); + + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setProperties(properties); + requestOptions.setPartitionKey(PartitionKey.None); + Flux> readDocumentObservable = asyncClientWithTokenResolver + .deleteDocument(documentLink, requestOptions); + readDocumentObservable.collectList().block().forEach(capturedResponse::add); + } + assertThat(capturedResponse, hasSize(10)); + } finally { + Utils.safeClose(asyncClientWithTokenResolver); + } + } + + /** + * Block list an user and throw error from token resolver + */ + @Test(groups = "samples", timeOut = TIMEOUT) + public void blockListUserThroughTokenResolver() throws Exception { + String blockListedUserId = "block listed user"; + String errorMessage = "block listed user! access denied!"; + + AsyncDocumentClient asyncClientWithTokenResolver = null; + + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolverWithBlockList(blockListedUserId, errorMessage)) + .build(); + + // READ a document using a block listed user, passing the 'userId' in the item. + // Token resolver will throw RuntimeException. + RequestOptions options = new RequestOptions(); + ImmutableMap properties = ImmutableMap. builder() + .put(USER_ID, blockListedUserId) + .build(); + + options.setProperties(properties); + Flux> readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), options); + List capturedErrors = Collections + .synchronizedList(new ArrayList<>()); + readObservable.subscribe(response -> {}, throwable -> capturedErrors.add(throwable)); + Thread.sleep(4000); + assertThat(capturedErrors, hasSize(1)); + assertThat(capturedErrors.get(0), instanceOf(RuntimeException.class)); + assertThat(capturedErrors.get(0).getMessage(), equalTo(errorMessage)); + + // READ a document using a valid user, passing the 'userId' in the item. + // Token resolver will pass on the correct token for authentication. + String validUserId = userToReadWriteResourceTokenMap.keySet().iterator().next(); + System.out.println(validUserId); + properties = ImmutableMap. builder() + .put(USER_ID, validUserId) + .build(); + options.setProperties(properties); + readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), options); + List capturedResponse = Collections + .synchronizedList(new ArrayList<>()); + readObservable.subscribe(resourceResponse -> capturedResponse.add(resourceResponse.getResource()), error -> error.printStackTrace()); + Thread.sleep(4000); + assertThat(capturedErrors, hasSize(1)); + assertThat(capturedResponse.get(0).id(), equalTo(createdCollection.id())); + } finally { + Utils.safeClose(asyncClientWithTokenResolver); + } + } + + /** + * For Reading DatabaseAccount on client initialization, use any User's token. + * For subsequent Reads, get the correct read only token based on 'userId'. + */ + private TokenResolver getTokenResolverForRead() { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + if (resourceType.equals(CosmosResourceType.System)) { + //Choose any token it should have the read access on database account + for (String token : userToReadOnlyResourceTokenMap.values()) { + return token; + } + } else { + return userToReadOnlyResourceTokenMap.get(properties.get(USER_ID)); + } + return null; + }; + } + + /** + * For Reading DatabaseAccount on client initialization, use any User's token. + * For subsequent Reads/Writes, get the correct read/write token based on 'userId'. + */ + private TokenResolver getTokenResolverForReadWrite() { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + if (resourceType.equals(CosmosResourceType.System)) { + //Choose any token it should have the read access on database account + for (String token : userToReadWriteResourceTokenMap.values()) { + return token; + } + } else { + return userToReadWriteResourceTokenMap.get(properties.get(USER_ID)); + } + return null; + }; + } + + /** + * For Reading DatabaseAccount on client initialization, use any User's token. + * For subsequent Reads, get the correct read/write token based on 'userId', + * only if user is not block listed. In this scenario, the block listed user id + * is compared to the current user's id, passed into the item for the request. + */ + private TokenResolver getTokenResolverWithBlockList(String blockListedUserId, String errorMessage) { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + if (resourceType == CosmosResourceType.System) { + return userToReadWriteResourceTokenMap.values().iterator().next(); + } else if (!properties.get(USER_ID).toString().equals(blockListedUserId)) { + return userToReadWriteResourceTokenMap.get(properties.get(USER_ID)); + } else { + throw new RuntimeException(errorMessage); + } + }; + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/UniqueIndexAsyncAPITest.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/UniqueIndexAsyncAPITest.java new file mode 100644 index 0000000000000..f1d48c7f0197f --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/UniqueIndexAsyncAPITest.java @@ -0,0 +1,133 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.UniqueKey; +import com.azure.data.cosmos.UniqueKeyPolicy; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import io.reactivex.subscribers.TestSubscriber; +import org.hamcrest.Matchers; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +public class UniqueIndexAsyncAPITest extends DocumentClientTest { + + private final static int TIMEOUT = 60000; + + private AsyncDocumentClient client; + private Database createdDatabase; + + @Test(groups = "samples", timeOut = TIMEOUT) + public void uniqueIndex() { + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); + UniqueKey uniqueKey = new UniqueKey(); + uniqueKey.paths(ImmutableList.of("/name", "/field")); + uniqueKeyPolicy.uniqueKeys(Lists.newArrayList(uniqueKey)); + collectionDefinition.setUniqueKeyPolicy(uniqueKeyPolicy); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); + + DocumentCollection collection = client.createCollection(getDatabaseLink(), collectionDefinition, null).single().block().getResource(); + + Document doc1 = new Document("{ 'name':'Alan Turning', 'field': 'Mathematics', 'other' : 'Logic' }"); + Document doc2 = new Document("{ 'name':'Al-Khwarizmi', 'field': 'Mathematics' , 'other' : 'Algebra '}"); + Document doc3 = new Document("{ 'name':'Alan Turning', 'field': 'Mathematics', 'other' : 'CS' }"); + + client.createDocument(getCollectionLink(collection), doc1, null, false).single().block().getResource(); + client.createDocument(getCollectionLink(collection), doc2, null, false).single().block().getResource(); + + // doc1 got inserted with the same values for 'name' and 'field' + // so inserting a new one with the same values will violate unique index constraint. + Flux> docCreation = + client.createDocument(getCollectionLink(collection), doc3, null, false); + + TestSubscriber> subscriber = new TestSubscriber<>(); + docCreation.subscribe(subscriber); + + subscriber.awaitTerminalEvent(); + subscriber.assertError(CosmosClientException.class); + assertThat(subscriber.errorCount(), Matchers.equalTo(1)); + + // error code for failure is conflict + assertThat(((CosmosClientException) subscriber.getEvents().get(1).get(0)).statusCode(), equalTo(409)); + } + + @BeforeClass(groups = "samples", timeOut = TIMEOUT) + public void setUp() { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy().connectionMode(ConnectionMode.DIRECT); + + this.clientBuilder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + + this.client = this.clientBuilder().build(); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + + // CREATE database + createdDatabase = Utils.createDatabaseForTest(client); + } + + @AfterClass(groups = "samples", timeOut = TIMEOUT) + public void shutdown() { + Utils.safeClean(client, createdDatabase); + Utils.safeClose(client); + } + + private String getCollectionLink(DocumentCollection collection) { + return "dbs/" + createdDatabase.id() + "/colls/" + collection.id(); + } + + private String getDatabaseLink() { + return "dbs/" + createdDatabase.id(); + } +} diff --git a/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/Utils.java b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/Utils.java new file mode 100644 index 0000000000000..87d3ab1a170ec --- /dev/null +++ b/sdk/cosmos/examples/src/test/java/com/azure/data/cosmos/rx/examples/Utils.java @@ -0,0 +1,124 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx.examples; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DatabaseForTest; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.RetryOptions; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.TestConfigurations; +import org.testng.annotations.AfterSuite; +import reactor.core.publisher.Flux; + +public class Utils { + + @AfterSuite(groups = "samples") + public void cleanupStaleDatabase() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + RetryOptions options = new RetryOptions(); + connectionPolicy.retryOptions(options); + AsyncDocumentClient client = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + safeCleanDatabases(client); + client.close(); + } + + public static String getCollectionLink(Database db, DocumentCollection collection) { + return "dbs/" + db.id() + "/colls/" + collection; + } + + public static Database createDatabaseForTest(AsyncDocumentClient client) { + return DatabaseForTest.create(DatabaseManagerImpl.getInstance(client)).createdDatabase; + } + + private static void safeCleanDatabases(AsyncDocumentClient client) { + if (client != null) { + DatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(client)); + } + } + + public static void safeClean(AsyncDocumentClient client, Database database) { + if (database != null) { + safeClean(client, database.id()); + } + } + + public static void safeClean(AsyncDocumentClient client, String databaseId) { + if (client != null) { + if (databaseId != null) { + try { + client.deleteDatabase("/dbs/" + databaseId, null).single().block(); + } catch (Exception e) { + } + } + } + } + + public static String generateDatabaseId() { + return DatabaseForTest.generateId(); + } + + public static void safeClose(AsyncDocumentClient client) { + if (client != null) { + client.close(); + } + } + + private static class DatabaseManagerImpl implements DatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(AsyncDocumentClient client) { + return new DatabaseManagerImpl(client); + } + + private final AsyncDocumentClient client; + + private DatabaseManagerImpl(AsyncDocumentClient client) { + this.client = client; + } + + @Override + public Flux> queryDatabases(SqlQuerySpec query) { + return client.queryDatabases(query, null); + } + + @Override + public Flux> createDatabase(Database databaseDefinition) { + return client.createDatabase(databaseDefinition, null); + } + + @Override + public Flux> deleteDatabase(String id) { + + return client.deleteDatabase("dbs/" + id, null); + } + } +} diff --git a/sdk/cosmos/examples/src/test/resources/log4j.properties b/sdk/cosmos/examples/src/test/resources/log4j.properties new file mode 100644 index 0000000000000..b7947ea7907d1 --- /dev/null +++ b/sdk/cosmos/examples/src/test/resources/log4j.properties @@ -0,0 +1,13 @@ +# this is the log4j configuration for tests + +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=INFO, A1 + +log4j.category.io.netty=INFO +log4j.category.io.reactivex=INFO +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n diff --git a/sdk/cosmos/faq/README.md b/sdk/cosmos/faq/README.md new file mode 100644 index 0000000000000..8fa637f1570d8 --- /dev/null +++ b/sdk/cosmos/faq/README.md @@ -0,0 +1,9 @@ + +### FAQ + +#### I am getting this error: + +- ``Request Rate too Large`` Request too large is an error from service indicating that you temporarily went beyond the provisioned throughput. You should retry after the provided +``DocumentClientException#getRetryAfterInMilliseconds()``. + +- ``CollectionPoolExhausted`` this is a SDK side error indicating that the SDK's connection pool is saturated. Consider to retry later, increase the connection pool size or use a semaphore to throttle your workload. diff --git a/sdk/cosmos/pom.xml b/sdk/cosmos/pom.xml new file mode 100644 index 0000000000000..2c3e793e2c91a --- /dev/null +++ b/sdk/cosmos/pom.xml @@ -0,0 +1,414 @@ + + + 4.0.0 + com.microsoft.azure + azure-cosmos-parent + 3.0.0 + pom + Azure Cosmos DB SQL API + Java Async SDK (with Reactive Extension RX support) for Azure Cosmos DB SQL API + https://docs.microsoft.com/en-us/azure/cosmos-db + + sdk + benchmark + examples + + + UTF-8 + UTF-8 + 3.11.1 + 2.5 + 3.8.1 + 1.6 + 1.6 + 1.6 + 3.0.0 + 3.0.0 + 27.0.1-jre + 1.3 + 2.9.8 + 3.1.4 + 1.58 + 1.2.17 + 4.0.5 + 1.10.19 + 4.1.36.Final + 2.0.25.Final + 3.2.2.RELEASE + Californium-SR7 + 2.2.4 + 3.0.0 + 1.7.6 + unit + 6.14.3 + ${project.basedir}/target/collectedArtifactsForRelease + + + + + + unit + + default + unit + + + true + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + + + fast + + simple,cosmosv3 + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + long + + long + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + direct + + direct + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + multi-master + + multi-master + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + examples + + + samples,examples + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + integration-test + verify + + + + + + + + + + emulator + + emulator + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + non-emulator + + non-emulator + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + e2e + + e2e + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.0 + + unit + + %regex[.*] + + + + surefire.testng.verbose + 2 + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.22.0 + + + %regex[.*] + + + + surefire.testng.verbose + 2 + + + ${test.groups} + + + + + integration-test + verify + + + + + + + + + maven-javadoc-plugin + 3.0.1 + true + + true + false + ${javadoc.opts} + + **/internal/**/*.java + **/*BridgeInternal.java + + + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.8 + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8 + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + + default-cli + + + + + + + + + + + + run + + + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.22.0 + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.4 + + + org.apache.maven.plugins + maven-jxr-plugin + 2.1 + + + + + + + com.microsoft.azure + azure-cosmos + ${project.parent.version} + + + io.projectreactor + reactor-bom + ${reactor-bom.version} + pom + import + + + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + scm:git:https://github.com/Azure/azure-cosmosdb-java.git + scm:git:https://github.com/Azure/azure-cosmosdb-java.git + https://github.com/Azure/azure-cosmosdb-java.git + + + + Azure Cosmos DB Developer Platform Devs + docdbdevplatdevs@microsoft.com + Microsoft + http://www.microsoft.com/ + + + diff --git a/sdk/cosmos/sdk/CosmosConflict b/sdk/cosmos/sdk/CosmosConflict new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/sdk/cosmos/sdk/pom.xml b/sdk/cosmos/sdk/pom.xml new file mode 100644 index 0000000000000..9481c2952c1b8 --- /dev/null +++ b/sdk/cosmos/sdk/pom.xml @@ -0,0 +1,280 @@ + + + 4.0.0 + + com.microsoft.azure + azure-cosmos-parent + 3.0.0 + + azure-cosmos + Async SDK for SQL API of Azure Cosmos DB Service + Java Async SDK (with Reactive Extension rx support) for Azure Cosmos DB SQL API + jar + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-eclipse-plugin + 2.8 + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8 + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + false + + + none + default-cli + + + + true + + + + + + + + fast + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + src/test/resources/fast-testng.xml + + + + + + + + + long + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + src/test/resources/long-testng.xml + + + + + + + + + emulator + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + src/test/resources/emulator-testng.xml + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.19.1 + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.4 + + + org.apache.maven.plugins + maven-jxr-plugin + 2.1 + + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson-databind.version} + + + com.fasterxml.uuid + java-uuid-generator + ${java-uuid-generator.version} + + + commons-io + commons-io + ${commons-io.version} + + + commons-validator + commons-validator + ${commons-validator.version} + + + io.projectreactor + reactor-core + + + io.netty + netty-codec-http + ${netty.version} + + + io.netty + netty-handler + ${netty.version} + + + io.netty + netty-transport + ${netty.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + org.apache.commons + commons-collections4 + 4.2 + + + org.apache.commons + commons-text + ${commons-text.version} + + + org.testng + testng + ${testng.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + test + + + log4j + log4j + ${log4j.version} + test + + + com.google.guava + guava + ${guava.version} + + + io.projectreactor + reactor-test + test + + + io.reactivex.rxjava2 + rxjava + ${rxjava2.version} + + + io.projectreactor.netty + reactor-netty + + + io.projectreactor.addons + reactor-adapter + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + + + org.mockito + mockito-core + ${mockito.version} + test + + + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessCondition.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessCondition.java new file mode 100644 index 0000000000000..4ea7951980ce8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessCondition.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Represents a set of access conditions to be used for operations against the Azure Cosmos DB database service. + */ +public final class AccessCondition { + + private AccessConditionType type = AccessConditionType.IF_MATCH; + private String condition; + + /** + * Gets the condition type. + * + * @return the condition type. + */ + public AccessConditionType type() { + return this.type; + } + + /** + * Sets the condition type. + * + * @param type the condition type to use. + * @return the Access Condition + */ + public AccessCondition type(AccessConditionType type) { + this.type = type; + return this; + } + + /** + * Gets the value of the condition - for AccessConditionType IfMatchs and IfNotMatch, this is the ETag that has to + * be compared to. + * + * @return the condition. + */ + public String condition() { + return this.condition; + } + + /** + * Sets the value of the condition - for AccessConditionType IfMatchs and IfNotMatch, this is the ETag that has to + * be compared to. + * + * @param condition the condition to use. + * @return the Access Condition + */ + public AccessCondition condition(String condition) { + this.condition = condition; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessConditionType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessConditionType.java new file mode 100644 index 0000000000000..7dd4538e76c75 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/AccessConditionType.java @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Specifies the set of access condition types that can be used for operations in the Azure Cosmos DB database service. + */ +public enum AccessConditionType { + /** + * Check if the resource's ETag value matches the ETag value performed. + */ + IF_MATCH, + + /** + * Check if the resource's ETag value does not match ETag value performed. + */ + IF_NONE_MATCH +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BadRequestException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BadRequestException.java new file mode 100644 index 0000000000000..7785b882f7a6b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BadRequestException.java @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class BadRequestException extends CosmosClientException { + private static final long serialVersionUID = 1L; + + public BadRequestException(String message, Exception innerException) { + super(message, innerException, new HashMap<>(), HttpConstants.StatusCodes.BADREQUEST, null); + } + + public BadRequestException() { + this(RMResources.BadRequest); + } + + public BadRequestException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.BADREQUEST, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public BadRequestException(String message) { + this(message, null, null, null); + } + + BadRequestException(String message, HttpHeaders headers, String requestUrlString) { + this(message, null, headers, requestUrlString); + } + + public BadRequestException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + BadRequestException(Exception innerException) { + this(RMResources.BadRequest, innerException, null, null); + } + + BadRequestException(String message, + Exception innerException, + HttpHeaders headers, + String requestUrlString) { + super(String.format("%s: %s", RMResources.BadRequest, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.BADREQUEST, + requestUrlString); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BridgeInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BridgeInternal.java new file mode 100644 index 0000000000000..f0e29b03accd6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/BridgeInternal.java @@ -0,0 +1,438 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.ReplicationPolicy; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.StoredProcedureResponse; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.directconnectivity.StoreResult; +import com.azure.data.cosmos.internal.query.metrics.ClientSideMetrics; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.net.URI; +import java.time.OffsetDateTime; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentMap; + +import static com.azure.data.cosmos.internal.Constants.QueryExecutionContext.INCREMENTAL_FEED_HEADER_VALUE; + +/** + * This is meant to be used only internally as a bridge access to classes in + * com.azure.data.cosmos + **/ +public class BridgeInternal { + + public static CosmosError createCosmosError(ObjectNode objectNode) { + return new CosmosError(objectNode); + } + + public static CosmosError createCosmosError(String jsonString) { + return new CosmosError(jsonString); + } + + public static Document documentFromObject(Object document, ObjectMapper mapper) { + return Document.FromObject(document, mapper); + } + + public static ResourceResponse toResourceResponse(RxDocumentServiceResponse response, + Class cls) { + return new ResourceResponse(response, cls); + } + + public static FeedResponse toFeedResponsePage(RxDocumentServiceResponse response, + Class cls) { + return new FeedResponse(response.getQueryResponse(cls), response.getResponseHeaders()); + } + + public static FeedResponse toChaneFeedResponsePage(RxDocumentServiceResponse response, + Class cls) { + return new FeedResponse(noChanges(response) ? Collections.emptyList() : response.getQueryResponse(cls), + response.getResponseHeaders(), noChanges(response)); + } + + public static StoredProcedureResponse toStoredProcedureResponse(RxDocumentServiceResponse response) { + return new StoredProcedureResponse(response); + } + + public static DatabaseAccount toDatabaseAccount(RxDocumentServiceResponse response) { + DatabaseAccount account = response.getResource(DatabaseAccount.class); + + // read the headers and set to the account + Map responseHeader = response.getResponseHeaders(); + + account.setMaxMediaStorageUsageInMB( + Long.valueOf(responseHeader.get(HttpConstants.HttpHeaders.MAX_MEDIA_STORAGE_USAGE_IN_MB))); + account.setMediaStorageUsageInMB( + Long.valueOf(responseHeader.get(HttpConstants.HttpHeaders.CURRENT_MEDIA_STORAGE_USAGE_IN_MB))); + + return account; + } + + public static Map getFeedHeaders(ChangeFeedOptions options) { + + if (options == null) + return new HashMap<>(); + + Map headers = new HashMap<>(); + + if (options.maxItemCount() != null) { + headers.put(HttpConstants.HttpHeaders.PAGE_SIZE, options.maxItemCount().toString()); + } + + String ifNoneMatchValue = null; + if (options.requestContinuation() != null) { + ifNoneMatchValue = options.requestContinuation(); + } else if (!options.startFromBeginning()) { + ifNoneMatchValue = "*"; + } + // On REST level, change feed is using IF_NONE_MATCH/ETag instead of + // continuation. + if (ifNoneMatchValue != null) { + headers.put(HttpConstants.HttpHeaders.IF_NONE_MATCH, ifNoneMatchValue); + } + + headers.put(HttpConstants.HttpHeaders.A_IM, INCREMENTAL_FEED_HEADER_VALUE); + + return headers; + } + + public static Map getFeedHeaders(FeedOptions options) { + + if (options == null) + return new HashMap<>(); + + Map headers = new HashMap<>(); + + if (options.maxItemCount() != null) { + headers.put(HttpConstants.HttpHeaders.PAGE_SIZE, options.maxItemCount().toString()); + } + + if (options.requestContinuation() != null) { + headers.put(HttpConstants.HttpHeaders.CONTINUATION, options.requestContinuation()); + } + + if (options != null) { + if (options.sessionToken() != null) { + headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, options.sessionToken()); + } + + if (options.enableScanInQuery() != null) { + headers.put(HttpConstants.HttpHeaders.ENABLE_SCAN_IN_QUERY, options.enableScanInQuery().toString()); + } + + if (options.emitVerboseTracesInQuery() != null) { + headers.put(HttpConstants.HttpHeaders.EMIT_VERBOSE_TRACES_IN_QUERY, + options.emitVerboseTracesInQuery().toString()); + } + + if (options.enableCrossPartitionQuery() != null) { + headers.put(HttpConstants.HttpHeaders.ENABLE_CROSS_PARTITION_QUERY, + options.enableCrossPartitionQuery().toString()); + } + + if (options.maxDegreeOfParallelism() != 0) { + headers.put(HttpConstants.HttpHeaders.PARALLELIZE_CROSS_PARTITION_QUERY, Boolean.TRUE.toString()); + } + + if (options.responseContinuationTokenLimitInKb() > 0) { + headers.put(HttpConstants.HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB, + Strings.toString(options.responseContinuationTokenLimitInKb())); + } + + if (options.populateQueryMetrics()) { + headers.put(HttpConstants.HttpHeaders.POPULATE_QUERY_METRICS, + String.valueOf(options.populateQueryMetrics())); + } + } + + return headers; + } + + public static boolean noChanges(FeedResponse page) { + return page.nochanges; + } + + public static boolean noChanges(RxDocumentServiceResponse rsp) { + return rsp.getStatusCode() == HttpConstants.StatusCodes.NOT_MODIFIED; + } + + public static FeedResponse createFeedResponse(List results, + Map headers) { + return new FeedResponse<>(results, headers); + } + + public static FeedResponse createFeedResponseWithQueryMetrics(List results, + Map headers, ConcurrentMap queryMetricsMap) { + return new FeedResponse<>(results, headers, queryMetricsMap); + } + + public static E setResourceAddress(E e, String resourceAddress) { + e.resourceAddress = resourceAddress; + return e; + } + + public static long getLSN(E e) { + return e.lsn; + } + + public static String getPartitionKeyRangeId(E e) { + return e.partitionKeyRangeId; + } + + public static String getResourceAddress(E e) { + return e.resourceAddress; + } + + public static E setLSN(E e, long lsn) { + e.lsn = lsn; + return e; + } + + public static E setPartitionKeyRangeId(E e, String partitionKeyRangeId) { + e.partitionKeyRangeId = partitionKeyRangeId; + return e; + } + + public static boolean isEnableMultipleWriteLocations(DatabaseAccount account) { + return account.isEnableMultipleWriteLocations(); + } + + public static boolean getUseMultipleWriteLocations(ConnectionPolicy policy) { + return policy.usingMultipleWriteLocations(); + } + + public static void setUseMultipleWriteLocations(ConnectionPolicy policy, boolean value) { + policy.usingMultipleWriteLocations(value); + } + + public static URI getRequestUri(CosmosClientException cosmosClientException) { + return cosmosClientException.requestUri; + } + + public static void setRequestHeaders(CosmosClientException cosmosClientException, + Map requestHeaders) { + cosmosClientException.requestHeaders = requestHeaders; + } + + public static Map getRequestHeaders( + CosmosClientException cosmosClientException) { + return cosmosClientException.requestHeaders; + } + + public static Map getQueryEngineConfiuration(DatabaseAccount databaseAccount) { + return databaseAccount.getQueryEngineConfiuration(); + } + + public static ReplicationPolicy getReplicationPolicy(DatabaseAccount databaseAccount) { + return databaseAccount.getReplicationPolicy(); + } + + public static ReplicationPolicy getSystemReplicationPolicy(DatabaseAccount databaseAccount) { + return databaseAccount.getSystemReplicationPolicy(); + } + + public static ConsistencyPolicy getConsistencyPolicy(DatabaseAccount databaseAccount) { + return databaseAccount.getConsistencyPolicy(); + } + + public static String getAltLink(Resource resource) { + return resource.altLink(); + } + + public static void setAltLink(Resource resource, String altLink) { + resource.altLink(altLink); + } + + public static void setMaxReplicaSetSize(ReplicationPolicy replicationPolicy, int value) { + replicationPolicy.setMaxReplicaSetSize(value); + } + + public static void putQueryMetricsIntoMap(FeedResponse response, String partitionKeyRangeId, + QueryMetrics queryMetrics) { + response.queryMetricsMap().put(partitionKeyRangeId, queryMetrics); + } + + public static QueryMetrics createQueryMetricsFromDelimitedStringAndClientSideMetrics( + String queryMetricsDelimitedString, ClientSideMetrics clientSideMetrics, String activityId) { + return QueryMetrics.createFromDelimitedStringAndClientSideMetrics(queryMetricsDelimitedString, + clientSideMetrics, activityId); + } + + public static QueryMetrics createQueryMetricsFromCollection(Collection queryMetricsCollection) { + return QueryMetrics.createFromCollection(queryMetricsCollection); + } + + public static ClientSideMetrics getClientSideMetrics(QueryMetrics queryMetrics) { + return queryMetrics.getClientSideMetrics(); + } + + public static String getInnerErrorMessage(CosmosClientException cosmosClientException) { + if (cosmosClientException == null) { + return null; + } + return cosmosClientException.innerErrorMessage(); + } + + public static PartitionKeyInternal getNonePartitionKey(PartitionKeyDefinition partitionKeyDefinition) { + return partitionKeyDefinition.getNonePartitionKeyValue(); + } + + public static PartitionKey getPartitionKey(PartitionKeyInternal partitionKeyInternal) { + return new PartitionKey(partitionKeyInternal); + } + + public static void setProperty(JsonSerializable jsonSerializable, String propertyName, T value) { + jsonSerializable.set(propertyName, value); + } + + public static ObjectNode getObject(JsonSerializable jsonSerializable, String propertyName) { + return jsonSerializable.getObject(propertyName); + } + + public static void remove(JsonSerializable jsonSerializable, String propertyName) { + jsonSerializable.remove(propertyName); + } + + public static CosmosStoredProcedureProperties createCosmosStoredProcedureProperties(String jsonString) { + return new CosmosStoredProcedureProperties(jsonString); + } + + public static Object getValue(JsonNode value) { + return JsonSerializable.getValue(value); + } + + public static CosmosClientException setCosmosResponseDiagnostics(CosmosClientException cosmosClientException, CosmosResponseDiagnostics cosmosResponseDiagnostics) { + return cosmosClientException.cosmosResponseDiagnostics(cosmosResponseDiagnostics); + } + + public static CosmosClientException createCosmosClientException(int statusCode) { + return new CosmosClientException(statusCode, null, null, null); + } + + public static CosmosClientException createCosmosClientException(int statusCode, String errorMessage) { + CosmosClientException cosmosClientException = new CosmosClientException(statusCode, errorMessage, null, null); + cosmosClientException.error(new CosmosError()); + cosmosClientException.error().set(Constants.Properties.MESSAGE, errorMessage); + return cosmosClientException; + } + + public static CosmosClientException createCosmosClientException(int statusCode, Exception innerException) { + return new CosmosClientException(statusCode, null, null, innerException); + } + + public static CosmosClientException createCosmosClientException(int statusCode, CosmosError cosmosErrorResource, Map responseHeaders) { + return new CosmosClientException(/* resourceAddress */ null, statusCode, cosmosErrorResource, responseHeaders); + } + + public static CosmosClientException createCosmosClientException(String resourceAddress, int statusCode, CosmosError cosmosErrorResource, Map responseHeaders) { + CosmosClientException cosmosClientException = new CosmosClientException(statusCode, cosmosErrorResource == null ? null : cosmosErrorResource.getMessage(), responseHeaders, null); + cosmosClientException.resourceAddress = resourceAddress; + cosmosClientException.error(cosmosErrorResource); + return cosmosClientException; + } + + public static CosmosClientException createCosmosClientException(String message, Exception exception, Map responseHeaders, int statusCode, String resourceAddress) { + CosmosClientException cosmosClientException = new CosmosClientException(statusCode, message, responseHeaders, exception); + cosmosClientException.resourceAddress = resourceAddress; + return cosmosClientException; + } + + public static Configs extractConfigs(CosmosClientBuilder cosmosClientBuilder) { + return cosmosClientBuilder.configs(); + } + + public static CosmosClientBuilder injectConfigs(CosmosClientBuilder cosmosClientBuilder, Configs configs) { + return cosmosClientBuilder.configs(configs); + } + + public static String extractContainerSelfLink(CosmosContainer container) { + return container.getLink(); + } + + public static String extractResourceSelfLink(Resource resource) { return resource.selfLink(); } + + public static void setResourceSelfLink(Resource resource, String selfLink) { resource.selfLink(selfLink); } + + public static void populatePropertyBagJsonSerializable(JsonSerializable jsonSerializable) { jsonSerializable.populatePropertyBag(); } + + public static void setMapper(JsonSerializable jsonSerializable, ObjectMapper om) { + jsonSerializable.setMapper(om); + } + + public static void setTimestamp(Resource resource, OffsetDateTime date) { + resource.timestamp(date); + } + + public static CosmosResponseDiagnostics createCosmosResponseDiagnostics() { + return new CosmosResponseDiagnostics(); + } + + public static void recordResponse(CosmosResponseDiagnostics cosmosResponseDiagnostics, + RxDocumentServiceRequest request, StoreResult storeResult) { + cosmosResponseDiagnostics.clientSideRequestStatistics().recordResponse(request, storeResult); + } + + public static String recordAddressResolutionStart(CosmosResponseDiagnostics cosmosResponseDiagnostics, + URI targetEndpoint) { + return cosmosResponseDiagnostics.clientSideRequestStatistics().recordAddressResolutionStart(targetEndpoint); + } + + public static void recordAddressResolutionEnd(CosmosResponseDiagnostics cosmosResponseDiagnostics, + String identifier) { + cosmosResponseDiagnostics.clientSideRequestStatistics().recordAddressResolutionEnd(identifier); + } + + public static List getContactedReplicas(CosmosResponseDiagnostics cosmosResponseDiagnostics) { + return cosmosResponseDiagnostics.clientSideRequestStatistics().getContactedReplicas(); + } + + public static void setContactedReplicas(CosmosResponseDiagnostics cosmosResponseDiagnostics, List contactedReplicas) { + cosmosResponseDiagnostics.clientSideRequestStatistics().setContactedReplicas(contactedReplicas); + } + + public static Set getFailedReplicas(CosmosResponseDiagnostics cosmosResponseDiagnostics) { + return cosmosResponseDiagnostics.clientSideRequestStatistics().getFailedReplicas(); + } + + public static ConcurrentMap queryMetricsFromFeedResponse(FeedResponse feedResponse) { + return feedResponse.queryMetrics(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedOptions.java new file mode 100644 index 0000000000000..5635320ebc8ae --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedOptions.java @@ -0,0 +1,221 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.PartitionKeyRange; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Specifies the options associated with change feed methods (enumeration + * operations) in the Azure Cosmos DB database service. + */ +public final class ChangeFeedOptions { + private String partitionKeyRangeId; + private boolean startFromBeginning; + private OffsetDateTime startDateTime; + private Integer maxItemCount; + private String requestContinuation; + private PartitionKey partitionkey; + private boolean populateQueryMetrics; + private Map properties; + + public ChangeFeedOptions() { + } + + public ChangeFeedOptions(ChangeFeedOptions options) { + this.partitionKeyRangeId = options.partitionKeyRangeId; + this.startFromBeginning = options.startFromBeginning; + this.startDateTime = options.startDateTime; + this.maxItemCount = options.maxItemCount; + this.requestContinuation = options.requestContinuation; + this.partitionkey = options.partitionkey; + this.populateQueryMetrics = options.populateQueryMetrics; + } + + /** + * Get the partition key range id for the current request + *

    + * ChangeFeed requests can be executed against specific partition key ranges. + * This is used to process the change feed in parallel across multiple + * consumers. + *

    + * + * @return a string indicating the partition key range ID + * @see PartitionKeyRange + */ + String partitionKeyRangeId() { + return partitionKeyRangeId; + } + + /** + * Set the partition key range id for the current request + *

    + * ChangeFeed requests can be executed against specific partition key ranges. + * This is used to process the change feed in parallel across multiple + * consumers. + *

    + * + * @param partitionKeyRangeId a string indicating the partition key range ID + * @see PartitionKeyRange + * @return the ChangeFeedOptions. + */ + ChangeFeedOptions partitionKeyRangeId(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + return this; + } + + /** + * Get whether change feed should start from beginning (true) or from current + * (false). By default it's start from current (false). + * + * @return a boolean value indicating change feed should start from beginning or + * not + */ + public boolean startFromBeginning() { + return startFromBeginning; + } + + /** + * Set whether change feed should start from beginning (true) or from current + * (false). By default it's start from current (false). + * + * @param startFromBeginning a boolean value indicating change feed should start + * from beginning or not + * @return the ChangeFeedOptions. + */ + public ChangeFeedOptions startFromBeginning(boolean startFromBeginning) { + this.startFromBeginning = startFromBeginning; + return this; + } + + /** + * Gets the zoned date time to start looking for changes after. + * + * @return a zoned date time to start looking for changes after, if set or null + * otherwise + */ + public OffsetDateTime startDateTime() { + return startDateTime; + } + + /** + * Sets the zoned date time (exclusive) to start looking for changes after. If + * this is specified, startFromBeginning is ignored. + * + * @param startDateTime a zoned date time to start looking for changes after. + * @return the ChangeFeedOptions. + */ + public ChangeFeedOptions startDateTime(OffsetDateTime startDateTime) { + this.startDateTime = startDateTime; + return this; + } + + /** + * Gets the maximum number of items to be returned in the enumeration + * operation. + * + * @return the max number of items. + */ + public Integer maxItemCount() { + return this.maxItemCount; + } + + /** + * Sets the maximum number of items to be returned in the enumeration + * operation. + * + * @param maxItemCount the max number of items. + * @return the FeedOptionsBase. + */ + public ChangeFeedOptions maxItemCount(Integer maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + /** + * Gets the request continuation token. + * + * @return the request continuation. + */ + public String requestContinuation() { + return this.requestContinuation; + } + + /** + * Sets the request continuation token. + * + * @param requestContinuation + * the request continuation. + * @return the FeedOptionsBase. + */ + public ChangeFeedOptions requestContinuation(String requestContinuation) { + this.requestContinuation = requestContinuation; + return this; + } + + /** + * Gets the partition key used to identify the current request's target + * partition. + * + * @return the partition key. + */ + public PartitionKey partitionKey() { + return this.partitionkey; + } + + /** + * Sets the partition key used to identify the current request's target + * partition. + * + * @param partitionkey + * the partition key value. + * @return the FeedOptionsBase. + */ + public ChangeFeedOptions partitionKey(PartitionKey partitionkey) { + this.partitionkey = partitionkey; + return this; + } + + /** + * Gets the properties + * + * @return Map of request options properties + */ + public Map properties() { + return properties; + } + + /** + * Sets the properties used to identify the request token. + * + * @param properties the properties. + * @return the FeedOptionsBase. + */ + public ChangeFeedOptions properties(Map properties) { + this.properties = properties; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessor.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessor.java new file mode 100644 index 0000000000000..22f4f6072d5bb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessor.java @@ -0,0 +1,155 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedProcessorBuilderImpl; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.function.Consumer; + +/** + * Simple host for distributing change feed events across observers and thus allowing these observers scale. + * It distributes the load across its instances and allows dynamic scaling: + * - Partitions in partitioned collections are distributed across instances/observers. + * - New instance takes leases from existing instances to make distribution equal. + * - If an instance dies, the leases are distributed across remaining instances. + * It's useful for scenario when partition count is high so that one host/VM is not capable of processing that many change feed events. + * Client application needs to implement {@link ChangeFeedObserver} and register processor implementation with {@link ChangeFeedProcessor}. + *

    + * It uses auxiliary document collection for managing leases for a partition. + * Every EventProcessorHost instance is performing the following two tasks: + * 1) Renew Leases: It keeps track of leases currently owned by the host and continuously keeps on renewing the leases. + * 2) Acquire Leases: Each instance continuously polls all leases to check if there are any leases it should acquire + * for the system to get into balanced state. + *

    + * {@code + * ChangeFeedProcessor changeFeedProcessor = ChangeFeedProcessor.Builder() + * .hostName(hostName) + * .feedContainer(feedContainer) + * .leaseContainer(leaseContainer) + * .handleChanges(docs -> { + * // Implementation for handling and processing CosmosItemProperties list goes here + * }) + * .build(); + * } + */ +public interface ChangeFeedProcessor { + + /** + * Start listening for changes asynchronously. + * + * @return a representation of the deferred computation of this call. + */ + Mono start(); + + /** + * Stops listening for changes asynchronously. + * + * @return a representation of the deferred computation of this call. + */ + Mono stop(); + + /** + * Helper static method to build {@link ChangeFeedProcessor} instances + * as logical representation of the Azure Cosmos DB database service. + *

    + * {@code + * + * ChangeFeedProcessor.Builder() + * .hostName("SampleHost") + * .feedContainer(feedContainer) + * .leaseContainer(leaseContainer) + * .handleChanges(docs -> { + * // Implementation for handling and processing CosmosItemProperties list goes here + * }) + * .build(); + * } + * + * @return a builder definition instance. + */ + static BuilderDefinition Builder() { + return new ChangeFeedProcessorBuilderImpl(); + } + + /** + * The {@link ChangeFeedProcessor} builder definitions for setting the properties. + */ + interface BuilderDefinition { + /** + * Sets the host name. + * + * @param hostName the name to be used for the host. When using multiple hosts, each host must have a unique name. + * @return current Builder. + */ + BuilderDefinition hostName(String hostName); + + /** + * Sets and existing {@link CosmosContainer} to be used to read from the monitored collection. + * + * @param feedContainer the instance of {@link CosmosContainer} to be used. + * @return current Builder. + */ + BuilderDefinition feedContainer(CosmosContainer feedContainer); + + /** + * Sets the {@link ChangeFeedProcessorOptions} to be used. + *

    + * Unless specifically set the default values that will be used are: + * - maximum items per page or FeedResponse: 100 + * - lease renew interval: 17 seconds + * - lease acquire interval: 13 seconds + * - lease expiration interval: 60 seconds + * - feed poll delay: 5 seconds + * - maximum scale count: unlimited + * + * @param changeFeedProcessorOptions the change feed processor options to use. + * @return current Builder. + */ + BuilderDefinition options(ChangeFeedProcessorOptions changeFeedProcessorOptions); + + /** + * Sets a consumer function which will be called to process changes. + * + * @param consumer the consumer of {@link ChangeFeedObserver} to call for handling the feeds. + * @return current Builder. + */ + BuilderDefinition handleChanges(Consumer> consumer); + + /** + * Sets an existing {@link CosmosContainer} to be used to read from the leases collection. + * + * @param leaseContainer the instance of {@link CosmosContainer} to use. + * @return current Builder. + */ + BuilderDefinition leaseContainer(CosmosContainer leaseContainer); + + /** + * Builds a new instance of the {@link ChangeFeedProcessor} with the specified configuration asynchronously. + * + * @return an instance of {@link ChangeFeedProcessor}. + */ + ChangeFeedProcessor build(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessorOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessorOptions.java new file mode 100644 index 0000000000000..a712913581b3a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ChangeFeedProcessorOptions.java @@ -0,0 +1,348 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import java.time.Duration; +import java.time.OffsetDateTime; + +/** + * Specifies the options associated with {@link ChangeFeedProcessor}. + */ +public class ChangeFeedProcessorOptions { + private static Duration DefaultRenewInterval = Duration.ofMillis(0).plusSeconds(17); + private static Duration DefaultAcquireInterval = Duration.ofMillis(0).plusSeconds(13); + private static Duration DefaultExpirationInterval = Duration.ofMillis(0).plusSeconds(60); + private static Duration DefaultFeedPollDelay = Duration.ofMillis(0).plusSeconds(5); + + private Duration leaseRenewInterval; + private Duration leaseAcquireInterval; + private Duration leaseExpirationInterval; + private Duration feedPollDelay; + + private String leasePrefix; + private int maxItemCount; + private String startContinuation; + private OffsetDateTime startTime; + private boolean startFromBeginning; + private int minScaleCount; + private int maxScaleCount; + private boolean discardExistingLeases; + + public ChangeFeedProcessorOptions() { + this.maxItemCount = 100; + this.startFromBeginning = false; + this.leaseRenewInterval = DefaultRenewInterval; + this.leaseAcquireInterval = DefaultAcquireInterval; + this.leaseExpirationInterval = DefaultExpirationInterval; + this.feedPollDelay = DefaultFeedPollDelay; + this.maxScaleCount = 0; // unlimited + } + + /** + * Gets the renew interval for all leases for partitions currently held by {@link ChangeFeedProcessor} instance. + * + * @return the renew interval for all leases for partitions. + */ + public Duration leaseRenewInterval() { + return this.leaseRenewInterval; + } + + /** + * Sets the renew interval for all leases for partitions currently held by {@link ChangeFeedProcessor} instance. + * + * @param leaseRenewInterval the renew interval for all leases for partitions currently held by {@link ChangeFeedProcessor} instance. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions leaseRenewInterval(Duration leaseRenewInterval) { + this.leaseRenewInterval = leaseRenewInterval; + return this; + } + + /** + * Gets the interval to kick off a task to compute if partitions are distributed evenly among known host instances. + * + * @return the interval to kick off a task to compute if partitions are distributed evenly among known host instances. + */ + public Duration leaseAcquireInterval() { + return this.leaseAcquireInterval; + } + + /** + * Sets he interval to kick off a task to compute if partitions are distributed evenly among known host instances. + * @param leaseAcquireInterval he interval to kick off a task to compute if partitions are distributed evenly among known host instances. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions leaseAcquireInterval(Duration leaseAcquireInterval) { + this.leaseAcquireInterval = leaseAcquireInterval; + return this; + } + + /** + * Gets the interval for which the lease is taken on a lease representing a partition. + * + *

    + * If the lease is not renewed within this interval, it will cause it to expire and ownership of the partition will + * move to another {@link ChangeFeedProcessor} instance. + * + * @return the interval for which the lease is taken on a lease representing a partition. + */ + public Duration leaseExpirationInterval() { + return this.leaseExpirationInterval; + } + + /** + * Sets the interval for which the lease is taken on a lease representing a partition. + * + *

    + * If the lease is not renewed within this interval, it will cause it to expire and ownership of the partition will + * move to another {@link ChangeFeedProcessor} instance. + * + * @param leaseExpirationInterval the interval for which the lease is taken on a lease representing a partition. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions leaseExpirationInterval(Duration leaseExpirationInterval) { + this.leaseExpirationInterval = leaseExpirationInterval; + return this; + } + + /** + * Gets the delay in between polling a partition for new changes on the feed, after all current changes are drained. + * + * @return the delay in between polling a partition for new changes on the feed. + */ + public Duration feedPollDelay() { + return this.feedPollDelay; + } + + /** + * Sets the delay in between polling a partition for new changes on the feed, after all current changes are drained. + * + * @param feedPollDelay the delay in between polling a partition for new changes on the feed, after all current changes are drained. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions feedPollDelay(Duration feedPollDelay) { + this.feedPollDelay = feedPollDelay; + return this; + } + + /** + * Gets a prefix to be used as part of the lease ID. + *

    + * This can be used to support multiple instances of {@link ChangeFeedProcessor} instances pointing at the same + * feed while using the same auxiliary collection. + * + * @return a prefix to be used as part of the lease ID. + */ + public String leasePrefix() { + return this.leasePrefix; + } + + /** + * Sets a prefix to be used as part of the lease ID. + * + * @param leasePrefix a prefix to be used as part of the lease ID. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions leasePrefix(String leasePrefix) { + this.leasePrefix = leasePrefix; + return this; + } + + /** + * Gets the maximum number of items to be returned in the enumeration operation in the Azure Cosmos DB service. + * + * @return the maximum number of items to be returned in the enumeration operation in the Azure Cosmos DB service. + */ + public int maxItemCount() { + return this.maxItemCount; + } + + /** + * Sets the maximum number of items to be returned in the enumeration operation. + * + * @param maxItemCount the maximum number of items to be returned in the enumeration operation. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions maxItemCount(int maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + /** + * Gets the start request continuation token to start looking for changes after. + *

    + * This is only used when lease store is not initialized and is ignored if a lease for partition exists and + * has continuation token. If this is specified, both StartTime and StartFromBeginning are ignored. + * + * @return the start request continuation token to start looking for changes after. + */ + public String startContinuation() { + return this.startContinuation; + } + + /** + * Sets the start request continuation token to start looking for changes after. + *

    + * This is only used when lease store is not initialized and is ignored if a lease for partition exists and + * has continuation token. If this is specified, both StartTime and StartFromBeginning are ignored. + * + * @param startContinuation the start request continuation token to start looking for changes after. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions startContinuation(String startContinuation) { + this.startContinuation= startContinuation; + return this; + } + + /** + * Gets the time (exclusive) to start looking for changes after. + *

    + * This is only used when: + * (1) Lease store is not initialized and is ignored if a lease for partition exists and has continuation token. + * (2) StartContinuation is not specified. + * If this is specified, StartFromBeginning is ignored. + * + * @return the time (exclusive) to start looking for changes after. + */ + public OffsetDateTime startTime() { + return this.startTime; + } + + /** + * Sets the time (exclusive) to start looking for changes after (UTC time). + *

    + * This is only used when: + * (1) Lease store is not initialized and is ignored if a lease for partition exists and has continuation token. + * (2) StartContinuation is not specified. + * If this is specified, StartFromBeginning is ignored. + * + * @param startTime the time (exclusive) to start looking for changes after. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions startTime(OffsetDateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * Gets a value indicating whether change feed in the Azure Cosmos DB service should start from beginning (true) + * or from current (false). By default it's start from current (false). + *

    + * This is only used when: + * (1) Lease store is not initialized and is ignored if a lease for partition exists and has continuation token. + * (2) StartContinuation is not specified. + * (3) StartTime is not specified. + * + * @return a value indicating whether change feed in the Azure Cosmos DB service should start from. + */ + public boolean startFromBeginning() { + return this.startFromBeginning; + } + + /** + * Sets a value indicating whether change feed in the Azure Cosmos DB service should start from beginning. + *

    + * This is only used when: + * (1) Lease store is not initialized and is ignored if a lease for partition exists and has continuation token. + * (2) StartContinuation is not specified. + * (3) StartTime is not specified. + * + * @param startFromBeginning Indicates to start from beginning if true + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions startFromBeginning(boolean startFromBeginning) { + this.startFromBeginning = startFromBeginning; + return this; + } + + /** + * Gets the minimum partition count for the host. + *

    + * This can be used to increase the number of partitions for the host and thus override equal distribution (which + * is the default) of leases between hosts. + * + * @return the minimum scale count for the host. + */ + public int minScaleCount() { + return this.minScaleCount; + } + + /** + * Sets the minimum partition count for the host. + *

    + * This can be used to increase the number of partitions for the host and thus override equal distribution (which + * is the default) of leases between hosts. + * + * @param minScaleCount the minimum partition count for the host. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions minScaleCount(int minScaleCount) { + this.minScaleCount = minScaleCount; + return this; + } + + /** + * Gets the maximum number of partitions the host can serve. + *

    + * This can be used property to limit the number of partitions for the host and thus override equal distribution + * (which is the default) of leases between hosts. DEFAULT is 0 (unlimited). + * + * @return the maximum number of partitions the host can serve. + */ + public int maxScaleCount() { + return this.maxScaleCount; + } + + /** + * Sets the maximum number of partitions the host can serve. + * + * @param maxScaleCount the maximum number of partitions the host can serve. + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions maxScaleCount(int maxScaleCount) { + this.maxScaleCount = maxScaleCount; + return this; + } + + /** + * Gets a value indicating whether on start of the host all existing leases should be deleted and the host + * should start from scratch. + * + * @return a value indicating whether on start of the host all existing leases should be deleted and the host should start from scratch. + */ + public boolean discardExistingLeases() { + return this.discardExistingLeases; + } + + /** + * Sets a value indicating whether on start of the host all existing leases should be deleted and the host + * should start from scratch. + * + * @param discardExistingLeases Indicates whether to discard all existing leases if true + * @return the current ChangeFeedProcessorOptions instance. + */ + public ChangeFeedProcessorOptions discardExistingLeases(boolean discardExistingLeases) { + this.discardExistingLeases = discardExistingLeases; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ClientSideRequestStatistics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ClientSideRequestStatistics.java new file mode 100644 index 0000000000000..39d4d16f3159a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ClientSideRequestStatistics.java @@ -0,0 +1,275 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.directconnectivity.StoreResult; +import org.apache.commons.lang3.StringUtils; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +class ClientSideRequestStatistics { + + private final static int MAX_SUPPLEMENTAL_REQUESTS_FOR_TO_STRING = 10; + + private final static DateTimeFormatter responseTimeFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss.SSS").withLocale(Locale.US); + + private ZonedDateTime requestStartTime; + private ZonedDateTime requestEndTime; + + private List responseStatisticsList; + private List supplementalResponseStatisticsList; + private Map addressResolutionStatistics; + + private List contactedReplicas; + private Set failedReplicas; + private Set regionsContacted; + + ClientSideRequestStatistics() { + this.requestStartTime = ZonedDateTime.now(ZoneOffset.UTC); + this.requestEndTime = ZonedDateTime.now(ZoneOffset.UTC); + this.responseStatisticsList = new ArrayList<>(); + this.supplementalResponseStatisticsList = new ArrayList<>(); + this.addressResolutionStatistics = new HashMap<>(); + this.contactedReplicas = new ArrayList<>(); + this.failedReplicas = new HashSet<>(); + this.regionsContacted = new HashSet<>(); + } + + Duration getRequestLatency() { + return Duration.between(requestStartTime, requestEndTime); + } + + private boolean isCPUOverloaded() { + // NOTE: CPUMonitor and CPULoadHistory is not implemented in async SDK yet. + return false; + } + + void recordResponse(RxDocumentServiceRequest request, StoreResult storeResult) { + ZonedDateTime responseTime = ZonedDateTime.now(ZoneOffset.UTC); + + StoreResponseStatistics storeResponseStatistics = new StoreResponseStatistics(); + storeResponseStatistics.requestResponseTime = responseTime; + storeResponseStatistics.storeResult = storeResult; + storeResponseStatistics.requestOperationType = request.getOperationType(); + storeResponseStatistics.requestResourceType = request.getResourceType(); + + URI locationEndPoint = null; + if (request.requestContext.locationEndpointToRoute != null) { + try { + locationEndPoint = request.requestContext.locationEndpointToRoute.toURI(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + } + + synchronized (this) { + if (responseTime.isAfter(this.requestEndTime)) { + this.requestEndTime = responseTime; + } + + if (locationEndPoint != null) { + this.regionsContacted.add(locationEndPoint); + } + + if (storeResponseStatistics.requestOperationType == OperationType.Head || + storeResponseStatistics.requestOperationType == OperationType.HeadFeed) { + this.supplementalResponseStatisticsList.add(storeResponseStatistics); + } else { + this.responseStatisticsList.add(storeResponseStatistics); + } + } + } + + String recordAddressResolutionStart(URI targetEndpoint) { + String identifier = Utils.randomUUID().toString(); + + AddressResolutionStatistics resolutionStatistics = new AddressResolutionStatistics(); + resolutionStatistics.startTime = ZonedDateTime.now(ZoneOffset.UTC); + // Very far in the future + resolutionStatistics.endTime = ZonedDateTime.of(LocalDateTime.MAX, ZoneOffset.UTC); + resolutionStatistics.targetEndpoint = targetEndpoint == null ? "" : targetEndpoint.toString(); + + synchronized (this) { + this.addressResolutionStatistics.put(identifier, resolutionStatistics); + } + + return identifier; + } + + void recordAddressResolutionEnd(String identifier) { + if (StringUtils.isEmpty(identifier)) { + return; + } + ZonedDateTime responseTime = ZonedDateTime.now(ZoneOffset.UTC); + + synchronized (this) { + if (!this.addressResolutionStatistics.containsKey(identifier)) { + throw new IllegalArgumentException("Identifier " + identifier + " does not exist. Please call start before calling end"); + } + + if (responseTime.isAfter(this.requestEndTime)) { + this.requestEndTime = responseTime; + } + + AddressResolutionStatistics resolutionStatistics = this.addressResolutionStatistics.get(identifier); + resolutionStatistics.endTime = responseTime; + } + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + + // need to lock in case of concurrent operations. this should be extremely rare since toString() + // should only be called at the end of request. + synchronized (this) { + + // first trace request start time, as well as total non-head/headfeed requests made. + stringBuilder.append("RequestStartTime: ") + .append("\"").append(this.requestStartTime.format(responseTimeFormatter)).append("\"") + .append(", ") + .append("RequestEndTime: ") + .append("\"").append(this.requestEndTime.format(responseTimeFormatter)).append("\"") + .append(", ") + .append("Duration: ") + .append(Duration.between(requestStartTime, requestEndTime).toMillis()) + .append(" ms, ") + .append("NUMBER of regions attempted: ") + .append(this.regionsContacted.isEmpty() ? 1 : this.regionsContacted.size()) + .append(System.lineSeparator()); + + // take all responses here - this should be limited in number and each one contains relevant information. + for (StoreResponseStatistics storeResponseStatistics : this.responseStatisticsList) { + stringBuilder.append(storeResponseStatistics.toString()).append(System.lineSeparator()); + } + + // take all responses here - this should be limited in number and each one is important. + for (AddressResolutionStatistics value : this.addressResolutionStatistics.values()) { + stringBuilder.append(value.toString()).append(System.lineSeparator()); + } + + // only take last 10 responses from this list - this has potential of having large number of entries. + // since this is for establishing consistency, we can make do with the last responses to paint a meaningful picture. + int supplementalResponseStatisticsListCount = this.supplementalResponseStatisticsList.size(); + int initialIndex = Math.max(supplementalResponseStatisticsListCount - MAX_SUPPLEMENTAL_REQUESTS_FOR_TO_STRING, 0); + if (initialIndex != 0) { + stringBuilder.append(" -- Displaying only the last ") + .append(MAX_SUPPLEMENTAL_REQUESTS_FOR_TO_STRING) + .append(" head/headfeed requests. Total head/headfeed requests: ") + .append(supplementalResponseStatisticsListCount); + } + for (int i = initialIndex; i < supplementalResponseStatisticsListCount; i++) { + stringBuilder.append(this.supplementalResponseStatisticsList.get(i).toString()).append(System.lineSeparator()); + } + } + String requestStatsString = stringBuilder.toString(); + if (!requestStatsString.isEmpty()) { + return System.lineSeparator() + requestStatsString; + } + return StringUtils.EMPTY; + } + + List getContactedReplicas() { + return contactedReplicas; + } + + void setContactedReplicas(List contactedReplicas) { + this.contactedReplicas = contactedReplicas; + } + + Set getFailedReplicas() { + return failedReplicas; + } + + void setFailedReplicas(Set failedReplicas) { + this.failedReplicas = failedReplicas; + } + + Set getRegionsContacted() { + return regionsContacted; + } + + void setRegionsContacted(Set regionsContacted) { + this.regionsContacted = regionsContacted; + } + + private static String formatDateTime(ZonedDateTime dateTime) { + if (dateTime == null) { + return null; + } + return dateTime.format(responseTimeFormatter); + } + + private class StoreResponseStatistics { + + private ZonedDateTime requestResponseTime; + private StoreResult storeResult; + private ResourceType requestResourceType; + private OperationType requestOperationType; + + @Override + public String toString() { + return "StoreResponseStatistics{" + + "requestResponseTime=\"" + formatDateTime(requestResponseTime) + "\"" + + ", storeResult=" + storeResult + + ", requestResourceType=" + requestResourceType + + ", requestOperationType=" + requestOperationType + + '}'; + } + } + + private class AddressResolutionStatistics { + private ZonedDateTime startTime; + private ZonedDateTime endTime; + private String targetEndpoint; + + AddressResolutionStatistics() { + } + + @Override + public String toString() { + return "AddressResolutionStatistics{" + + "startTime=\"" + formatDateTime(startTime) + "\"" + + ", endTime=\"" + formatDateTime(endTime) + "\"" + + ", targetEndpoint='" + targetEndpoint + '\'' + + '}'; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CommonsBridgeInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CommonsBridgeInternal.java new file mode 100644 index 0000000000000..00d1f014a5382 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CommonsBridgeInternal.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +public class CommonsBridgeInternal { + public static boolean isV2(PartitionKeyDefinition pkd) { + return pkd.version() != null && PartitionKeyDefinitionVersion.V2.val == pkd.version().val; + } + + public static void setV2(PartitionKeyDefinition pkd) { + pkd.version(PartitionKeyDefinitionVersion.V2); + } + + /** + * Gets the partitionKeyRangeId. + * + * @return the partitionKeyRangeId. + */ + public static String partitionKeyRangeIdInternal(FeedOptions options) { + return options.partitionKeyRangeIdInternal(); + } + + /** + * Gets the partitionKeyRangeId. + * + * @return the partitionKeyRangeId. + */ + public static String partitionKeyRangeIdInternal(ChangeFeedOptions options) { + return options.partitionKeyRangeId(); + } + + /** + * Sets the partitionKeyRangeId. + * + * @return the partitionKeyRangeId. + */ + public static FeedOptions partitionKeyRangeIdInternal(FeedOptions options, String partitionKeyRangeId) { + return options.partitionKeyRangeIdInternal(partitionKeyRangeId); + } + + /** + * Sets the partitionKeyRangeId. + * + * @return the partitionKeyRangeId. + */ + public static ChangeFeedOptions partitionKeyRangeIdInternal(ChangeFeedOptions options, String partitionKeyRangeId) { + return options.partitionKeyRangeId(partitionKeyRangeId); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePath.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePath.java new file mode 100644 index 0000000000000..d20e46b4128c1 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePath.java @@ -0,0 +1,106 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a composite path of the IndexingPolicy in the Azure Cosmos DB database service. + * A composite path is used in a composite index. For example if you want to run a query like + * "SELECT * FROM c ORDER BY c.age, c.height", then you need to add "/age" and "/height" + * as composite paths to your composite index. + */ +public class CompositePath extends JsonSerializable { + /** + * Constructor. + */ + public CompositePath() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the included path. + */ + public CompositePath(String jsonString) { + super(jsonString); + } + + /** + * Gets path. + * + * @return the path. + */ + public String path() { + return super.getString(Constants.Properties.PATH); + } + + /** + * Sets path. + * + * @param path the path. + * @return the CompositePath. + */ + public CompositePath path(String path) { + super.set(Constants.Properties.PATH, path); + return this; + } + + /** + * Gets the sort order for the composite path. + * + * For example if you want to run the query "SELECT * FROM c ORDER BY c.age asc, c.height desc", + * then you need to make the order for "/age" "ascending" and the order for "/height" "descending". + * + * @return the sort order. + */ + public CompositePathSortOrder order() { + String strValue = super.getString(Constants.Properties.ORDER); + if (!StringUtils.isEmpty(strValue)) { + try { + return CompositePathSortOrder.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.ORDER))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID indexingMode value {}.", super.getString(Constants.Properties.ORDER)); + return CompositePathSortOrder.ASCENDING; + } + } + return CompositePathSortOrder.ASCENDING; + } + + /** + * Gets the sort order for the composite path. + * + * For example if you want to run the query "SELECT * FROM c ORDER BY c.age asc, c.height desc", + * then you need to make the order for "/age" "ascending" and the order for "/height" "descending". + * + * @param order the sort order. + * @return the CompositePath. + */ + public CompositePath order(CompositePathSortOrder order) { + super.set(Constants.Properties.ORDER, order.toString()); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePathSortOrder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePathSortOrder.java new file mode 100644 index 0000000000000..7440421065c5d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CompositePathSortOrder.java @@ -0,0 +1,48 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Represents the sorting order for a path in a composite index, for a + * collection in the Azure Cosmos DB database service. + */ +public enum CompositePathSortOrder { + /** + * ASCENDING sort order for composite paths. + */ + ASCENDING { + public String toString() { + return "ascending"; + } + }, + + /** + * DESCENDING sort order for composite paths. + */ + DESCENDING { + public String toString() { + return "descending"; + } + }, +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictException.java new file mode 100644 index 0000000000000..a7bbd09d2ab37 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictException.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class ConflictException extends CosmosClientException { + + private static final long serialVersionUID = 1L; + + ConflictException() { + this(RMResources.EntityAlreadyExists); + } + + public ConflictException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.CONFLICT, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + ConflictException(String msg) { + super(HttpConstants.StatusCodes.CONFLICT, msg); + } + + ConflictException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.CONFLICT, resourceAddress); + } + + public ConflictException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + ConflictException(Exception innerException) { + this(RMResources.EntityAlreadyExists, innerException, null, null); + } + + ConflictException(CosmosError cosmosError, Map headers) { + super(HttpConstants.StatusCodes.CONFLICT, cosmosError, headers); + } + + ConflictException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format("%s: %s", RMResources.EntityAlreadyExists, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.CONFLICT, + requestUriString); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionMode.java new file mode 100644 index 0000000000000..5854e31f17e98 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionMode.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.internal.StoredProcedure; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.WordUtils; + +public enum ConflictResolutionMode { + /** + * Last writer wins conflict resolution mode + * + * Setting the ConflictResolutionMode to "LAST_WRITER_WINS" indicates that conflict resolution should be done by inspecting a field in the conflicting documents + * and picking the document which has the higher value in that path. See {@link ConflictResolutionPolicy#conflictResolutionPath()} for details on how to specify the path + * to be checked for conflict resolution. Also note that Deletes win. + */ + LAST_WRITER_WINS, + + /** + * CUSTOM conflict resolution mode + * + * Setting the ConflictResolutionMode to "CUSTOM" indicates that conflict resolution is custom handled by a user. + * The user could elect to register a user specified {@link StoredProcedure} for handling conflicting resources. + * Should the user not register a user specified StoredProcedure, conflicts will default to being made available as {@link Conflict} resources, + * which the user can inspect and manually resolve. + * See {@link ConflictResolutionPolicy#conflictResolutionProcedure()} for details on how to specify the stored procedure + * to run for conflict resolution. + */ + CUSTOM, + + /** + * INVALID or unknown mode. + */ + INVALID; + + @Override + public String toString() { + return StringUtils.remove(WordUtils.capitalizeFully(this.name(), '_'), '_'); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionPolicy.java new file mode 100644 index 0000000000000..9f862e8ed9a16 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConflictResolutionPolicy.java @@ -0,0 +1,225 @@ +package com.azure.data.cosmos; + + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.internal.Strings; + + +/** + * Represents the conflict resolution policy configuration for specifying how to resolve conflicts + * in case writes from different regions result in conflicts on documents in the collection in the Azure Cosmos DB service. + * + * A collection with custom conflict resolution with no user-registered stored procedure. + *

    {@code
    + * DocumentCollection collectionSpec = new DocumentCollection();
    + * collectionSpec.id("Multi-master collection");
    + *
    + * ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
    + * collectionSpec.conflictResolutionPolicy(policy);
    + *
    + * DocumentCollection collection = client.createCollection(databaseLink, collectionSpec, null)
    + *         .toBlocking().single().getResource();
    + *
    + * }
    + * 
    + * + * A collection with custom conflict resolution with a user-registered stored procedure. + *
    {@code
    + * DocumentCollection collectionSpec = new DocumentCollection();
    + * collectionSpec.id("Multi-master collection");
    + *
    + * ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy(conflictResolutionSprocName);
    + * collectionSpec.conflictResolutionPolicy(policy);
    + *
    + * DocumentCollection collection = client.createCollection(databaseLink, collectionSpec, null)
    + *         .toBlocking().single().getResource();
    + *
    + * }
    + * 
    + * + * A collection with last writer wins conflict resolution, based on a path in the conflicting documents. + * A collection with custom conflict resolution with a user-registered stored procedure. + *
    {@code
    + * DocumentCollection collectionSpec = new DocumentCollection();
    + * collectionSpec.id("Multi-master collection");
    + *
    + * ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/path/for/conflict/resolution");
    + * collectionSpec.conflictResolutionPolicy(policy);
    + *
    + * DocumentCollection collection = client.createCollection(databaseLink, collectionSpec, null)
    + *         .toBlocking().single().getResource();
    + *
    + * }
    + * 
    + */ +public class ConflictResolutionPolicy extends JsonSerializable { + + /** + * Creates a LAST_WRITER_WINS {@link ConflictResolutionPolicy} with "/_ts" as the resolution path. + * + * In case of a conflict occurring on a document, the document with the higher integer value in the default path + * {@link Resource#timestamp()}, i.e., "/_ts" will be used. + * + * @return ConflictResolutionPolicy. + */ + public static ConflictResolutionPolicy createLastWriterWinsPolicy() { + ConflictResolutionPolicy policy = new ConflictResolutionPolicy(); + policy.mode(ConflictResolutionMode.LAST_WRITER_WINS); + return policy; + } + + /** + * + * Creates a LAST_WRITER_WINS {@link ConflictResolutionPolicy} with path as the resolution path. + * + * The specified path must be present in each document and must be an integer value. + * In case of a conflict occurring on a document, the document with the higher integer value in the specified path + * will be picked. + * + * @param conflictResolutionPath The path to check values for last-writer wins conflict resolution. + * That path is a rooted path of the property in the document, such as "/name/first". + * @return ConflictResolutionPolicy. + */ + public static ConflictResolutionPolicy createLastWriterWinsPolicy(String conflictResolutionPath) { + ConflictResolutionPolicy policy = new ConflictResolutionPolicy(); + policy.mode(ConflictResolutionMode.LAST_WRITER_WINS); + if (conflictResolutionPath != null) { + policy.conflictResolutionPath(conflictResolutionPath); + } + return policy; + } + + /** + * Creates a CUSTOM {@link ConflictResolutionPolicy} which uses the specified stored procedure + * to perform conflict resolution + * + * This stored procedure may be created after the {@link DocumentCollection} is created and can be changed as required. + * + *
      + *
    • In case the stored procedure fails or throws an exception, + * the conflict resolution will default to registering conflicts in the conflicts feed
    • + *
    • The user can provide the stored procedure @see {@link Resource#id()}
    • + *
    + * @param conflictResolutionSprocName stored procedure to perform conflict resolution. + * @return ConflictResolutionPolicy. + */ + public static ConflictResolutionPolicy createCustomPolicy(String conflictResolutionSprocName) { + ConflictResolutionPolicy policy = new ConflictResolutionPolicy(); + policy.mode(ConflictResolutionMode.CUSTOM); + if (conflictResolutionSprocName != null) { + policy.conflictResolutionProcedure(conflictResolutionSprocName); + } + return policy; + } + + /** + * Creates a CUSTOM {@link ConflictResolutionPolicy} without any {@link StoredProcedure}. User manually + * should resolve conflicts. + * + * The conflicts will be registered in the conflicts feed and the user should manually resolve them. + * + * @return ConflictResolutionPolicy. + */ + public static ConflictResolutionPolicy createCustomPolicy() { + ConflictResolutionPolicy policy = new ConflictResolutionPolicy(); + policy.mode(ConflictResolutionMode.CUSTOM); + return policy; + } + + /** + * Initializes a new instance of the {@link ConflictResolutionPolicy} class for the Azure Cosmos DB service. + */ + ConflictResolutionPolicy() {} + + public ConflictResolutionPolicy(String jsonString) { + super(jsonString); + } + + /** + * Gets the {@link ConflictResolutionMode} in the Azure Cosmos DB service. + * By default it is {@link ConflictResolutionMode#LAST_WRITER_WINS}. + * + * @return ConflictResolutionMode. + */ + public ConflictResolutionMode mode() { + + String strValue = super.getString(Constants.Properties.MODE); + + if (!Strings.isNullOrEmpty(strValue)) { + try { + return ConflictResolutionMode.valueOf(Strings.fromCamelCaseToUpperCase(super.getString(Constants.Properties.MODE))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID ConflictResolutionMode value {}.", super.getString(Constants.Properties.MODE)); + return ConflictResolutionMode.INVALID; + } + } + + return ConflictResolutionMode.INVALID; + } + + /** + * Sets the {@link ConflictResolutionMode} in the Azure Cosmos DB service. + * By default it is {@link ConflictResolutionMode#LAST_WRITER_WINS}. + * + * @param mode One of the values of the {@link ConflictResolutionMode} enum. + */ + ConflictResolutionPolicy mode(ConflictResolutionMode mode) { + super.set(Constants.Properties.MODE, mode.toString()); + return this; + } + + /** + * Gets the path which is present in each document in the Azure Cosmos DB service for last writer wins conflict-resolution. + * This path must be present in each document and must be an integer value. + * In case of a conflict occurring on a document, the document with the higher integer value in the specified path will be picked. + * If the path is unspecified, by default the {@link Resource#timestamp()} path will be used. + * + * This value should only be set when using {@link ConflictResolutionMode#LAST_WRITER_WINS} + * + * @return The path to check values for last-writer wins conflict resolution. + * That path is a rooted path of the property in the document, such as "/name/first". + */ + public String conflictResolutionPath() { + return super.getString(Constants.Properties.CONFLICT_RESOLUTION_PATH); + } + + /** + * Sets the path which is present in each document in the Azure Cosmos DB service for last writer wins conflict-resolution. + * This path must be present in each document and must be an integer value. + * In case of a conflict occurring on a document, the document with the higher integer value in the specified path will be picked. + * If the path is unspecified, by default the {@link Resource#timestamp()} path will be used. + * + * This value should only be set when using {@link ConflictResolutionMode#LAST_WRITER_WINS} + * + * @param value The path to check values for last-writer wins conflict resolution. + * That path is a rooted path of the property in the document, such as "/name/first". + */ + ConflictResolutionPolicy conflictResolutionPath(String value) { + super.set(Constants.Properties.CONFLICT_RESOLUTION_PATH, value); + return this; + } + + /** + * Gets the {@link StoredProcedure} which is used for conflict resolution in the Azure Cosmos DB service. + * This stored procedure may be created after the {@link DocumentCollection} is created and can be changed as required. + * + *
      + *
    • This value should only be set when using {@link ConflictResolutionMode#CUSTOM}
    • + *
    • In case the stored procedure fails or throws an exception, + * the conflict resolution will default to registering conflicts in the conflicts feed
    • + *
    • The user can provide the stored procedure @see {@link Resource#id()}
    • + *
    + ** + * @return the stored procedure to perform conflict resolution.] + */ + public String conflictResolutionProcedure() { + return super.getString(Constants.Properties.CONFLICT_RESOLUTION_PROCEDURE); + } + + ConflictResolutionPolicy conflictResolutionProcedure(String value) { + super.set(Constants.Properties.CONFLICT_RESOLUTION_PROCEDURE, value); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionMode.java new file mode 100644 index 0000000000000..cc6d367d0af50 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionMode.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Represents the connection mode to be used by the client in the Azure Cosmos DB database service. + *

    + * DIRECT and GATEWAY connectivity modes are supported. GATEWAY is the default. + * Refer to <see>http://azure.microsoft.com/documentation/articles/documentdb- + * interactions-with-resources/#connectivity-options</see> for additional + * details. + *

    + */ +public enum ConnectionMode { + + /** + * Specifies that requests to server resources are made through a gateway proxy using HTTPS. + *

    + * In GATEWAY mode, all requests are made through a gateway proxy. + *

    + */ + GATEWAY, + + /** + * Specifies that requests to server resources are made directly to the data nodes. + *

    + * In DIRECT mode, all requests to server resources within a collection, such as documents, stored procedures + * and user-defined functions, etc., are made directly to the data nodes within the target Cosmos DB cluster + * using either the HTTPS or TCP/SSL transport protocol. + *

    + * Certain operations on account or database level resources, such as databases, collections and users, etc., + * are always routed through the gateway using HTTPS. + *

    + */ + DIRECT +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionPolicy.java new file mode 100644 index 0000000000000..524d304acfdfa --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConnectionPolicy.java @@ -0,0 +1,380 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.List; + +/** + * Represents the Connection policy associated with a DocumentClient in the Azure Cosmos DB database service. + */ +public final class ConnectionPolicy { + + private static final int DEFAULT_REQUEST_TIMEOUT_IN_MILLIS = 60 * 1000; + // defaultMediaRequestTimeout is based upon the blob client timeout and the + // retry policy. + private static final int DEFAULT_MEDIA_REQUEST_TIMEOUT_IN_MILLIS = 300 * 1000; + private static final int DEFAULT_IDLE_CONNECTION_TIMEOUT_IN_MILLIS = 60 * 1000; + + private static final int DEFAULT_MAX_POOL_SIZE = 1000; + + private static ConnectionPolicy default_policy = null; + private int requestTimeoutInMillis; + private int mediaRequestTimeoutInMillis; + private ConnectionMode connectionMode; + private int maxPoolSize; + private int idleConnectionTimeoutInMillis; + private String userAgentSuffix; + private RetryOptions retryOptions; + private boolean enableEndpointDiscovery = true; + private List preferredLocations; + private boolean usingMultipleWriteLocations; + private InetSocketAddress inetSocketProxyAddress; + private Boolean enableReadRequestsFallback; + + /** + * Constructor. + */ + public ConnectionPolicy() { + this.connectionMode = ConnectionMode.GATEWAY; + this.enableReadRequestsFallback = null; + this.idleConnectionTimeoutInMillis = DEFAULT_IDLE_CONNECTION_TIMEOUT_IN_MILLIS; + this.maxPoolSize = DEFAULT_MAX_POOL_SIZE; + this.mediaRequestTimeoutInMillis = ConnectionPolicy.DEFAULT_MEDIA_REQUEST_TIMEOUT_IN_MILLIS; + this.requestTimeoutInMillis = ConnectionPolicy.DEFAULT_REQUEST_TIMEOUT_IN_MILLIS; + this.retryOptions = new RetryOptions(); + this.userAgentSuffix = ""; + } + + /** + * Gets the default connection policy. + * + * @return the default connection policy. + */ + public static ConnectionPolicy defaultPolicy() { + if (ConnectionPolicy.default_policy == null) { + ConnectionPolicy.default_policy = new ConnectionPolicy(); + } + return ConnectionPolicy.default_policy; + } + + /** + * Gets the request timeout (time to wait for response from network peer) in + * milliseconds. + * + * @return the request timeout in milliseconds. + */ + public int requestTimeoutInMillis() { + return this.requestTimeoutInMillis; + } + + /** + * Sets the request timeout (time to wait for response from network peer) in + * milliseconds. The default is 60 seconds. + * + * @param requestTimeoutInMillis the request timeout in milliseconds. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy requestTimeoutInMillis(int requestTimeoutInMillis) { + this.requestTimeoutInMillis = requestTimeoutInMillis; + return this; + } + + /** + * Gets the connection mode used in the client. + * + * @return the connection mode. + */ + public ConnectionMode connectionMode() { + return this.connectionMode; + } + + /** + * Sets the connection mode used in the client. + * + * @param connectionMode the connection mode. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy connectionMode(ConnectionMode connectionMode) { + this.connectionMode = connectionMode; + return this; + } + + /** + * Gets the value of the connection pool size the client is using. + * + * @return connection pool size. + */ + public int maxPoolSize() { + return this.maxPoolSize; + } + + /** + * Sets the value of the connection pool size, the default + * is 1000. + * + * @param maxPoolSize The value of the connection pool size. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy maxPoolSize(int maxPoolSize) { + this.maxPoolSize = maxPoolSize; + return this; + } + + /** + * Gets the value of the timeout for an idle connection, the default is 60 + * seconds. + * + * @return Idle connection timeout. + */ + public int idleConnectionTimeoutInMillis() { + return this.idleConnectionTimeoutInMillis; + } + + /** + * sets the value of the timeout for an idle connection. After that time, + * the connection will be automatically closed. + * + * @param idleConnectionTimeoutInMillis the timeout for an idle connection in seconds. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy idleConnectionTimeoutInMillis(int idleConnectionTimeoutInMillis) { + this.idleConnectionTimeoutInMillis = idleConnectionTimeoutInMillis; + return this; + } + + /** + * Gets the value of user-agent suffix. + * + * @return the value of user-agent suffix. + */ + public String userAgentSuffix() { + return this.userAgentSuffix; + } + + /** + * sets the value of the user-agent suffix. + * + * @param userAgentSuffix The value to be appended to the user-agent header, this is + * used for monitoring purposes. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy userAgentSuffix(String userAgentSuffix) { + this.userAgentSuffix = userAgentSuffix; + return this; + } + + /** + * Gets the retry policy options associated with the DocumentClient instance. + * + * @return the RetryOptions instance. + */ + public RetryOptions retryOptions() { + return this.retryOptions; + } + + /** + * Sets the retry policy options associated with the DocumentClient instance. + *

    + * Properties in the RetryOptions class allow application to customize the built-in + * retry policies. This property is optional. When it's not set, the SDK uses the + * default values for configuring the retry policies. See RetryOptions class for + * more details. + * + * @param retryOptions the RetryOptions instance. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy retryOptions(RetryOptions retryOptions) { + if (retryOptions == null) { + throw new IllegalArgumentException("retryOptions value must not be null."); + } + + this.retryOptions = retryOptions; + return this; + } + + /** + * Gets the flag to enable endpoint discovery for geo-replicated database accounts. + * + * @return whether endpoint discovery is enabled. + */ + public boolean enableEndpointDiscovery() { + return this.enableEndpointDiscovery; + } + + /** + * Sets the flag to enable endpoint discovery for geo-replicated database accounts. + *

    + * When EnableEndpointDiscovery is true, the SDK will automatically discover the + * current write and read regions to ensure requests are sent to the correct region + * based on the capability of the region and the user's preference. + *

    + * The default value for this property is true indicating endpoint discovery is enabled. + * + * @param enableEndpointDiscovery true if EndpointDiscovery is enabled. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy enableEndpointDiscovery(boolean enableEndpointDiscovery) { + this.enableEndpointDiscovery = enableEndpointDiscovery; + return this; + } + + /** + * Gets the flag to enable writes on any locations (regions) for geo-replicated database accounts in the Azure Cosmos DB service. + * + * When the value of this property is true, the SDK will direct write operations to + * available writable locations of geo-replicated database account. Writable locations + * are ordered by PreferredLocations property. Setting the property value + * to true has no effect until EnableMultipleWriteLocations in DatabaseAccount + * is also set to true. + * + * DEFAULT value is false indicating that writes are only directed to + * first region in PreferredLocations property. + * + * @return flag to enable writes on any locations (regions) for geo-replicated database accounts. + */ + public boolean usingMultipleWriteLocations() { + return this.usingMultipleWriteLocations; + } + + /** + * Gets whether to allow for reads to go to multiple regions configured on an account of Azure Cosmos DB service. + * + * DEFAULT value is null. + * + * If this property is not set, the default is true for all Consistency Levels other than Bounded Staleness, + * The default is false for Bounded Staleness. + * 1. {@link #enableEndpointDiscovery} is true + * 2. the Azure Cosmos DB account has more than one region + * + * @return flag to allow for reads to go to multiple regions configured on an account of Azure Cosmos DB service. + */ + public Boolean enableReadRequestsFallback() { + return this.enableReadRequestsFallback; + } + + /** + * Sets the flag to enable writes on any locations (regions) for geo-replicated database accounts in the Azure Cosmos DB service. + * + * When the value of this property is true, the SDK will direct write operations to + * available writable locations of geo-replicated database account. Writable locations + * are ordered by PreferredLocations property. Setting the property value + * to true has no effect until EnableMultipleWriteLocations in DatabaseAccount + * is also set to true. + * + * DEFAULT value is false indicating that writes are only directed to + * first region in PreferredLocations property. + * + * @param usingMultipleWriteLocations flag to enable writes on any locations (regions) for geo-replicated database accounts. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy usingMultipleWriteLocations(boolean usingMultipleWriteLocations) { + this.usingMultipleWriteLocations = usingMultipleWriteLocations; + return this; + } + + /** + * Sets whether to allow for reads to go to multiple regions configured on an account of Azure Cosmos DB service. + * + * DEFAULT value is null. + * + * If this property is not set, the default is true for all Consistency Levels other than Bounded Staleness, + * The default is false for Bounded Staleness. + * 1. {@link #enableEndpointDiscovery} is true + * 2. the Azure Cosmos DB account has more than one region + * + * @param enableReadRequestsFallback flag to enable reads to go to multiple regions configured on an account of Azure Cosmos DB service. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy enableReadRequestsFallback(Boolean enableReadRequestsFallback) { + this.enableReadRequestsFallback = enableReadRequestsFallback; + return this; + } + + /** + * Gets the preferred locations for geo-replicated database accounts + * + * @return the list of preferred location. + */ + public List preferredLocations() { + return this.preferredLocations != null ? preferredLocations : Collections.emptyList(); + } + + /** + * Sets the preferred locations for geo-replicated database accounts. For example, + * "East US" as the preferred location. + *

    + * When EnableEndpointDiscovery is true and PreferredRegions is non-empty, + * the SDK will prefer to use the locations in the collection in the order + * they are specified to perform operations. + *

    + * If EnableEndpointDiscovery is set to false, this property is ignored. + * + * @param preferredLocations the list of preferred locations. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy preferredLocations(List preferredLocations) { + this.preferredLocations = preferredLocations; + return this; + } + + /** + * Gets the InetSocketAddress of proxy server. + * + * @return the value of proxyHost. + */ + public InetSocketAddress proxy() { + return this.inetSocketProxyAddress; + } + + /** + * This will create the InetSocketAddress for proxy server, + * all the requests to cosmoDB will route from this address. + * @param proxyHost The proxy server host. + * @param proxyPort The proxy server port. + * @return the ConnectionPolicy. + */ + public ConnectionPolicy proxy(String proxyHost, int proxyPort) { + this.inetSocketProxyAddress = new InetSocketAddress(proxyHost, proxyPort); + return this; + } + + @Override + public String toString() { + return "ConnectionPolicy{" + + "requestTimeoutInMillis=" + requestTimeoutInMillis + + ", mediaRequestTimeoutInMillis=" + mediaRequestTimeoutInMillis + + ", connectionMode=" + connectionMode + + ", maxPoolSize=" + maxPoolSize + + ", idleConnectionTimeoutInMillis=" + idleConnectionTimeoutInMillis + + ", userAgentSuffix='" + userAgentSuffix + '\'' + + ", retryOptions=" + retryOptions + + ", enableEndpointDiscovery=" + enableEndpointDiscovery + + ", preferredLocations=" + preferredLocations + + ", usingMultipleWriteLocations=" + usingMultipleWriteLocations + + ", inetSocketProxyAddress=" + inetSocketProxyAddress + + '}'; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyLevel.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyLevel.java new file mode 100644 index 0000000000000..e64a5ef9976ec --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyLevel.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.WordUtils; + +/** + * Represents the consistency levels supported for Cosmos DB client operations in the Azure Cosmos DB database service. + *

    + * The requested ConsistencyLevel must match or be weaker than that provisioned for the database account. Consistency + * levels by order of strength are STRONG, BOUNDED_STALENESS, SESSION and EVENTUAL. + */ +public enum ConsistencyLevel { + + /** + * STRONG Consistency guarantees that read operations always return the value that was last written. + */ + STRONG, + + /** + * Bounded Staleness guarantees that reads are not too out-of-date. This can be configured based on number of + * operations (MaxStalenessPrefix) or time (MaxStalenessIntervalInSeconds) + */ + BOUNDED_STALENESS, + + /** + * SESSION Consistency guarantees monotonic reads (you never read old data, then new, then old again), monotonic + * writes (writes are ordered) and read your writes (your writes are immediately visible to your reads) within + * any single session. + */ + SESSION, + + /** + * EVENTUAL Consistency guarantees that reads will return a subset of writes. ALL writes will be eventually be + * available for reads. + */ + EVENTUAL, + + /** + * CONSISTENT_PREFIX Consistency guarantees that reads will return some prefix of all writes with no gaps. ALL writes + * will be eventually be available for reads. + */ + CONSISTENT_PREFIX; + + @Override + public String toString() { + return StringUtils.remove(WordUtils.capitalizeFully(this.name(), '_'), '_'); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyPolicy.java new file mode 100644 index 0000000000000..2af95869c1db4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ConsistencyPolicy.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Encapsulates the properties for consistency policy in the Azure Cosmos DB database service. + */ +public final class ConsistencyPolicy extends JsonSerializable { + private static final ConsistencyLevel DEFAULT_DEFAULT_CONSISTENCY_LEVEL = + ConsistencyLevel.SESSION; + + private static final int DEFAULT_MAX_STALENESS_INTERVAL = 5; + private static final int DEFAULT_MAX_STALENESS_PREFIX = 100; + + + /** + * Constructor. + */ + public ConsistencyPolicy() { + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the consistency policy. + */ + ConsistencyPolicy(String jsonString) { + super(jsonString); + } + + /** + * Get the name of the resource. + * + * @return the default consistency level. + */ + public ConsistencyLevel defaultConsistencyLevel() { + + ConsistencyLevel result = ConsistencyPolicy.DEFAULT_DEFAULT_CONSISTENCY_LEVEL; + try { + result = ConsistencyLevel.valueOf( + StringUtils.upperCase(super.getString(Constants.Properties.DEFAULT_CONSISTENCY_LEVEL))); + } catch (IllegalArgumentException e) { + // ignore the exception and return the default + this.getLogger().warn("Unknown consistency level {}, value ignored.", super.getString(Constants.Properties.DEFAULT_CONSISTENCY_LEVEL)); + } + return result; + } + + /** + * Set the name of the resource. + * + * @param level the consistency level. + * @return the ConsistenctPolicy. + */ + public ConsistencyPolicy defaultConsistencyLevel(ConsistencyLevel level) { + super.set(Constants.Properties.DEFAULT_CONSISTENCY_LEVEL, level.toString()); + return this; + } + + /** + * Gets the bounded staleness consistency, the maximum allowed staleness in terms difference in sequence numbers + * (aka version). + * + * @return the max staleness prefix. + */ + public int maxStalenessPrefix() { + Integer value = super.getInt(Constants.Properties.MAX_STALENESS_PREFIX); + if (value == null) { + return ConsistencyPolicy.DEFAULT_MAX_STALENESS_PREFIX; + } + return value; + } + + /** + * Sets the bounded staleness consistency, the maximum allowed staleness in terms difference in sequence numbers + * (aka version). + * + * @param maxStalenessPrefix the max staleness prefix. + * @return the ConsistenctPolicy. + */ + public ConsistencyPolicy maxStalenessPrefix(int maxStalenessPrefix) { + super.set(Constants.Properties.MAX_STALENESS_PREFIX, maxStalenessPrefix); + return this; + } + + /** + * Gets the in bounded staleness consistency, the maximum allowed staleness in terms time interval. + * + * @return the max staleness prefix. + */ + public int maxStalenessIntervalInSeconds() { + Integer value = super.getInt(Constants.Properties.MAX_STALENESS_INTERVAL_IN_SECONDS); + if (value == null) { + return ConsistencyPolicy.DEFAULT_MAX_STALENESS_INTERVAL; + } + return value; + } + + /** + * Sets the in bounded staleness consistency, the maximum allowed staleness in terms time interval. + * + * @param maxStalenessIntervalInSeconds the max staleness interval in seconds. + * @return the ConsistenctPolicy. + */ + public ConsistencyPolicy maxStalenessIntervalInSeconds(int maxStalenessIntervalInSeconds) { + super.set(Constants.Properties.MAX_STALENESS_INTERVAL_IN_SECONDS, maxStalenessIntervalInSeconds); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosBridgeInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosBridgeInternal.java new file mode 100644 index 0000000000000..fab004759731b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosBridgeInternal.java @@ -0,0 +1,40 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.DocumentCollection; +import reactor.core.publisher.Mono; + +/** + * DO NOT USE. For internal use only by the SDK. These methods might break at any time. No support will be provided. + */ +public class CosmosBridgeInternal { + + public static DocumentCollection toDocumentCollection(CosmosContainerProperties cosmosContainerProperties) { + return new DocumentCollection(cosmosContainerProperties.toJson()); + } + + public static AsyncDocumentClient getAsyncDocumentClient(CosmosClient client) { + return client.getDocClientWrapper(); + } + + public static CosmosDatabase getCosmosDatabaseWithNewClient(CosmosDatabase cosmosDatabase, CosmosClient client) { + return new CosmosDatabase(cosmosDatabase.id(), client); + } + + public static CosmosContainer getCosmosContainerWithNewClient(CosmosContainer cosmosContainer, CosmosDatabase cosmosDatabase, CosmosClient client) { + return new CosmosContainer(cosmosContainer.id(), CosmosBridgeInternal.getCosmosDatabaseWithNewClient(cosmosDatabase, client)); + } + + public static Mono getDatabaseAccount(CosmosClient client) { + return client.getDatabaseAccount(); + } + + public static AsyncDocumentClient getContextClient(CosmosDatabase database) { + return database.getClient().getContextClient(); + } + + public static AsyncDocumentClient getContextClient(CosmosContainer container) { + return container.getDatabase().getClient().getContextClient(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClient.java new file mode 100644 index 0000000000000..049d4fc01dfed --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClient.java @@ -0,0 +1,380 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Permission; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * Provides a client-side logical representation of the Azure Cosmos database service. + * This asynchronous client is used to configure and execute requests + * against the service. + */ +public class CosmosClient implements AutoCloseable { + + //Document client wrapper + private final Configs configs; + private final AsyncDocumentClient asyncDocumentClient; + private final String serviceEndpoint; + private final String keyOrResourceToken; + private final ConnectionPolicy connectionPolicy; + private final ConsistencyLevel desiredConsistencyLevel; + private final List permissions; + private final TokenResolver tokenResolver; + + + CosmosClient(CosmosClientBuilder builder) { + this.configs = builder.configs(); + this.serviceEndpoint = builder.endpoint(); + this.keyOrResourceToken = builder.key(); + this.connectionPolicy = builder.connectionPolicy(); + this.desiredConsistencyLevel = builder.consistencyLevel(); + this.permissions = builder.permissions(); + this.tokenResolver = builder.tokenResolver(); + this.asyncDocumentClient = new AsyncDocumentClient.Builder() + .withServiceEndpoint(this.serviceEndpoint) + .withMasterKeyOrResourceToken(this.keyOrResourceToken) + .withConnectionPolicy(this.connectionPolicy) + .withConsistencyLevel(this.desiredConsistencyLevel) + .withConfigs(this.configs) + .withTokenResolver(this.tokenResolver) + .build(); + } + + AsyncDocumentClient getContextClient() { + return this.asyncDocumentClient; + } + + /** + * Instantiate the cosmos client builder to build cosmos client + * @return {@link CosmosClientBuilder} + */ + public static CosmosClientBuilder builder(){ + return new CosmosClientBuilder(); + } + + /** + * Get the service endpoint + * @return the service endpoint + */ + String getServiceEndpoint() { + return serviceEndpoint; + } + + /** + * Gets the key or resource token + * @return get the key or resource token + */ + String getKeyOrResourceToken() { + return keyOrResourceToken; + } + + /** + * Get the connection policy + * @return {@link ConnectionPolicy} + */ + ConnectionPolicy getConnectionPolicy() { + return connectionPolicy; + } + + /** + * Gets the consistency level + * @return the (@link ConsistencyLevel) + */ + ConsistencyLevel getDesiredConsistencyLevel() { + return desiredConsistencyLevel; + } + + /** + * Gets the permission list + * @return the permission list + */ + List getPermissions() { + return permissions; + } + + AsyncDocumentClient getDocClientWrapper(){ + return asyncDocumentClient; + } + + /** + * Gets the configs + * @return the configs + */ + Configs getConfigs() { + return configs; + } + + /** + * Gets the token resolver + * @return the token resolver + */ + TokenResolver getTokenResolver() { + return tokenResolver; + } + + /** + * CREATE a Database if it does not already exist on the service + * + * The {@link Mono} upon successful completion will contain a single cosmos database response with the + * created or existing database. + * @param databaseSettings CosmosDatabaseProperties + * @return a {@link Mono} containing the cosmos database response with the created or existing database or + * an error. + */ + public Mono createDatabaseIfNotExists(CosmosDatabaseProperties databaseSettings) { + return createDatabaseIfNotExistsInternal(getDatabase(databaseSettings.id())); + } + + /** + * CREATE a Database if it does not already exist on the service + * The {@link Mono} upon successful completion will contain a single cosmos database response with the + * created or existing database. + * @param id the id of the database + * @return a {@link Mono} containing the cosmos database response with the created or existing database or + * an error + */ + public Mono createDatabaseIfNotExists(String id) { + return createDatabaseIfNotExistsInternal(getDatabase(id)); + } + + private Mono createDatabaseIfNotExistsInternal(CosmosDatabase database){ + return database.read().onErrorResume(exception -> { + if (exception instanceof CosmosClientException) { + CosmosClientException cosmosClientException = (CosmosClientException) exception; + if (cosmosClientException.statusCode() == HttpConstants.StatusCodes.NOTFOUND) { + return createDatabase(new CosmosDatabaseProperties(database.id()), new CosmosDatabaseRequestOptions()); + } + } + return Mono.error(exception); + }); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param databaseSettings {@link CosmosDatabaseProperties} + * @param options {@link CosmosDatabaseRequestOptions} + * @return an {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(CosmosDatabaseProperties databaseSettings, + CosmosDatabaseRequestOptions options) { + if (options == null) { + options = new CosmosDatabaseRequestOptions(); + } + Database wrappedDatabase = new Database(); + wrappedDatabase.id(databaseSettings.id()); + return asyncDocumentClient.createDatabase(wrappedDatabase, options.toRequestOptions()).map(databaseResourceResponse -> + new CosmosDatabaseResponse(databaseResourceResponse, this)).single(); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param databaseSettings {@link CosmosDatabaseProperties} + * @return an {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(CosmosDatabaseProperties databaseSettings) { + return createDatabase(databaseSettings, new CosmosDatabaseRequestOptions()); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param id id of the database + * @return a {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(String id) { + return createDatabase(new CosmosDatabaseProperties(id), new CosmosDatabaseRequestOptions()); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param databaseSettings {@link CosmosDatabaseProperties} + * @param throughput the throughput for the database + * @param options {@link CosmosDatabaseRequestOptions} + * @return an {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(CosmosDatabaseProperties databaseSettings, + int throughput, + CosmosDatabaseRequestOptions options) { + if (options == null) { + options = new CosmosDatabaseRequestOptions(); + } + options.offerThroughput(throughput); + Database wrappedDatabase = new Database(); + wrappedDatabase.id(databaseSettings.id()); + return asyncDocumentClient.createDatabase(wrappedDatabase, options.toRequestOptions()).map(databaseResourceResponse -> + new CosmosDatabaseResponse(databaseResourceResponse, this)).single(); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param databaseSettings {@link CosmosDatabaseProperties} + * @param throughput the throughput for the database + * @return an {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(CosmosDatabaseProperties databaseSettings, int throughput) { + CosmosDatabaseRequestOptions options = new CosmosDatabaseRequestOptions(); + options.offerThroughput(throughput); + return createDatabase(databaseSettings, options); + } + + /** + * Creates a database. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the + * created database. + * In case of failure the {@link Mono} will error. + * + * @param id id of the database + * @param throughput the throughput for the database + * @return a {@link Mono} containing the single cosmos database response with the created database or an error. + */ + public Mono createDatabase(String id, int throughput) { + CosmosDatabaseRequestOptions options = new CosmosDatabaseRequestOptions(); + options.offerThroughput(throughput); + return createDatabase(new CosmosDatabaseProperties(id), options); + } + + /** + * Reads all databases. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @param options {@link FeedOptions} + * @return a {@link Flux} containing one or several feed response pages of read databases or an error. + */ + public Flux> readAllDatabases(FeedOptions options) { + return getDocClientWrapper().readDatabases(options) + .map(response-> BridgeInternal.createFeedResponse(CosmosDatabaseProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Reads all databases. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @return a {@link Flux} containing one or several feed response pages of read databases or an error. + */ + public Flux> readAllDatabases() { + return readAllDatabases(new FeedOptions()); + } + + + /** + * Query for databases. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of read databases or an error. + */ + public Flux> queryDatabases(String query, FeedOptions options){ + return queryDatabases(new SqlQuerySpec(query), options); + } + + /** + * Query for databases. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of read databases or an error. + */ + public Flux> queryDatabases(SqlQuerySpec querySpec, FeedOptions options){ + return getDocClientWrapper().queryDatabases(querySpec, options) + .map(response-> BridgeInternal.createFeedResponse( + CosmosDatabaseProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + Mono getDatabaseAccount() { + return asyncDocumentClient.getDatabaseAccount().single(); + } + + /** + * Gets a database object without making a service call. + * + * @param id name of the database + * @return {@link CosmosDatabase} + */ + public CosmosDatabase getDatabase(String id) { + return new CosmosDatabase(id, this); + } + + /** + * Close this {@link CosmosClient} instance and cleans up the resources. + */ + @Override + public void close() { + asyncDocumentClient.close(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientBuilder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientBuilder.java new file mode 100644 index 0000000000000..f077c6570096f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientBuilder.java @@ -0,0 +1,228 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.Permission; + +import java.util.List; + +/** + * Helper class to build {@link CosmosClient} instances + * as logical representation of the Azure Cosmos database service. + * + *

    + * {@code
    + * ConnectionPolicy connectionPolicy = new ConnectionPolicy();
    + * connectionPolicy.connectionMode(ConnectionMode.DIRECT);
    + * CosmonsClient client = new CosmosClient.builder()
    + *         .endpoint(serviceEndpoint)
    + *         .key(key)
    + *         .connectionPolicy(connectionPolicy)
    + *         .consistencyLevel(ConsistencyLevel.SESSION)
    + *         .build();
    + * }
    + * 
    + */ +public class CosmosClientBuilder { + + private Configs configs = new Configs(); + private String serviceEndpoint; + private String keyOrResourceToken; + private ConnectionPolicy connectionPolicy; + private ConsistencyLevel desiredConsistencyLevel; + private List permissions; + private TokenResolver tokenResolver; + + CosmosClientBuilder() { + } + + /** + * Gets the token resolver + * @return the token resolver + */ + public TokenResolver tokenResolver() { + return tokenResolver; + } + + /** + * Sets the token resolver + * @param tokenResolver + * @return current builder + */ + public CosmosClientBuilder tokenResolver(TokenResolver tokenResolver) { + this.tokenResolver = tokenResolver; + return this; + } + + /** + * Gets the Azure Cosmos DB endpoint the SDK will connect to + * @return the endpoint + */ + public String endpoint() { + return serviceEndpoint; + } + + /** + * Sets the Azure Cosmos DB endpoint the SDK will connect to + * @param endpoint the service endpoint + * @return current Builder + */ + public CosmosClientBuilder endpoint(String endpoint) { + this.serviceEndpoint = endpoint; + return this; + } + + /** + * Gets either a master or readonly key used to perform authentication + * for accessing resource. + * @return the key + */ + public String key() { + return keyOrResourceToken; + } + + /** + * Sets either a master or readonly key used to perform authentication + * for accessing resource. + * + * @param key master or readonly key + * @return current Builder. + */ + public CosmosClientBuilder key(String key) { + this.keyOrResourceToken = key; + return this; + } + + /** + * Sets a resource token used to perform authentication + * for accessing resource. + * @return the resourceToken + */ + public String resourceToken() { + return keyOrResourceToken; + } + + /** + * Sets a resource token used to perform authentication + * for accessing resource. + * + * @param resourceToken resourceToken for authentication + * @return current Builder. + */ + public CosmosClientBuilder resourceToken(String resourceToken) { + this.keyOrResourceToken = resourceToken; + return this; + } + + /** + * Gets the permission list, which contains the + * resource tokens needed to access resources. + * @return the permission list + */ + public List permissions() { + return permissions; + } + + /** + * Sets the permission list, which contains the + * resource tokens needed to access resources. + * + * @param permissions Permission list for authentication. + * @return current Builder. + */ + public CosmosClientBuilder permissions(List permissions) { + this.permissions = permissions; + return this; + } + + /** + * Gets the (@link ConsistencyLevel) to be used + * @return the consistency level + */ + public ConsistencyLevel consistencyLevel() { + return this.desiredConsistencyLevel; + } + + /** + * Sets the (@link ConsistencyLevel) to be used + * @param desiredConsistencyLevel {@link ConsistencyLevel} + * @return current Builder + */ + public CosmosClientBuilder consistencyLevel(ConsistencyLevel desiredConsistencyLevel) { + this.desiredConsistencyLevel = desiredConsistencyLevel; + return this; + } + + /** + * Gets the (@link ConnectionPolicy) to be used + * @return the connection policy + */ + public ConnectionPolicy connectionPolicy() { + return connectionPolicy; + } + + /** + * Sets the (@link ConnectionPolicy) to be used + * @param connectionPolicy {@link ConnectionPolicy} + * @return current Builder + */ + public CosmosClientBuilder connectionPolicy(ConnectionPolicy connectionPolicy) { + this.connectionPolicy = connectionPolicy; + return this; + } + + /** + * Builds a cosmos configuration object with the provided properties + * @return CosmosClient + */ + public CosmosClient build() { + + ifThrowIllegalArgException(this.serviceEndpoint == null, "cannot build client without service endpoint"); + ifThrowIllegalArgException( + this.keyOrResourceToken == null && (permissions == null || permissions.isEmpty()), + "cannot build client without key or resource token"); + + return new CosmosClient(this); + } + + Configs configs() { + return configs; + } + + /** + * Configs + * @param configs + * @return current builder + */ + CosmosClientBuilder configs(Configs configs) { + this.configs = configs; + return this; + } + + private void ifThrowIllegalArgException(boolean value, String error) { + if (value) { + throw new IllegalArgumentException(error); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientException.java new file mode 100644 index 0000000000000..cd3b216dc6c4c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosClientException.java @@ -0,0 +1,291 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.HttpConstants; +import org.apache.commons.lang3.StringUtils; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +/** + * This class defines a custom exception type for all operations on + * DocumentClient in the Azure Cosmos DB database service. Applications are + * expected to catch CosmosClientException and handle errors as appropriate when + * calling methods on DocumentClient. + *

    + * Errors coming from the service during normal execution are converted to + * CosmosClientException before returning to the application with the following + * exception: + *

    + * When a BE error is encountered during a QueryIterable<T> iteration, an + * IllegalStateException is thrown instead of CosmosClientException. + *

    + * When a transport level error happens that request is not able to reach the + * service, an IllegalStateException is thrown instead of CosmosClientException. + */ +public class CosmosClientException extends Exception { + private static final long serialVersionUID = 1L; + + private final int statusCode; + private final Map responseHeaders; + + private CosmosResponseDiagnostics cosmosResponseDiagnostics; + private CosmosError cosmosError; + + long lsn; + String partitionKeyRangeId; + Map requestHeaders; + URI requestUri; + String resourceAddress; + + CosmosClientException(int statusCode, String message, Map responseHeaders, Throwable cause) { + super(message, cause, /* enableSuppression */ true, /* writableStackTrace */ false); + this.statusCode = statusCode; + this.responseHeaders = responseHeaders == null ? new HashMap<>() : new HashMap<>(responseHeaders); + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param statusCode the http status code of the response. + */ + CosmosClientException(int statusCode) { + this(statusCode, null, null, null); + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param statusCode the http status code of the response. + * @param errorMessage the error message. + */ + CosmosClientException(int statusCode, String errorMessage) { + this(statusCode, errorMessage, null, null); + this.cosmosError = new CosmosError(); + cosmosError.set(Constants.Properties.MESSAGE, errorMessage); + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param statusCode the http status code of the response. + * @param innerException the original exception. + */ + CosmosClientException(int statusCode, Exception innerException) { + this(statusCode, null, null, innerException); + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param statusCode the http status code of the response. + * @param cosmosErrorResource the error resource object. + * @param responseHeaders the response headers. + */ + CosmosClientException(int statusCode, CosmosError cosmosErrorResource, Map responseHeaders) { + this(/* resourceAddress */ null, statusCode, cosmosErrorResource, responseHeaders); + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param resourceAddress the address of the resource the request is associated with. + * @param statusCode the http status code of the response. + * @param cosmosErrorResource the error resource object. + * @param responseHeaders the response headers. + */ + + CosmosClientException(String resourceAddress, int statusCode, CosmosError cosmosErrorResource, Map responseHeaders) { + this(statusCode, cosmosErrorResource == null ? null : cosmosErrorResource.getMessage(), responseHeaders, null); + this.resourceAddress = resourceAddress; + this.cosmosError = cosmosErrorResource; + } + + /** + * Creates a new instance of the CosmosClientException class. + * + * @param message the string message. + * @param statusCode the http status code of the response. + * @param exception the exception object. + * @param responseHeaders the response headers. + * @param resourceAddress the address of the resource the request is associated with. + */ + CosmosClientException(String message, Exception exception, Map responseHeaders, int statusCode, String resourceAddress) { + this(statusCode, message, responseHeaders, exception); + this.resourceAddress = resourceAddress; + } + + @Override + public String getMessage() { + if (cosmosResponseDiagnostics == null) { + return innerErrorMessage(); + } + return innerErrorMessage() + ", " + cosmosResponseDiagnostics.toString(); + } + + /** + * Gets the activity ID associated with the request. + * + * @return the activity ID. + */ + public String message() { + if (this.responseHeaders != null) { + return this.responseHeaders.get(HttpConstants.HttpHeaders.ACTIVITY_ID); + } + + return null; + } + + /** + * Gets the http status code. + * + * @return the status code. + */ + public int statusCode() { + return this.statusCode; + } + + /** + * Gets the sub status code. + * + * @return the status code. + */ + public int subStatusCode() { + int code = HttpConstants.SubStatusCodes.UNKNOWN; + if (this.responseHeaders != null) { + String subStatusString = this.responseHeaders.get(HttpConstants.HttpHeaders.SUB_STATUS); + if (StringUtils.isNotEmpty(subStatusString)) { + try { + code = Integer.parseInt(subStatusString); + } catch (NumberFormatException e) { + // If value cannot be parsed as Integer, return Unknown. + } + } + } + + return code; + } + + /** + * Gets the error code associated with the exception. + * + * @return the error. + */ + public CosmosError error() { + return this.cosmosError; + } + + void error(CosmosError cosmosError) { + this.cosmosError = cosmosError; + } + + /** + * Gets the recommended time interval after which the client can retry failed + * requests + * + * @return the recommended time interval after which the client can retry failed + * requests. + */ + public long retryAfterInMilliseconds() { + long retryIntervalInMilliseconds = 0; + + if (this.responseHeaders != null) { + String header = this.responseHeaders.get(HttpConstants.HttpHeaders.RETRY_AFTER_IN_MILLISECONDS); + + if (StringUtils.isNotEmpty(header)) { + try { + retryIntervalInMilliseconds = Long.parseLong(header); + } catch (NumberFormatException e) { + // If the value cannot be parsed as long, return 0. + } + } + } + + // + // In the absence of explicit guidance from the backend, don't introduce + // any unilateral retry delays here. + return retryIntervalInMilliseconds; + } + + /** + * Gets the response headers as key-value pairs + * + * @return the response headers + */ + public Map responseHeaders() { + return this.responseHeaders; + } + + /** + * Gets the resource address associated with this exception. + * + * @return the resource address associated with this exception. + */ + String getResourceAddress() { + return this.resourceAddress; + } + + /** + * Gets the Cosmos Response Diagnostic Statistics associated with this exception. + * + * @return Cosmos Response Diagnostic Statistics associated with this exception. + */ + public CosmosResponseDiagnostics cosmosResponseDiagnostics() { + return cosmosResponseDiagnostics; + } + + CosmosClientException cosmosResponseDiagnostics(CosmosResponseDiagnostics cosmosResponseDiagnostics) { + this.cosmosResponseDiagnostics = cosmosResponseDiagnostics; + return this; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{" + "error=" + cosmosError + ", resourceAddress='" + resourceAddress + '\'' + + ", statusCode=" + statusCode + ", message=" + getMessage() + ", causeInfo=" + causeInfo() + + ", responseHeaders=" + responseHeaders + ", requestHeaders=" + requestHeaders + '}'; + } + + String innerErrorMessage() { + String innerErrorMessage = super.getMessage(); + if (cosmosError != null) { + innerErrorMessage = cosmosError.getMessage(); + if (innerErrorMessage == null) { + innerErrorMessage = String.valueOf(cosmosError.get("Errors")); + } + } + return innerErrorMessage; + } + + private String causeInfo() { + Throwable cause = getCause(); + if (cause != null) { + return String.format("[class: %s, message: %s]", cause.getClass(), cause.getMessage()); + } + return null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflict.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflict.java new file mode 100644 index 0000000000000..4b4b6adbf9755 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflict.java @@ -0,0 +1,127 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; +import reactor.core.publisher.Mono; + +import static com.azure.data.cosmos.internal.Paths.CONFLICTS_PATH_SEGMENT; + +/** + * Read and delete conflicts + */ +public class CosmosConflict { + + private CosmosContainer container; + private String id; + + /** + * Constructor + * + * @param id the conflict id + * @param container the container + */ + CosmosConflict(String id, CosmosContainer container) { + this.id = id; + this.container = container; + } + + /** + * Get the id of the {@link CosmosConflict} + * + * @return the id of the {@link CosmosConflict} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosConflict} + * + * @param id the id of the {@link CosmosConflict} + * @return the same {@link CosmosConflict} that had the id set + */ + CosmosConflict id(String id) { + this.id = id; + return this; + } + + /** + * Reads a conflict. + *

    + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single resource response with the read + * conflict. In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return a {@link Mono} containing the single resource response with the read + * conflict or an error. + */ + public Mono read(CosmosConflictRequestOptions options) { + if (options == null) { + options = new CosmosConflictRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return this.container.getDatabase().getDocClientWrapper().readConflict(getLink(), requestOptions) + .map(response -> new CosmosConflictResponse(response, container)).single(); + + } + + /** + * Reads all conflicts in a document collection. + *

    + * After subscription the operation will be performed. The {@link Mono} will + * contain one or several feed response pages of the read conflicts. In case of + * failure the {@link Mono} will error. + * + * @param options the feed options. + * @return a {@link Mono} containing one or several feed response pages of the + * read conflicts or an error. + */ + public Mono delete(CosmosConflictRequestOptions options) { + if (options == null) { + options = new CosmosConflictRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return this.container.getDatabase().getDocClientWrapper().deleteConflict(getLink(), requestOptions) + .map(response -> new CosmosConflictResponse(response, container)).single(); + } + + String URIPathSegment() { + return CONFLICTS_PATH_SEGMENT; + } + + String parentLink() { + return this.container.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictProperties.java new file mode 100644 index 0000000000000..8c33bd1ab47f8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictProperties.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.Strings; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosConflictProperties extends Resource { + + /** + * Initialize a conflict object. + */ + CosmosConflictProperties() { + super(); + } + + /** + * Initialize a conflict object from json string. + * + * @param jsonString the json string that represents the conflict. + */ + CosmosConflictProperties(String jsonString) { + super(jsonString); + } + + /** + * Gets the operation kind. + * + * @return the operation kind. + */ + public String operationKind() { + return super.getString(Constants.Properties.OPERATION_TYPE); + } + + /** + * Gets the type of the conflicting resource. + * + * @return the resource type. + */ + public String resourceType() { + return super.getString(Constants.Properties.RESOURCE_TYPE); + } + + /** + * Gets the resource ID for the conflict in the Azure Cosmos DB service. + * @return resource Id for the conflict. + */ + String sourceResourceId() { + return super.getString(Constants.Properties.SOURCE_RESOURCE_ID); + } + + /** + * Gets the conflicting resource in the Azure Cosmos DB service. + * @param the type of the object. + * @param klass The returned type of conflicting resource. + * @return The conflicting resource. + */ + public T getResource(Class klass) { + String resourceAsString = super.getString(Constants.Properties.CONTENT); + + if (!Strings.isNullOrEmpty(resourceAsString)) { + try { + return klass.getConstructor(String.class).newInstance(resourceAsString); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + } else { + return null; + } + } + + static List getFromV2Results(List results) { + return results.stream().map(conflict -> new CosmosConflictProperties(conflict.toJson())) + .collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictRequestOptions.java new file mode 100644 index 0000000000000..3271fccd84e7e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictRequestOptions.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +public class CosmosConflictRequestOptions { + private AccessCondition accessCondition; + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosConflictRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + + RequestOptions toRequestOptions() { + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setAccessCondition(accessCondition); + return requestOptions; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictResponse.java new file mode 100644 index 0000000000000..6ece0c92f4a85 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosConflictResponse.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.internal.ResourceResponse; + +public class CosmosConflictResponse extends CosmosResponse { + private CosmosContainer container; + private CosmosConflict conflictClient; + + CosmosConflictResponse(ResourceResponse response, CosmosContainer container) { + super(response); + this.container = container; + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosConflictProperties(response.getResource().toJson())); + conflictClient = new CosmosConflict(response.getResource().id(), container); + } + } + + CosmosContainer getContainer() { + return container; + } + + /** + * Get conflict client + * @return the cosmos conflict client + */ + public CosmosConflict conflict() { + return conflictClient; + } + + /** + * Get conflict properties object representing the resource on the server + * @return the conflict properties + */ + public CosmosConflictProperties properties() { + return resourceSettings(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainer.java new file mode 100644 index 0000000000000..c2a55589f499e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainer.java @@ -0,0 +1,500 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Offer; +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.RequestOptions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static com.azure.data.cosmos.Resource.validateResource; + +/** + * Provides methods for reading, deleting, and replacing existing Containers. + * Provides methods for interacting with child resources (Items, Scripts, Conflicts) + */ +public class CosmosContainer { + + private CosmosDatabase database; + private String id; + private CosmosScripts scripts; + + CosmosContainer(String id, CosmosDatabase database) { + this.id = id; + this.database = database; + } + + /** + * Get the id of the {@link CosmosContainer} + * + * @return the id of the {@link CosmosContainer} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosContainer} + * + * @param id the id of the {@link CosmosContainer} + * @return the same {@link CosmosContainer} that had the id set + */ + CosmosContainer id(String id) { + this.id = id; + return this; + } + + /** + * Reads the document container + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response with + * the read container. In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single cosmos container response with + * the read container or an error. + */ + public Mono read() { + return read(new CosmosContainerRequestOptions()); + } + + /** + * Reads the document container by the container link. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response with + * the read container. In case of failure the {@link Mono} will error. + * + * @param options The cosmos container request options. + * @return an {@link Mono} containing the single cosmos container response with + * the read container or an error. + */ + public Mono read(CosmosContainerRequestOptions options) { + if (options == null) { + options = new CosmosContainerRequestOptions(); + } + return database.getDocClientWrapper().readCollection(getLink(), options.toRequestOptions()) + .map(response -> new CosmosContainerResponse(response, database)).single(); + } + + /** + * Deletes the item container + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response for the + * deleted database. In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single cosmos container response for + * the deleted database or an error. + */ + public Mono delete(CosmosContainerRequestOptions options) { + if (options == null) { + options = new CosmosContainerRequestOptions(); + } + return database.getDocClientWrapper().deleteCollection(getLink(), options.toRequestOptions()) + .map(response -> new CosmosContainerResponse(response, database)).single(); + } + + /** + * Deletes the item container + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response for the + * deleted container. In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single cosmos container response for + * the deleted container or an error. + */ + public Mono delete() { + return delete(new CosmosContainerRequestOptions()); + } + + /** + * Replaces a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response with + * the replaced document container. In case of failure the {@link Mono} will + * error. + * + * @param containerSettings the item container properties + * @return an {@link Mono} containing the single cosmos container response with + * the replaced document container or an error. + */ + public Mono replace(CosmosContainerProperties containerSettings) { + return replace(containerSettings, null); + } + + /** + * Replaces a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos container response with + * the replaced document container. In case of failure the {@link Mono} will + * error. + * + * @param containerSettings the item container properties + * @param options the cosmos container request options. + * @return an {@link Mono} containing the single cosmos container response with + * the replaced document container or an error. + */ + public Mono replace(CosmosContainerProperties containerSettings, + CosmosContainerRequestOptions options) { + validateResource(containerSettings); + if (options == null) { + options = new CosmosContainerRequestOptions(); + } + return database.getDocClientWrapper() + .replaceCollection(containerSettings.getV2Collection(), options.toRequestOptions()) + .map(response -> new CosmosContainerResponse(response, database)).single(); + } + + /* CosmosItem operations */ + + /** + * Creates a cosmos item. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single resource response with the + * created cosmos item. In case of failure the {@link Mono} will error. + * + * @param item the cosmos item represented as a POJO or cosmos item object. + * @return an {@link Mono} containing the single resource response with the + * created cosmos item or an error. + */ + public Mono createItem(Object item) { + return createItem(item, new CosmosItemRequestOptions()); + } + + /** + * Creates a cosmos item. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single resource response with the + * created cosmos item. In case of failure the {@link Mono} will error. + * + * @param item the cosmos item represented as a POJO or cosmos item object. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the + * created cosmos item or an error. + */ + public Mono createItem(Object item, CosmosItemRequestOptions options) { + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return database.getDocClientWrapper() + .createDocument(getLink(), CosmosItemProperties.fromObject(item), requestOptions, true) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), this)).single(); + } + + /** + * Upserts an item. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single resource response with the + * upserted item. In case of failure the {@link Mono} will error. + * + * @param item the item represented as a POJO or Item object to upsert. + * @return an {@link Mono} containing the single resource response with the + * upserted document or an error. + */ + public Mono upsertItem(Object item) { + return upsertItem(item, null); + } + + /** + * Upserts a cosmos item. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single resource response with the + * upserted item. In case of failure the {@link Mono} will error. + * + * @param item the item represented as a POJO or Item object to upsert. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the + * upserted document or an error. + */ + public Mono upsertItem(Object item, CosmosItemRequestOptions options) { + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + + return this.getDatabase().getDocClientWrapper() + .upsertDocument(this.getLink(), CosmosItemProperties.fromObject(item), options.toRequestOptions(), true) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), this)).single(); + } + + /** + * Reads all cosmos items in the container. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read cosmos items. In case of + * failure the {@link Flux} will error. + * + * @return an {@link Flux} containing one or several feed response pages of the + * read cosmos items or an error. + */ + public Flux> readAllItems() { + return readAllItems(new FeedOptions()); + } + + /** + * Reads all cosmos items in a container. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read cosmos items. In case of + * failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the + * read cosmos items or an error. + */ + public Flux> readAllItems(FeedOptions options) { + return getDatabase().getDocClientWrapper().readDocuments(getLink(), options).map( + response -> BridgeInternal.createFeedResponse(CosmosItemProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Query for documents in a items in a container + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained items. In case of + * failure the {@link Flux} will error. + * + * @param query the query. + * @return an {@link Flux} containing one or several feed response pages of the + * obtained items or an error. + */ + public Flux> queryItems(String query) { + return queryItems(new SqlQuerySpec(query), null); + } + + /** + * Query for documents in a items in a container + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained items. In case of + * failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the + * obtained items or an error. + */ + public Flux> queryItems(String query, FeedOptions options) { + return queryItems(new SqlQuerySpec(query), options); + } + + /** + * Query for documents in a items in a container + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained items. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @return an {@link Flux} containing one or several feed response pages of the + * obtained items or an error. + */ + public Flux> queryItems(SqlQuerySpec querySpec) { + return queryItems(querySpec, null); + } + + /** + * Query for documents in a items in a container + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained items. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the + * obtained items or an error. + */ + public Flux> queryItems(SqlQuerySpec querySpec, FeedOptions options) { + return getDatabase().getDocClientWrapper().queryDocuments(getLink(), querySpec, options) + .map(response -> BridgeInternal.createFeedResponseWithQueryMetrics( + CosmosItemProperties.getFromV2Results(response.results()), response.responseHeaders(), + response.queryMetrics())); + } + + /** + * Query for documents in a items in a container + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained items. In case of + * failure the {@link Flux} will error. + * + * @param changeFeedOptions the feed options. + * @return an {@link Flux} containing one or several feed response pages of the + * obtained items or an error. + */ + public Flux> queryChangeFeedItems(ChangeFeedOptions changeFeedOptions) { + return getDatabase().getDocClientWrapper().queryDocumentChangeFeed(getLink(), changeFeedOptions) + .map(response -> new FeedResponse( + CosmosItemProperties.getFromV2Results(response.results()), response.responseHeaders(), false)); + } + + /** + * Gets a CosmosItem object without making a service call + * + * @param id id of the item + * @param partitionKey the partition key + * @return a cosmos item + */ + public CosmosItem getItem(String id, Object partitionKey) { + return new CosmosItem(id, partitionKey, this); + } + + public CosmosScripts getScripts() { + if (this.scripts == null) { + this.scripts = new CosmosScripts(this); + } + return this.scripts; + } + + /** + * Lists all the conflicts in the container + * + * @param options the feed options + * @return a {@link Flux} containing one or several feed response pages of the + * obtained conflicts or an error. + */ + public Flux> readAllConflicts(FeedOptions options) { + return database.getDocClientWrapper().readConflicts(getLink(), options) + .map(response -> BridgeInternal.createFeedResponse( + CosmosConflictProperties.getFromV2Results(response.results()), response.responseHeaders())); + } + + /** + * Queries all the conflicts in the container + * + * @param query the query + * @return a {@link Flux} containing one or several feed response pages of the + * obtained conflicts or an error. + */ + public Flux> queryConflicts(String query) { + return queryConflicts(query, null); + } + + /** + * Queries all the conflicts in the container + * + * @param query the query + * @param options the feed options + * @return a {@link Flux} containing one or several feed response pages of the + * obtained conflicts or an error. + */ + public Flux> queryConflicts(String query, FeedOptions options) { + return database.getDocClientWrapper().queryConflicts(getLink(), query, options) + .map(response -> BridgeInternal.createFeedResponse( + CosmosConflictProperties.getFromV2Results(response.results()), response.responseHeaders())); + } + + /** + * Gets a CosmosConflict object without making a service call + * + * @param id id of the cosmos conflict + * @return a cosmos conflict + */ + public CosmosConflict getConflict(String id) { + return new CosmosConflict(id, this); + } + + /** + * Gets the throughput of the container + * + * @return a {@link Mono} containing throughput or an error. + */ + public Mono readProvisionedThroughput() { + return this.read().flatMap(cosmosContainerResponse -> database.getDocClientWrapper() + .queryOffers("select * from c where c.offerResourceId = '" + + cosmosContainerResponse.resourceSettings().resourceId() + "'", new FeedOptions()) + .single()).flatMap(offerFeedResponse -> { + if (offerFeedResponse.results().isEmpty()) { + return Mono.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + "No offers found for the resource")); + } + return database.getDocClientWrapper().readOffer(offerFeedResponse.results().get(0).selfLink()) + .single(); + }).map(cosmosOfferResponse -> cosmosOfferResponse.getResource().getThroughput()); + } + + /** + * Sets throughput provisioned for a container in measurement of + * Requests-per-Unit in the Azure Cosmos service. + * + * @param requestUnitsPerSecond the cosmos container throughput, expressed in + * Request Units per second + * @return a {@link Mono} containing throughput or an error. + */ + public Mono replaceProvisionedThroughput(int requestUnitsPerSecond) { + return this.read().flatMap(cosmosContainerResponse -> database.getDocClientWrapper() + .queryOffers("select * from c where c.offerResourceId = '" + + cosmosContainerResponse.resourceSettings().resourceId() + "'", new FeedOptions()) + .single()).flatMap(offerFeedResponse -> { + if (offerFeedResponse.results().isEmpty()) { + return Mono.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + "No offers found for the resource")); + } + Offer offer = offerFeedResponse.results().get(0); + offer.setThroughput(requestUnitsPerSecond); + return database.getDocClientWrapper().replaceOffer(offer).single(); + }).map(offerResourceResponse -> offerResourceResponse.getResource().getThroughput()); + } + + /** + * Gets the parent Database + * + * @return the {@link CosmosDatabase} + */ + public CosmosDatabase getDatabase() { + return database; + } + + String URIPathSegment() { + return Paths.COLLECTIONS_PATH_SEGMENT; + } + + String parentLink() { + return database.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerProperties.java new file mode 100644 index 0000000000000..244bf3422db76 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerProperties.java @@ -0,0 +1,216 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.ResourceResponse; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Represents a item container in the Azure Cosmos DB database service. A cosmos container is a named logical container + * for cosmos items. + *

    + * A database may contain zero or more named containers and each container consists of zero or more JSON items. + * Being schema-free, the items in a container do not need to share the same structure or fields. Since containers + * are application resources, they can be authorized using either the master key or resource keys. + */ +public class CosmosContainerProperties extends Resource { + + private IndexingPolicy indexingPolicy; + private UniqueKeyPolicy uniqueKeyPolicy; + private PartitionKeyDefinition partitionKeyDefinition; + + /** + * Constructor + * @param id id of the Container + * @param partitionKeyPath partition key path + */ + public CosmosContainerProperties(String id, String partitionKeyPath) { + super.id(id); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add(partitionKeyPath); + partitionKeyDef.paths(paths); + partitionKeyDefinition(partitionKeyDef); + } + + /** + * Constructor + * @param id id of the container + * @param partitionKeyDefinition the {@link PartitionKeyDefinition} + */ + public CosmosContainerProperties(String id, PartitionKeyDefinition partitionKeyDefinition) { + super.id(id); + partitionKeyDefinition(partitionKeyDefinition); + } + + CosmosContainerProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + // Converting document collection to CosmosContainerProperties + CosmosContainerProperties(DocumentCollection collection){ + super(collection.toJson()); + } + + static List getFromV2Results(List results){ + return results.stream().map(CosmosContainerProperties::new).collect(Collectors.toList()); + } + + /** + * Gets the container's indexing policy. + * + * @return the indexing policy. + */ + public IndexingPolicy indexingPolicy() { + if (this.indexingPolicy == null) { + if (super.has(Constants.Properties.INDEXING_POLICY)) { + this.indexingPolicy = super.getObject(Constants.Properties.INDEXING_POLICY, IndexingPolicy.class); + } else { + this.indexingPolicy = new IndexingPolicy(); + } + } + + return this.indexingPolicy; + } + + /** + * Sets the container's indexing policy + * + * @param indexingPolicy {@link IndexingPolicy} the indexing policy + * @return the CosmosContainerProperties. + */ + public CosmosContainerProperties indexingPolicy(IndexingPolicy indexingPolicy) { + if (indexingPolicy == null) { + throw new IllegalArgumentException("IndexingPolicy cannot be null."); + } + this.indexingPolicy = indexingPolicy; + super.set(Constants.Properties.INDEXING_POLICY, indexingPolicy); + return this; + } + + /** + * Gets the containers unique key policy + * + * @return the unique key policy + */ + public UniqueKeyPolicy uniqueKeyPolicy() { + + // Thread safe lazy initialization for case when collection is cached (and is basically readonly). + if (this.uniqueKeyPolicy == null) { + this.uniqueKeyPolicy = super.getObject(Constants.Properties.UNIQUE_KEY_POLICY, UniqueKeyPolicy.class); + + if (this.uniqueKeyPolicy == null) { + this.uniqueKeyPolicy = new UniqueKeyPolicy(); + } + } + + return this.uniqueKeyPolicy; + } + + /** + * Sets the Containers unique key policy + * + * @param uniqueKeyPolicy the unique key policy + * @return the CosmosContainerProperties. + */ + public CosmosContainerProperties uniqueKeyPolicy(UniqueKeyPolicy uniqueKeyPolicy) { + if (uniqueKeyPolicy == null) { + throw new IllegalArgumentException("uniqueKeyPolicy cannot be null."); + } + + this.uniqueKeyPolicy = uniqueKeyPolicy; + super.set(Constants.Properties.UNIQUE_KEY_POLICY, uniqueKeyPolicy); + return this; + } + + /** + * Gets the containers's partition key definition. + * + * @return the partition key definition. + */ + public PartitionKeyDefinition partitionKeyDefinition() { + if (this.partitionKeyDefinition == null) { + + if (super.has(Constants.Properties.PARTITION_KEY)) { + this.partitionKeyDefinition = super.getObject(Constants.Properties.PARTITION_KEY, PartitionKeyDefinition.class); + } else { + this.partitionKeyDefinition = new PartitionKeyDefinition(); + } + } + + return this.partitionKeyDefinition; + } + + /** + * Sets the containers's partition key definition. + * + * @param partitionKeyDefinition the partition key definition. + * @return the CosmosContainerProperties. + */ + public CosmosContainerProperties partitionKeyDefinition(PartitionKeyDefinition partitionKeyDefinition) { + if (partitionKeyDefinition == null) { + throw new IllegalArgumentException("partitionKeyDefinition cannot be null."); + } + + this.partitionKeyDefinition = partitionKeyDefinition; + return this; + } + + /** + * Gets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @return ConflictResolutionPolicy + */ + public ConflictResolutionPolicy conflictResolutionPolicy() { + return super.getObject(Constants.Properties.CONFLICT_RESOLUTION_POLICY, ConflictResolutionPolicy.class); + } + + /** + * Sets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @param value ConflictResolutionPolicy to be used. + * @return the CosmosContainerProperties. + */ + public CosmosContainerProperties conflictResolutionPolicy(ConflictResolutionPolicy value) { + if (value == null) { + throw new IllegalArgumentException("CONFLICT_RESOLUTION_POLICY cannot be null."); + } + + super.set(Constants.Properties.CONFLICT_RESOLUTION_POLICY, value); + return this; + } + + DocumentCollection getV2Collection(){ + DocumentCollection collection = new DocumentCollection(this.toJson()); + collection.setPartitionKey(this.partitionKeyDefinition()); + collection.setIndexingPolicy(this.indexingPolicy()); + return collection; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerRequestOptions.java new file mode 100644 index 0000000000000..c2222cca36b5b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerRequestOptions.java @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +/** + * Encapsulates options that can be specified for a request issued to cosmos container. + */ +public class CosmosContainerRequestOptions { + private Integer offerThroughput; + private boolean populateQuotaInfo; + private ConsistencyLevel consistencyLevel; + private String sessionToken; + private AccessCondition accessCondition; + + /** + * Gets the throughput in the form of Request Units per second when creating a cosmos container. + * + * @return the throughput value. + */ + Integer offerThroughput() { + return offerThroughput; + } + + /** + * Sets the throughput in the form of Request Units per second when creating a cosmos container. + * + * @param offerThroughput the throughput value. + * @return the current request options + */ + CosmosContainerRequestOptions offerThroughput(Integer offerThroughput) { + this.offerThroughput = offerThroughput; + return this; + } + + /** + * Gets the PopulateQuotaInfo setting for cosmos container read requests in the Azure Cosmos DB database service. + * PopulateQuotaInfo is used to enable/disable getting cosmos container quota related stats for document + * collection read requests. + * + * @return true if PopulateQuotaInfo is enabled + */ + public boolean populateQuotaInfo() { + return populateQuotaInfo; + } + + /** + * Sets the PopulateQuotaInfo setting for cosmos container read requests in the Azure Cosmos DB database service. + * PopulateQuotaInfo is used to enable/disable getting cosmos container quota related stats for document + * collection read requests. + * + * @param populateQuotaInfo a boolean value indicating whether PopulateQuotaInfo is enabled or not + * @return the current request options + */ + public CosmosContainerRequestOptions populateQuotaInfo(boolean populateQuotaInfo) { + this.populateQuotaInfo = populateQuotaInfo; + return this; + } + + /** + * Gets the consistency level required for the request. + * + * @return the consistency level. + */ + public ConsistencyLevel consistencyLevel() { + return consistencyLevel; + } + + /** + * Sets the consistency level required for the request. + * + * @param consistencyLevel the consistency level. + * @return the current request options + */ + public CosmosContainerRequestOptions consistencyLevel(ConsistencyLevel consistencyLevel) { + this.consistencyLevel = consistencyLevel; + return this; + } + + /** + * Gets the token for use with session consistency. + * + * @return the session token. + */ + public String sessionToken() { + return sessionToken; + } + + /** + * Sets the token for use with session consistency. + * + * @param sessionToken the session token. + * @return the current request options + */ + public CosmosContainerRequestOptions sessionToken(String sessionToken) { + this.sessionToken = sessionToken; + return this; + } + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosContainerRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + + RequestOptions toRequestOptions() { + RequestOptions options = new RequestOptions(); + options.setAccessCondition(accessCondition); + options.setOfferThroughput(offerThroughput); + options.setPopulateQuotaInfo(populateQuotaInfo); + options.setSessionToken(sessionToken); + options.setConsistencyLevel(consistencyLevel); + return options; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerResponse.java new file mode 100644 index 0000000000000..50c82ee30f3f2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosContainerResponse.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.ResourceResponse; + +public class CosmosContainerResponse extends CosmosResponse { + + private CosmosContainer container; + + CosmosContainerResponse(ResourceResponse response, CosmosDatabase database) { + super(response); + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosContainerProperties(response)); + container = new CosmosContainer(resourceSettings().id(), database); + } + } + + /** + * Gets the progress of an index transformation, if one is underway. + * + * @return the progress of an index transformation. + */ + public long indexTransformationProgress() { + return resourceResponseWrapper.getIndexTransformationProgress(); + } + + /** + * Gets the progress of lazy indexing. + * + * @return the progress of lazy indexing. + */ + long lazyIndexingProgress() { + return resourceResponseWrapper.getLazyIndexingProgress(); + } + + /** + * Gets the container properties + * @return the cosmos container properties + */ + public CosmosContainerProperties properties() { + return resourceSettings(); + } + + /** + * Gets the Container object + * @return the Cosmos container object + */ + public CosmosContainer container() { + return container; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabase.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabase.java new file mode 100644 index 0000000000000..b37885710fefd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabase.java @@ -0,0 +1,627 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Offer; +import com.azure.data.cosmos.internal.Paths; +import org.apache.commons.lang3.StringUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static com.azure.data.cosmos.Resource.validateResource; + +/** + * Perform read and delete databases, update database throughput, and perform operations on child resources + */ +public class CosmosDatabase { + private CosmosClient client; + private String id; + + CosmosDatabase(String id, CosmosClient client) { + this.id = id; + this.client = client; + } + + /** + * Get the id of the CosmosDatabase + * + * @return the id of the CosmosDatabase + */ + public String id() { + return id; + } + + /** + * Set the id of the CosmosDatabase + * + * @param id the id of the CosmosDatabase + * @return the same CosmosConflict that had the id set + */ + CosmosDatabase id(String id) { + this.id = id; + return this; + } + + /** + * Reads a database. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a single cosmos database respone with the + * read database. In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single cosmos database respone with + * the read database or an error. + */ + public Mono read() { + return read(new CosmosDatabaseRequestOptions()); + } + + /** + * Reads a database. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos cosmos database respone with the + * read database. In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single cosmos database response with + * the read database or an error. + */ + public Mono read(CosmosDatabaseRequestOptions options) { + return getDocClientWrapper().readDatabase(getLink(), options.toRequestOptions()) + .map(response -> new CosmosDatabaseResponse(response, getClient())).single(); + } + + /** + * Deletes a database. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos database response with the + * deleted database. In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single cosmos database response + */ + public Mono delete() { + return delete(new CosmosDatabaseRequestOptions()); + } + + /** + * Deletes a database. + *

    + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos database response with the + * deleted database. In case of failure the {@link Mono} will error. + * + * @param options the request options + * @return an {@link Mono} containing the single cosmos database response + */ + public Mono delete(CosmosDatabaseRequestOptions options) { + return getDocClientWrapper().deleteDatabase(getLink(), options.toRequestOptions()) + .map(response -> new CosmosDatabaseResponse(response, getClient())).single(); + } + + /* CosmosContainer operations */ + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param containerSettings the container properties. + * @return an {@link Flux} containing the single cosmos container response with + * the created container or an error. + */ + public Mono createContainer(CosmosContainerProperties containerSettings) { + return createContainer(containerSettings, new CosmosContainerRequestOptions()); + } + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param containerSettings the container properties. + * @param throughput the throughput for the container + * @return an {@link Flux} containing the single cosmos container response with + * the created container or an error. + */ + public Mono createContainer(CosmosContainerProperties containerSettings, int throughput) { + validateResource(containerSettings); + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(throughput); + return createContainer(containerSettings, options); + } + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param containerSettings the containerSettings. + * @param options the cosmos container request options + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainer(CosmosContainerProperties containerSettings, + CosmosContainerRequestOptions options) { + validateResource(containerSettings); + return getDocClientWrapper() + .createCollection(this.getLink(), containerSettings.getV2Collection(), options.toRequestOptions()) + .map(response -> new CosmosContainerResponse(response, this)).single(); + } + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param containerSettings the containerSettings. + * @param throughput the throughput for the container + * @param options the cosmos container request options + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainer(CosmosContainerProperties containerSettings, + int throughput, + CosmosContainerRequestOptions options) { + options.offerThroughput(throughput); + return createContainer(containerSettings, options); + } + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param id the cosmos container id + * @param partitionKeyPath the partition key path + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainer(String id, String partitionKeyPath) { + return createContainer(new CosmosContainerProperties(id, partitionKeyPath)); + } + + /** + * Creates a document container. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param id the cosmos container id + * @param partitionKeyPath the partition key path + * @param throughput the throughput for the container + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainer(String id, String partitionKeyPath, int throughput) { + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(throughput); + return createContainer(new CosmosContainerProperties(id, partitionKeyPath), options); + } + + /** + * Creates a document container if it does not exist on the service. + *

    + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created or existing collection. In case of failure the {@link Mono} will + * error. + * + * @param containerSettings the container properties + * @return a {@link Mono} containing the cosmos container response with the + * created or existing container or an error. + */ + public Mono createContainerIfNotExists(CosmosContainerProperties containerSettings) { + CosmosContainer container = getContainer(containerSettings.id()); + return createContainerIfNotExistsInternal(containerSettings, container, null); + } + + /** + * Creates a document container if it does not exist on the service. + *

    + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created or existing collection. In case of failure the {@link Mono} will + * error. + * + * @param containerSettings the container properties + * @param throughput the throughput for the container + * @return a {@link Mono} containing the cosmos container response with the + * created or existing container or an error. + */ + public Mono createContainerIfNotExists(CosmosContainerProperties containerSettings, int throughput) { + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(throughput); + CosmosContainer container = getContainer(containerSettings.id()); + return createContainerIfNotExistsInternal(containerSettings, container, options); + } + + /** + * Creates a document container if it does not exist on the service. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param id the cosmos container id + * @param partitionKeyPath the partition key path + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainerIfNotExists(String id, String partitionKeyPath) { + CosmosContainer container = getContainer(id); + return createContainerIfNotExistsInternal(new CosmosContainerProperties(id, partitionKeyPath), container, null); + } + + /** + * Creates a document container if it does not exist on the service. + * + * After subscription the operation will be performed. The {@link Mono} upon + * successful completion will contain a cosmos container response with the + * created collection. In case of failure the {@link Mono} will error. + * + * @param id the cosmos container id + * @param partitionKeyPath the partition key path + * @param throughput the throughput for the container + * @return an {@link Flux} containing the cosmos container response with the + * created container or an error. + */ + public Mono createContainerIfNotExists(String id, String partitionKeyPath, int throughput) { + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(throughput); + CosmosContainer container = getContainer(id); + return createContainerIfNotExistsInternal(new CosmosContainerProperties(id, partitionKeyPath), container, options); + } + + private Mono createContainerIfNotExistsInternal( + CosmosContainerProperties containerSettings, CosmosContainer container, CosmosContainerRequestOptions options) { + return container.read(options).onErrorResume(exception -> { + if (exception instanceof CosmosClientException) { + CosmosClientException cosmosClientException = (CosmosClientException) exception; + if (cosmosClientException.statusCode() == HttpConstants.StatusCodes.NOTFOUND) { + return createContainer(containerSettings, options); + } + } + return Mono.error(exception); + }); + } + + /** + * Reads all cosmos containers. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read containers. In case of + * failure the {@link Flux} will error. + * + * @param options {@link FeedOptions} + * @return a {@link Flux} containing one or several feed response pages of read + * containers or an error. + */ + public Flux> readAllContainers(FeedOptions options) { + return getDocClientWrapper().readCollections(getLink(), options) + .map(response -> BridgeInternal.createFeedResponse( + CosmosContainerProperties.getFromV2Results(response.results()), response.responseHeaders())); + } + + /** + * Reads all cosmos containers. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read containers. In case of + * failure the {@link Flux} will error. + * + * @return a {@link Flux} containing one or several feed response pages of read + * containers or an error. + */ + public Flux> readAllContainers() { + return readAllContainers(new FeedOptions()); + } + + /** + * Query for cosmos containers in a cosmos database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained containers. In case of + * failure the {@link Flux} will error. + * + * @param query the query + * @return a {@link Flux} containing one or several feed response pages of the + * obtained containers or an error. + */ + public Flux> queryContainers(String query) { + return queryContainers(new SqlQuerySpec(query)); + } + + /** + * Query for cosmos containers in a cosmos database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained containers. In case of + * failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return a {@link Flux} containing one or several feed response pages of the + * obtained containers or an error. + */ + public Flux> queryContainers(String query, FeedOptions options) { + return queryContainers(new SqlQuerySpec(query), options); + } + + /** + * Query for cosmos containers in a cosmos database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained containers. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @return a {@link Flux} containing one or several feed response pages of the + * obtained containers or an error. + */ + public Flux> queryContainers(SqlQuerySpec querySpec) { + return queryContainers(querySpec, null); + } + + /** + * Query for cosmos containers in a cosmos database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained containers. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return a {@link Flux} containing one or several feed response pages of the + * obtained containers or an error. + */ + public Flux> queryContainers(SqlQuerySpec querySpec, FeedOptions options) { + return getDocClientWrapper().queryCollections(getLink(), querySpec, options) + .map(response -> BridgeInternal.createFeedResponse( + CosmosContainerProperties.getFromV2Results(response.results()), response.responseHeaders())); + } + + /** + * Gets a CosmosContainer object without making a service call + * + * @param id id of the container + * @return Cosmos Container + */ + public CosmosContainer getContainer(String id) { + return new CosmosContainer(id, this); + } + + /** User operations **/ + + /** + * Creates a user After subscription the operation will be performed. The + * {@link Mono} upon successful completion will contain a single resource + * response with the created user. In case of failure the {@link Mono} will + * error. + * + * @param settings the cosmos user properties + * @return an {@link Mono} containing the single resource response with the + * created cosmos user or an error. + */ + public Mono createUser(CosmosUserProperties settings) { + return getDocClientWrapper().createUser(this.getLink(), settings.getV2User(), null) + .map(response -> new CosmosUserResponse(response, this)).single(); + } + + + /** + * Upsert a user. Upsert will create a new user if it doesn't exist, or replace + * the existing one if it does. After subscription the operation will be + * performed. The {@link Mono} upon successful completion will contain a single + * resource response with the created user. In case of failure the {@link Mono} + * will error. + * + * @param settings the cosmos user properties + * @return an {@link Mono} containing the single resource response with the + * upserted user or an error. + */ + public Mono upsertUser(CosmosUserProperties settings) { + return getDocClientWrapper().upsertUser(this.getLink(), settings.getV2User(), null) + .map(response -> new CosmosUserResponse(response, this)).single(); + } + + /** + * Reads all cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read cosmos users. In case of + * failure the {@link Flux} will error. + * + * @return an {@link Flux} containing one or several feed response pages of the + * read cosmos users or an error. + */ + public Flux> readAllUsers() { + return readAllUsers(new FeedOptions()); + } + + /** + * Reads all cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the read cosmos users. In case of + * failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the + * read cosmos users or an error. + */ + public Flux> readAllUsers(FeedOptions options) { + return getDocClientWrapper().readUsers(getLink(), options).map(response -> BridgeInternal.createFeedResponse( + CosmosUserProperties.getFromV2Results(response.results()), response.responseHeaders())); + } + + /** + * Query for cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained users. In case of + * failure the {@link Flux} will error. + * + * @param query query as string + * @return a {@link Flux} containing one or several feed response pages of the + * obtained users or an error. + */ + public Flux> queryUsers(String query) { + return queryUsers(query, null); + } + + /** + * Query for cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained users. In case of + * failure the {@link Flux} will error. + * + * @param query query as string + * @param options the feed options + * @return a {@link Flux} containing one or several feed response pages of the + * obtained users or an error. + */ + public Flux> queryUsers(String query, FeedOptions options) { + return queryUsers(new SqlQuerySpec(query), options); + } + + /** + * Query for cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained users. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @return a {@link Flux} containing one or several feed response pages of the + * obtained users or an error. + */ + public Flux> queryUsers(SqlQuerySpec querySpec) { + return queryUsers(querySpec, null); + } + + /** + * Query for cosmos users in a database. + * + * After subscription the operation will be performed. The {@link Flux} will + * contain one or several feed response of the obtained users. In case of + * failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return a {@link Flux} containing one or several feed response pages of the + * obtained users or an error. + */ + public Flux> queryUsers(SqlQuerySpec querySpec, FeedOptions options) { + return getDocClientWrapper().queryUsers(getLink(), querySpec, options) + .map(response -> BridgeInternal.createFeedResponseWithQueryMetrics( + CosmosUserProperties.getFromV2Results(response.results()), response.responseHeaders(), + response.queryMetrics())); + } + + public CosmosUser getUser(String id) { + return new CosmosUser(id, this); + } + + /** + * Gets the throughput of the database + * + * @return a {@link Mono} containing throughput or an error. + */ + public Mono readProvisionedThroughput() { + return this.read().flatMap(cosmosDatabaseResponse -> getDocClientWrapper() + .queryOffers("select * from c where c.offerResourceId = '" + + cosmosDatabaseResponse.resourceSettings().resourceId() + "'", new FeedOptions()) + .single().flatMap(offerFeedResponse -> { + if (offerFeedResponse.results().isEmpty()) { + return Mono.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + "No offers found for the resource")); + } + return getDocClientWrapper().readOffer(offerFeedResponse.results().get(0).selfLink()).single(); + }).map(cosmosContainerResponse1 -> cosmosContainerResponse1.getResource().getThroughput())); + } + + /** + * Sets throughput provisioned for a container in measurement of + * Requests-per-Unit in the Azure Cosmos service. + * + * @param requestUnitsPerSecond the cosmos container throughput, expressed in + * Request Units per second + * @return a {@link Mono} containing throughput or an error. + */ + public Mono replaceProvisionedThroughput(int requestUnitsPerSecond) { + return this.read().flatMap(cosmosDatabaseResponse -> this.getDocClientWrapper() + .queryOffers("select * from c where c.offerResourceId = '" + + cosmosDatabaseResponse.resourceSettings().resourceId() + "'", new FeedOptions()) + .single().flatMap(offerFeedResponse -> { + if (offerFeedResponse.results().isEmpty()) { + return Mono.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + "No offers found for the resource")); + } + Offer offer = offerFeedResponse.results().get(0); + offer.setThroughput(requestUnitsPerSecond); + return this.getDocClientWrapper().replaceOffer(offer).single(); + }).map(offerResourceResponse -> offerResourceResponse.getResource().getThroughput())); + } + + CosmosClient getClient() { + return client; + } + + AsyncDocumentClient getDocClientWrapper() { + return client.getDocClientWrapper(); + } + + String URIPathSegment() { + return Paths.DATABASES_PATH_SEGMENT; + } + + String parentLink() { + return StringUtils.EMPTY; + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseProperties.java new file mode 100644 index 0000000000000..8153fb579bb7d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseProperties.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.ResourceResponse; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Represents a CosmosDatabase in the Azure Cosmos database service. A cosmos database manages users, permissions and a set of containers + *

    + * Each Azure Cosmos DB Service is able to support multiple independent named databases, with the database being the + * logical container for data. Each Database consists of one or more cosmos containers, each of which in turn contain one or + * more cosmos items. Since databases are an an administrative resource and the Service Key will be required in + * order to access and successfully complete any action using the User APIs. + */ +public class CosmosDatabaseProperties extends Resource { + + /** + * Constructor + * @param id id of the database + */ + public CosmosDatabaseProperties(String id) { + super.id(id); + } + + CosmosDatabaseProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + // Converting document collection to CosmosContainerProperties + CosmosDatabaseProperties(Database database){ + super(database.toJson()); + } + + static List getFromV2Results(List results){ + return results.stream().map(CosmosDatabaseProperties::new).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseRequestOptions.java new file mode 100644 index 0000000000000..ca1b8cc0ecd77 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseRequestOptions.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +/** + * Encapsulates options that can be specified for a request issued to cosmos database. + */ +public class CosmosDatabaseRequestOptions{ + private Integer offerThroughput; + private AccessCondition accessCondition; + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosDatabaseRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + + /** + * Gets the throughput in the form of Request Units per second when creating a cosmos database. + * + * @return the throughput value. + */ + Integer offerThroughput() { + return offerThroughput; + } + + /** + * Sets the throughput in the form of Request Units per second when creating a cosmos database. + * + * @param offerThroughput the throughput value. + * @return the current request options + */ + CosmosDatabaseRequestOptions offerThroughput(Integer offerThroughput) { + this.offerThroughput = offerThroughput; + return this; + } + + RequestOptions toRequestOptions() { + RequestOptions options = new RequestOptions(); + options.setAccessCondition(accessCondition); + options.setOfferThroughput(offerThroughput); + return options; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseResponse.java new file mode 100644 index 0000000000000..b1b2240c289fe --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosDatabaseResponse.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.ResourceResponse; + +public class CosmosDatabaseResponse extends CosmosResponse{ + private CosmosDatabase database; + + CosmosDatabaseResponse(ResourceResponse response, CosmosClient client) { + super(response); + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosDatabaseProperties(response)); + database = new CosmosDatabase(resourceSettings().id(), client); + } + } + + /** + * Gets the CosmosDatabase object + * + * @return {@link CosmosDatabase} + */ + public CosmosDatabase database() { + return database; + } + + /** + * Gets the cosmos database properties + * + * @return the cosmos database properties + */ + public CosmosDatabaseProperties properties() { + return resourceSettings(); + } + + /** + * Gets the Max Quota. + * + * @return the database quota. + */ + public long databaseQuota(){ + return resourceResponseWrapper.getDatabaseQuota(); + } + + /** + * Gets the current Usage. + * + * @return the current database usage. + */ + public long databaseUsage(){ + return resourceResponseWrapper.getDatabaseUsage(); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosError.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosError.java new file mode 100644 index 0000000000000..15f0351df0912 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosError.java @@ -0,0 +1,148 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Encapsulates error related details in the Azure Cosmos DB database service. + */ +public class CosmosError extends Resource { + /** + * Initialize a new instance of the Error object. + */ + public CosmosError() { + super(); + } + + /** + * Initialize a new instance of the Error object from a JSON string. + * + * @param objectNode the {@link ObjectNode} that represents the error. + */ + CosmosError(ObjectNode objectNode) { + super(objectNode); + } + + /** + * Initialize a new instance of the Error object from a JSON string. + * + * @param jsonString the jsonString that represents the error. + */ + CosmosError(String jsonString) { + super(jsonString); + } + + /** + * Initialize a new instance of the Error object. + * + * @param errorCode the error code. + * @param message the error message. + */ + public CosmosError(String errorCode, String message) { + this(errorCode, message, null); + } + + /** + * Initialize a new instance of the Error object. + * + * @param errorCode + * the error code. + * @param message + * the error message. + * @param additionalErrorInfo + * additional error info. + */ + public CosmosError(String errorCode, String message, String additionalErrorInfo) { + super(); + this.setCode(errorCode); + this.setMessage(message); + this.setAdditionalErrorInfo(additionalErrorInfo); + } + + /** + * Gets the error code. + * + * @return the error code. + */ + public String getCode() { + return super.getString(Constants.Properties.CODE); + } + + /** + * Sets the error code. + * + * @param code the error code. + */ + private void setCode(String code) { + super.set(Constants.Properties.CODE, code); + } + + /** + * Gets the error message. + * + * @return the error message. + */ + public String getMessage() { + return super.getString(Constants.Properties.MESSAGE); + } + + /** + * Sets the error message. + * + * @param message the error message. + */ + private void setMessage(String message) { + super.set(Constants.Properties.MESSAGE, message); + } + + /** + * Gets the error details. + * + * @return the error details. + */ + public String getErrorDetails() { + return super.getString(Constants.Properties.ERROR_DETAILS); + } + + /** + * Sets the partitioned query execution info. + * + * @param additionalErrorInfo + * the partitioned query execution info. + */ + private void setAdditionalErrorInfo(String additionalErrorInfo) { + super.set(Constants.Properties.ADDITIONAL_ERROR_INFO, additionalErrorInfo); + } + + /** + * Gets the partitioned query execution info. + * + * @return the partitioned query execution info. + */ + public String getPartitionedQueryExecutionInfo() { + return super.getString(Constants.Properties.ADDITIONAL_ERROR_INFO); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItem.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItem.java new file mode 100644 index 0000000000000..74eeaa27a576c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItem.java @@ -0,0 +1,186 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.RequestOptions; +import reactor.core.publisher.Mono; + +public class CosmosItem { + private Object partitionKey; + private CosmosContainer container; + private String id; + + CosmosItem(String id, Object partitionKey, CosmosContainer container) { + this.id = id; + this.partitionKey = partitionKey; + this.container = container; + } + + /** + * Get the id of the {@link CosmosItem} + * @return the id of the {@link CosmosItem} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosItem} + * @param id the id of the {@link CosmosItem} + * @return the same {@link CosmosItem} that had the id set + */ + CosmosItem id(String id) { + this.id = id; + return this; + } + + /** + * Reads an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a cosmos item response with the read item + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the cosmos item response with the read item or an error + */ + public Mono read() { + return read(new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Reads an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a cosmos item response with the read item + * In case of failure the {@link Mono} will error. + * + * @param options the request comosItemRequestOptions + * @return an {@link Mono} containing the cosmos item response with the read item or an error + */ + public Mono read(CosmosItemRequestOptions options) { + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return container.getDatabase().getDocClientWrapper() + .readDocument(getLink(), requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .single(); + } + + /** + * Replaces an item with the passed in item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param item the item to replace (containing the document id). + * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. + */ + public Mono replace(Object item){ + return replace(item, new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Replaces an item with the passed in item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param item the item to replace (containing the document id). + * @param options the request comosItemRequestOptions + * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. + */ + public Mono replace(Object item, CosmosItemRequestOptions options){ + Document doc = CosmosItemProperties.fromObject(item); + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return container.getDatabase() + .getDocClientWrapper() + .replaceDocument(getLink(), doc, requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .single(); + } + + /** + * Deletes the item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * @return an {@link Mono} containing the cosmos item resource response. + */ + public Mono delete() { + return delete(new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Deletes the item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param options the request options + * @return an {@link Mono} containing the cosmos item resource response. + */ + public Mono delete(CosmosItemRequestOptions options){ + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return container.getDatabase() + .getDocClientWrapper() + .deleteDocument(getLink(), requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .single(); + } + + void setContainer(CosmosContainer container) { + this.container = container; + } + + String URIPathSegment() { + return Paths.DOCUMENTS_PATH_SEGMENT; + } + + String parentLink() { + return this.container.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemProperties.java new file mode 100644 index 0000000000000..c610554cf3b58 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemProperties.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosItemProperties extends Resource { + + private static final ObjectMapper mapper = Utils.getSimpleObjectMapper(); + + /** + * Initialize an empty CosmosItemProperties object. + */ + public CosmosItemProperties() { + } + + /** + * Sets the id + * + * @param id the name of the resource. + * @return the cosmos item properties with id set + */ + public CosmosItemProperties id(String id) { + super.id(id); + return this; + } + + /** + * Initialize a CosmosItemProperties object from json string. + * + * @param jsonString the json string that represents the document object. + */ + public CosmosItemProperties(String jsonString) { + super(jsonString); + } + + /** + * fromObject returns Document for compatibility with V2 sdk + * + * @param cosmosItem + * @return + */ + static Document fromObject(Object cosmosItem) { + Document typedItem; + if (cosmosItem instanceof CosmosItemProperties) { + typedItem = new Document(((CosmosItemProperties) cosmosItem).toJson()); + } else { + try { + return new Document(CosmosItemProperties.mapper.writeValueAsString(cosmosItem)); + } catch (IOException e) { + throw new IllegalArgumentException("Can't serialize the object into the json string", e); + } + } + return typedItem; + } + + static List getFromV2Results(List results) { + return results.stream().map(document -> new CosmosItemProperties(document.toJson())) + .collect(Collectors.toList()); + } + + public T getObject(Class klass) throws IOException { + return (T) mapper.readValue(this.toJson(), klass); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemRequestOptions.java new file mode 100644 index 0000000000000..9d2363e0aae16 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemRequestOptions.java @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +import java.util.List; + +/** + * Encapsulates options that can be specified for a request issued to cosmos Item. + */ +public class CosmosItemRequestOptions { + private ConsistencyLevel consistencyLevel; + private IndexingDirective indexingDirective; + private List preTriggerInclude; + private List postTriggerInclude; + private String sessionToken; + private PartitionKey partitionKey; + private AccessCondition accessCondition; + + /** + * Constructor + */ + public CosmosItemRequestOptions(){ + super(); + } + + /** + * Constructor + * @param partitionKey the partition key + */ + public CosmosItemRequestOptions(Object partitionKey){ + super(); + if (partitionKey instanceof PartitionKey) { + partitionKey((PartitionKey) partitionKey); + } else { + partitionKey(new PartitionKey(partitionKey)); + } + } + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosItemRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + + /** + * Gets the consistency level required for the request. + * + * @return the consistency level. + */ + public ConsistencyLevel consistencyLevel() { + return consistencyLevel; + } + + /** + * Sets the consistency level required for the request. + * + * @param consistencyLevel the consistency level. + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions consistencyLevel(ConsistencyLevel consistencyLevel) { + this.consistencyLevel = consistencyLevel; + return this; + } + + /** + * Gets the indexing directive (index, do not index etc). + * + * @return the indexing directive. + */ + public IndexingDirective indexingDirective() { + return indexingDirective; + } + + /** + * Sets the indexing directive (index, do not index etc). + * + * @param indexingDirective the indexing directive. + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions indexingDirective(IndexingDirective indexingDirective) { + this.indexingDirective = indexingDirective; + return this; + } + + /** + * Gets the triggers to be invoked before the operation. + * + * @return the triggers to be invoked before the operation. + */ + public List preTriggerInclude() { + return preTriggerInclude; + } + + /** + * Sets the triggers to be invoked before the operation. + * + * @param preTriggerInclude the triggers to be invoked before the operation. + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions preTriggerInclude(List preTriggerInclude) { + this.preTriggerInclude = preTriggerInclude; + return this; + } + + /** + * Gets the triggers to be invoked after the operation. + * + * @return the triggers to be invoked after the operation. + */ + public List postTriggerInclude() { + return postTriggerInclude; + } + + /** + * Sets the triggers to be invoked after the operation. + * + * @param postTriggerInclude the triggers to be invoked after the operation. + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions postTriggerInclude(List postTriggerInclude) { + this.postTriggerInclude = postTriggerInclude; + return this; + } + + /** + * Gets the token for use with session consistency. + * + * @return the session token. + */ + public String sessionToken() { + return sessionToken; + } + + /** + * Sets the token for use with session consistency. + * + * @param sessionToken the session token. + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions sessionToken(String sessionToken) { + this.sessionToken = sessionToken; + return this; + } + + /** + * Sets the partition key + * @param partitionKey the partition key + * @return the CosmosItemRequestOptions. + */ + public CosmosItemRequestOptions partitionKey(PartitionKey partitionKey) { + this.partitionKey = partitionKey; + return this; + } + + /** + * Gets the partition key + * @return the partition key + */ + public PartitionKey partitionKey() { + return partitionKey; + } + + RequestOptions toRequestOptions() { + //TODO: Should we set any default values instead of nulls? + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setAccessCondition(accessCondition); + requestOptions.setAccessCondition(accessCondition()); + requestOptions.setConsistencyLevel(consistencyLevel()); + requestOptions.setIndexingDirective(indexingDirective); + requestOptions.setPreTriggerInclude(preTriggerInclude); + requestOptions.setPostTriggerInclude(postTriggerInclude); + requestOptions.setSessionToken(sessionToken); + requestOptions.setPartitionKey(partitionKey); + return requestOptions; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemResponse.java new file mode 100644 index 0000000000000..f25d0d2361789 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosItemResponse.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.ResourceResponse; + +public class CosmosItemResponse extends CosmosResponse{ + private CosmosItem itemClient; + + CosmosItemResponse(ResourceResponse response, PartitionKey partitionKey, CosmosContainer container) { + super(response); + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosItemProperties(response.getResource().toJson())); + itemClient = new CosmosItem(response.getResource().id(),partitionKey, container); + } + } + + /** + * Gets the itemSettings + * @return the itemSettings + */ + public CosmosItemProperties properties() { + return resourceSettings(); + } + + /** + * Gets the CosmosItem + * @return the cosmos item + */ + public CosmosItem item() { + return itemClient; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermission.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermission.java new file mode 100644 index 0000000000000..590c95cc23b5d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermission.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.RequestOptions; +import reactor.core.publisher.Mono; + +public class CosmosPermission { + + private final CosmosUser cosmosUser; + private String id; + + CosmosPermission(String id, CosmosUser user){ + this.id = id; + this.cosmosUser = user; + } + + /** + * Get the id of the {@link CosmosPermission} + * @return the id of the {@link CosmosPermission} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosPermission} + * @param id the id of the {@link CosmosPermission} + * @return the same {@link CosmosPermission} that had the id set + */ + CosmosPermission id(String id) { + this.id = id; + return this; + } + + /** + * Reads a permission. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the read permission. + * In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the read permission or an error. + */ + public Mono read(RequestOptions options) { + + return cosmosUser.getDatabase() + .getDocClientWrapper() + .readPermission(getLink(),options) + .map(response -> new CosmosPermissionResponse(response, cosmosUser)) + .single(); + } + + /** + * Replaces a permission. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the replaced permission. + * In case of failure the {@link Mono} will error. + * + * @param permissionSettings the permission properties to use. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the replaced permission or an error. + */ + public Mono replace(CosmosPermissionProperties permissionSettings, RequestOptions options) { + + return cosmosUser.getDatabase() + .getDocClientWrapper() + .replacePermission(permissionSettings.getV2Permissions(), options) + .map(response -> new CosmosPermissionResponse(response, cosmosUser)) + .single(); + } + + /** + * Deletes a permission. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the deleted permission. + * In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single resource response for the deleted permission or an error. + */ + public Mono delete(CosmosPermissionRequestOptions options) { + if(options == null){ + options = new CosmosPermissionRequestOptions(); + } + return cosmosUser.getDatabase() + .getDocClientWrapper() + .deletePermission(getLink(), options.toRequestOptions()) + .map(response -> new CosmosPermissionResponse(response, cosmosUser)) + .single(); + } + + String URIPathSegment() { + return Paths.PERMISSIONS_PATH_SEGMENT; + } + + String parentLink() { + return cosmosUser.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionProperties.java new file mode 100644 index 0000000000000..dce8f70a96799 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionProperties.java @@ -0,0 +1,138 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.Permission; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosPermissionProperties extends Resource { + + public static List getFromV2Results(List results) { + return results.stream().map(permission -> new CosmosPermissionProperties(permission.toJson())).collect(Collectors.toList()); + } + + /** + * Initialize a permission object. + */ + public CosmosPermissionProperties() { + super(); + } + + /** + * Sets the id + * + * @param id the name of the resource. + * @return the current {@link CosmosPermissionProperties} object + */ + public CosmosPermissionProperties id(String id) { + super.id(id); + return this; + } + + /** + * Initialize a permission object from json string. + * + * @param jsonString the json string that represents the permission. + */ + CosmosPermissionProperties(String jsonString) { + super(jsonString); + } + + /** + * Gets the self-link of resource to which the permission applies. + * + * @return the resource link. + */ + public String resourceLink() { + return super.getString(Constants.Properties.RESOURCE_LINK); + } + + /** + * Sets the self-link of resource to which the permission applies. + * + * @param resourceLink the resource link. + * @return the current {@link CosmosPermissionProperties} object + */ + public CosmosPermissionProperties resourceLink(String resourceLink) { + super.set(Constants.Properties.RESOURCE_LINK, resourceLink); + return this; + } + + /** + * Gets the permission mode. + * + * @return the permission mode. + */ + public PermissionMode permissionMode() { + String value = super.getString(Constants.Properties.PERMISSION_MODE); + return PermissionMode.valueOf(StringUtils.upperCase(value)); + } + + /** + * Sets the permission mode. + * + * @param permissionMode the permission mode. + * @return the current {@link CosmosPermissionProperties} object + */ + public CosmosPermissionProperties permissionMode(PermissionMode permissionMode) { + this.set(Constants.Properties.PERMISSION_MODE, + permissionMode.toString().toLowerCase()); + return this; + } + + //TODO: need value from JsonSerializable +// /** +// * Gets the resource partition key associated with this permission object. +// * +// * @return the partition key. +// */ +// public PartitionKey getResourcePartitionKey() { +// PartitionKey key = null; +// Object value = super.get(Constants.Properties.RESOURCE_PARTITION_KEY); +// if (value != null) { +// ArrayNode arrayValue = (ArrayNode) value; +// key = new PartitionKey(value(arrayValue.get(0))); +// } +// +// return key; +// } + + /** + * Sets the resource partition key associated with this permission object. + * + * @param partitionKey the partition key. + * @return the current {@link CosmosPermissionProperties} object + */ + public CosmosPermissionProperties resourcePartitionKey(PartitionKey partitionKey) { + super.set(Constants.Properties.RESOURCE_PARTITION_KEY, partitionKey.getInternalPartitionKey().toJson()); + return this; + } + + Permission getV2Permissions() { + return new Permission(this.toJson()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionRequestOptions.java new file mode 100644 index 0000000000000..d3cb39f886523 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionRequestOptions.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +/** + * Contains the request options of CosmosPermission + */ +public class CosmosPermissionRequestOptions { + //TODO: Need to add respective options + private AccessCondition accessCondition; + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosPermissionRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + + RequestOptions toRequestOptions() { + //TODO: Should we set any default values instead of nulls? + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setAccessCondition(accessCondition); + return requestOptions; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionResponse.java new file mode 100644 index 0000000000000..8227ac9419c10 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosPermissionResponse.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Permission; +import com.azure.data.cosmos.internal.ResourceResponse; + +public class CosmosPermissionResponse extends CosmosResponse { + CosmosPermission permissionClient; + + CosmosPermissionResponse(ResourceResponse response, CosmosUser cosmosUser) { + super(response); + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosPermissionProperties(response.getResource().toJson())); + permissionClient = new CosmosPermission(response.getResource().id(), cosmosUser); + } + } + + /** + * Get the permission properties + * + * @return the permission properties + */ + public CosmosPermissionProperties properties() { + return super.resourceSettings(); + } + + /** + * Gets the CosmosPermission + * + * @return the cosmos permission + */ + public CosmosPermission permission() { + return permissionClient; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResourceType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResourceType.java new file mode 100644 index 0000000000000..dce4aa8475c12 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResourceType.java @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Resource types in the Azure Cosmos DB database service. + */ +public enum CosmosResourceType { + + System(-100), + Attachment(3), + DocumentCollection(1), + Conflict(107), + Database(0), + Document(2), + Index(104), + Offer(113), + Permission(5), + StoredProcedure(109), + Trigger(110), + User(4), + UserDefinedFunction(111); + + final private int value; + + CosmosResourceType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponse.java new file mode 100644 index 0000000000000..fe227d5bd771b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponse.java @@ -0,0 +1,137 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.StoredProcedureResponse; + +import java.time.Duration; +import java.util.Map; + +public class CosmosResponse { + private T resourceSettings; + ResourceResponse resourceResponseWrapper; + + CosmosResponse(ResourceResponse resourceResponse){ + this.resourceResponseWrapper = resourceResponse; + } + + CosmosResponse(T resourceSettings){ + this.resourceSettings = resourceSettings; + } + + // Only used in CosmosStoredProcedureResponse compatibility with StoredProcedureResponse + CosmosResponse(StoredProcedureResponse response) { + } + + T resourceSettings() { + return resourceSettings; + } + + CosmosResponse resourceSettings(T resourceSettings){ + this.resourceSettings = resourceSettings; + return this; + } + + /** + * Gets the maximum size limit for this entity (in megabytes (MB) for server resources and in count for master + * resources). + * + * @return the max resource quota. + */ + public String maxResourceQuota() { + return resourceResponseWrapper.getMaxResourceQuota(); + } + + /** + * Gets the current size of this entity (in megabytes (MB) for server resources and in count for master resources) + * + * @return the current resource quota usage. + */ + public String currentResourceQuotaUsage() { + return resourceResponseWrapper.getCurrentResourceQuotaUsage(); + } + + /** + * Gets the Activity ID for the request. + * + * @return the activity id. + */ + public String activityId() { + return resourceResponseWrapper.getActivityId(); + } + + /** + * Gets the number of index paths (terms) generated by the operation. + * + * @return the request charge. + */ + public double requestCharge() { + return resourceResponseWrapper.getRequestCharge(); + } + + /** + * Gets the HTTP status code associated with the response. + * + * @return the status code. + */ + public int statusCode() { + return resourceResponseWrapper.getStatusCode(); + } + + /** + * Gets the token used for managing client's consistency requirements. + * + * @return the session token. + */ + public String sessionToken(){ + return resourceResponseWrapper.getSessionToken(); + } + + /** + * Gets the headers associated with the response. + * + * @return the response headers. + */ + public Map responseHeaders() { + return resourceResponseWrapper.getResponseHeaders(); + } + + /** + * Gets the diagnostics information for the current request to Azure Cosmos DB service. + * + * @return diagnostics information for the current request to Azure Cosmos DB service. + */ + public CosmosResponseDiagnostics cosmosResponseDiagnosticsString() { + return resourceResponseWrapper.getCosmosResponseDiagnostics(); + } + + /** + * Gets the end-to-end request latency for the current request to Azure Cosmos DB service. + * + * @return end-to-end request latency for the current request to Azure Cosmos DB service. + */ + public Duration requestLatency() { + return resourceResponseWrapper.getRequestLatency(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponseDiagnostics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponseDiagnostics.java new file mode 100644 index 0000000000000..3346298fba3a0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosResponseDiagnostics.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import java.time.Duration; + +/** + * This class represents response diagnostic statistics associated with a request to Azure Cosmos DB + */ +public class CosmosResponseDiagnostics { + + private ClientSideRequestStatistics clientSideRequestStatistics; + + CosmosResponseDiagnostics() { + this.clientSideRequestStatistics = new ClientSideRequestStatistics(); + } + + ClientSideRequestStatistics clientSideRequestStatistics() { + return clientSideRequestStatistics; + } + + CosmosResponseDiagnostics clientSideRequestStatistics(ClientSideRequestStatistics clientSideRequestStatistics) { + this.clientSideRequestStatistics = clientSideRequestStatistics; + return this; + } + + /** + * Retrieves Response Diagnostic String + * @return Response Diagnostic String + */ + @Override + public String toString() { + return this.clientSideRequestStatistics.toString(); + } + + /** + * Retrieves latency related to the completion of the request + * @return request completion latency + */ + public Duration requestLatency() { + return this.clientSideRequestStatistics.getRequestLatency(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosScripts.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosScripts.java new file mode 100644 index 0000000000000..3891d36e843da --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosScripts.java @@ -0,0 +1,310 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.internal.Trigger; +import com.azure.data.cosmos.internal.UserDefinedFunction; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class CosmosScripts { + private final CosmosContainer container; + private final CosmosDatabase database; + + CosmosScripts(CosmosContainer container) { + this.container = container; + this.database = container.getDatabase(); + } + /* CosmosStoredProcedure operations */ + + /** + * Creates a cosmos stored procedure. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos stored procedure response with the + * created cosmos stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param properties the cosmos stored procedure properties. + * @return an {@link Mono} containing the single cosmos stored procedure resource response or an error. + */ + public Mono createStoredProcedure(CosmosStoredProcedureProperties properties){ + return this.createStoredProcedure(properties, new CosmosStoredProcedureRequestOptions()); + } + + /** + * Creates a cosmos stored procedure. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos stored procedure response with the + * created cosmos stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param properties the cosmos stored procedure properties. + * @param options the stored procedure request options. + * @return an {@link Mono} containing the single cosmos stored procedure resource response or an error. + */ + public Mono createStoredProcedure(CosmosStoredProcedureProperties properties, + CosmosStoredProcedureRequestOptions options){ + if(options == null){ + options = new CosmosStoredProcedureRequestOptions(); + } + StoredProcedure sProc = new StoredProcedure(); + sProc.id(properties.id()); + sProc.setBody(properties.body()); + return database.getDocClientWrapper() + .createStoredProcedure(container.getLink(), sProc, options.toRequestOptions()) + .map(response -> new CosmosStoredProcedureResponse(response, this.container)) + .single(); + } + + /** + * Reads all cosmos stored procedures in a container. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read cosmos stored procedure properties. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read cosmos stored procedures + * properties or an error. + */ + public Flux> readAllStoredProcedures(FeedOptions options){ + return database.getDocClientWrapper() + .readStoredProcedures(container.getLink(), options) + .map(response -> BridgeInternal.createFeedResponse(CosmosStoredProcedureProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Query for stored procedures in a container. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained stored procedures. + * In case of failure the {@link Flux} will error. + * + * @param query the the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained stored procedures or + * an error. + */ + public Flux> queryStoredProcedures(String query, + FeedOptions options){ + return queryStoredProcedures(new SqlQuerySpec(query), options); + } + + /** + * Query for stored procedures in a container. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained stored procedures. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained stored procedures or + * an error. + */ + public Flux> queryStoredProcedures(SqlQuerySpec querySpec, + FeedOptions options){ + return database.getDocClientWrapper() + .queryStoredProcedures(container.getLink(), querySpec,options) + .map(response -> BridgeInternal.createFeedResponse( CosmosStoredProcedureProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Gets a CosmosStoredProcedure object without making a service call + * @param id id of the stored procedure + * @return a cosmos stored procedure + */ + public CosmosStoredProcedure getStoredProcedure(String id){ + return new CosmosStoredProcedure(id, this.container); + } + + + /* UDF Operations */ + + /** + * Creates a cosmos user defined function. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos user defined function response. + * In case of failure the {@link Mono} will error. + * + * @param properties the cosmos user defined function properties + * @return an {@link Mono} containing the single resource response with the created user defined function or an error. + */ + public Mono createUserDefinedFunction(CosmosUserDefinedFunctionProperties properties){ + UserDefinedFunction udf = new UserDefinedFunction(); + udf.id(properties.id()); + udf.setBody(properties.body()); + + return database.getDocClientWrapper() + .createUserDefinedFunction(container.getLink(), udf, null) + .map(response -> new CosmosUserDefinedFunctionResponse(response, this.container)).single(); + } + + /** + * Reads all cosmos user defined functions in the container + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read user defined functions or an error. + */ + public Flux> readAllUserDefinedFunctions(FeedOptions options){ + return database.getDocClientWrapper() + .readUserDefinedFunctions(container.getLink(), options) + .map(response -> BridgeInternal.createFeedResponse(CosmosUserDefinedFunctionProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Query for user defined functions in the container. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained user defined functions or an error. + */ + public Flux> queryUserDefinedFunctions(String query, + FeedOptions options){ + return queryUserDefinedFunctions(new SqlQuerySpec(query), options); + } + + /** + * Query for user defined functions in the container. + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained user defined functions or an error. + */ + public Flux> queryUserDefinedFunctions(SqlQuerySpec querySpec, + FeedOptions options){ + return database.getDocClientWrapper() + .queryUserDefinedFunctions(container.getLink(),querySpec, options) + .map(response -> BridgeInternal.createFeedResponse(CosmosUserDefinedFunctionProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Gets a CosmosUserDefinedFunction object without making a service call + * @param id id of the user defined function + * @return a cosmos user defined function + */ + public CosmosUserDefinedFunction getUserDefinedFunction(String id){ + return new CosmosUserDefinedFunction(id, this.container); + } + + /* Trigger Operations */ + /** + * Creates a Cosmos trigger. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a cosmos trigger response + * In case of failure the {@link Mono} will error. + * + * @param properties the cosmos trigger properties + * @return an {@link Mono} containing the single resource response with the created trigger or an error. + */ + public Mono createTrigger(CosmosTriggerProperties properties){ + Trigger trigger = new Trigger(properties.toJson()); + + return database.getDocClientWrapper() + .createTrigger(container.getLink(), trigger, null) + .map(response -> new CosmosTriggerResponse(response, this.container)) + .single(); + } + + /** + * Reads all triggers in a container + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read cosmos trigger properties. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read cosmos rigger properties or an error. + */ + public Flux> readAllTriggers(FeedOptions options){ + return database.getDocClientWrapper() + .readTriggers(container.getLink(), options) + .map(response -> BridgeInternal.createFeedResponse(CosmosTriggerProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Query for triggers in the container + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained triggers. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained triggers or an error. + */ + public Flux> queryTriggers(String query, FeedOptions options){ + return queryTriggers(new SqlQuerySpec(query), options); + } + + /** + * Query for triggers in the container + * + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained triggers. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained triggers or an error. + */ + public Flux> queryTriggers(SqlQuerySpec querySpec, + FeedOptions options){ + return database.getDocClientWrapper() + .queryTriggers(container.getLink(), querySpec, options) + .map(response -> BridgeInternal.createFeedResponse(CosmosTriggerProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Gets a CosmosTrigger object without making a service call + * @param id id of the cosmos trigger + * @return a cosmos trigger + */ + public CosmosTrigger getTrigger(String id){ + return new CosmosTrigger(id, this.container); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedure.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedure.java new file mode 100644 index 0000000000000..14a11f121eb32 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedure.java @@ -0,0 +1,200 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.StoredProcedure; +import reactor.core.publisher.Mono; + +public class CosmosStoredProcedure { + + private CosmosContainer cosmosContainer; + private String id; + + CosmosStoredProcedure(String id, CosmosContainer cosmosContainer) { + this.id = id; + this.cosmosContainer = cosmosContainer; + } + + /** + * Get the id of the {@link CosmosStoredProcedure} + * @return the id of the {@link CosmosStoredProcedure} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosStoredProcedure} + * @param id the id of the {@link CosmosStoredProcedure} + * @return the same {@link CosmosStoredProcedure} that had the id set + */ + CosmosStoredProcedure id(String id) { + this.id = id; + return this; + } + + /** + * Read a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the read stored + * procedure. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response with the read stored procedure or an error. + */ + public Mono read() { + return read(null); + } + + /** + * Read a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the read stored + * procedure. + * In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the read stored procedure or an error. + */ + public Mono read(CosmosStoredProcedureRequestOptions options) { + if(options == null) { + options = new CosmosStoredProcedureRequestOptions(); + } + return cosmosContainer.getDatabase().getDocClientWrapper().readStoredProcedure(getLink(), options.toRequestOptions()) + .map(response -> new CosmosStoredProcedureResponse(response, cosmosContainer)).single(); + } + + /** + * Deletes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the deleted stored procedure. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response for the deleted stored procedure or an error. + */ + public Mono delete() { + return delete(null); + } + + /** + * Deletes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the deleted stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param options the request options. + * @return an {@link Mono} containing the single resource response for the deleted stored procedure or an error. + */ + public Mono delete(CosmosStoredProcedureRequestOptions options) { + if(options == null) { + options = new CosmosStoredProcedureRequestOptions(); + } + return cosmosContainer.getDatabase() + .getDocClientWrapper() + .deleteStoredProcedure(getLink(), options.toRequestOptions()) + .map(response -> new CosmosResponse(response.getResource())) + .single(); + } + + /** + * Executes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the stored procedure response. + * In case of failure the {@link Mono} will error. + * + * @param procedureParams the array of procedure parameter values. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the stored procedure response or an error. + */ + public Mono execute(Object[] procedureParams, CosmosStoredProcedureRequestOptions options) { + if(options == null) { + options = new CosmosStoredProcedureRequestOptions(); + } + return cosmosContainer.getDatabase() + .getDocClientWrapper() + .executeStoredProcedure(getLink(), options.toRequestOptions(), procedureParams) + .map(response -> new CosmosStoredProcedureResponse(response, cosmosContainer)) + .single(); + } + + /** + * Replaces a stored procedure. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the replaced stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param storedProcedureSettings the stored procedure properties + * @return an {@link Mono} containing the single resource response with the replaced stored procedure or an error. + */ + public Mono replace(CosmosStoredProcedureProperties storedProcedureSettings) { + return replace(storedProcedureSettings, null); + } + + /** + * Replaces a stored procedure. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the replaced stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param storedProcedureSettings the stored procedure properties. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the replaced stored procedure or an error. + */ + public Mono replace(CosmosStoredProcedureProperties storedProcedureSettings, + CosmosStoredProcedureRequestOptions options) { + if(options == null) { + options = new CosmosStoredProcedureRequestOptions(); + } + return cosmosContainer.getDatabase() + .getDocClientWrapper() + .replaceStoredProcedure(new StoredProcedure(storedProcedureSettings.toJson()), options.toRequestOptions()) + .map(response -> new CosmosStoredProcedureResponse(response, cosmosContainer)) + .single(); + } + + String URIPathSegment() { + return Paths.STORED_PROCEDURES_PATH_SEGMENT; + } + + String parentLink() { + return cosmosContainer.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureProperties.java new file mode 100644 index 0000000000000..609216373e4fd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureProperties.java @@ -0,0 +1,99 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.StoredProcedure; + +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosStoredProcedureProperties extends Resource { + + /** + * Constructor. + * + */ + public CosmosStoredProcedureProperties() { + super(); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return return the Cosmos stored procedure properties with id set + */ + public CosmosStoredProcedureProperties id(String id){ + super.id(id); + return this; + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the stored procedure. + */ + CosmosStoredProcedureProperties(String jsonString) { + super(jsonString); + } + + /** + * Constructor. + * + * @param id the id of the stored procedure + * @param body the body of the stored procedure + */ + public CosmosStoredProcedureProperties(String id, String body) { + super(); + super.id(id); + this.body(body); + } + + CosmosStoredProcedureProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + /** + * Get the body of the stored procedure. + * + * @return the body of the stored procedure. + */ + public String body() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the stored procedure. + * + * @param body the body of the stored procedure. + */ + public void body(String body) { + super.set(Constants.Properties.BODY, body); + } + + + static List getFromV2Results(List results) { + return results.stream().map(sproc -> new CosmosStoredProcedureProperties(sproc.toJson())).collect(Collectors.toList()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureRequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureRequestOptions.java new file mode 100644 index 0000000000000..8cd9d08689788 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureRequestOptions.java @@ -0,0 +1,123 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RequestOptions; + +/** + * Encapsulates options that can be specified for a request issued to cosmos stored procedure. + */ +public class CosmosStoredProcedureRequestOptions { + private ConsistencyLevel consistencyLevel; + private PartitionKey partitionKey; + private String sessionToken; + private AccessCondition accessCondition; + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition accessCondition() { + return accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + * @return the current request options + */ + public CosmosStoredProcedureRequestOptions accessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + return this; + } + /** + * Gets the consistency level required for the request. + * + * @return the consistency level. + */ + public ConsistencyLevel consistencyLevel() { + return consistencyLevel; + } + + /** + * Sets the consistency level required for the request. + * + * @param consistencyLevel the consistency level. + * @return the CosmosStoredProcedureRequestOptions. + */ + public CosmosStoredProcedureRequestOptions consistencyLevel(ConsistencyLevel consistencyLevel) { + this.consistencyLevel = consistencyLevel; + return this; + } + + /** + * Gets the partition key used to identify the current request's target partition. + * + * @return the partition key value. + */ + public PartitionKey partitionKey() { + return partitionKey; + } + + /** + * Sets the partition key used to identify the current request's target partition. + * + * @param partitionKey the partition key value. + * @return the CosmosStoredProcedureRequestOptions. + */ + public CosmosStoredProcedureRequestOptions partitionKey(PartitionKey partitionKey) { + this.partitionKey = partitionKey; + return this; + } + + /** + * Gets the token for use with session consistency. + * + * @return the session token. + */ + public String sessionToken() { + return sessionToken; + } + + /** + * Sets the token for use with session consistency. + * + * @param sessionToken the session token. + * @return the CosmosStoredProcedureRequestOptions. + */ + public CosmosStoredProcedureRequestOptions sessionToken(String sessionToken) { + this.sessionToken = sessionToken; + return this; + } + + RequestOptions toRequestOptions() { + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setAccessCondition(accessCondition); + requestOptions.setConsistencyLevel(consistencyLevel()); + requestOptions.setPartitionKey(partitionKey); + requestOptions.setSessionToken(sessionToken); + return requestOptions; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureResponse.java new file mode 100644 index 0000000000000..6e208cac567cd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosStoredProcedureResponse.java @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.internal.StoredProcedureResponse; + +public class CosmosStoredProcedureResponse extends CosmosResponse { + + private CosmosStoredProcedure storedProcedure; + private StoredProcedureResponse storedProcedureResponse; + + CosmosStoredProcedureResponse(ResourceResponse response, CosmosContainer cosmosContainer) { + super(response); + if(response.getResource() != null){ + super.resourceSettings(new CosmosStoredProcedureProperties(response)); + storedProcedure = new CosmosStoredProcedure(resourceSettings().id(), cosmosContainer); + } + } + + CosmosStoredProcedureResponse(StoredProcedureResponse response, CosmosContainer cosmosContainer) { + super(response); + this.storedProcedureResponse = response; + } + + /** + * Gets the stored procedure properties + * @return the stored procedure properties or null + */ + public CosmosStoredProcedureProperties properties() { + return super.resourceSettings(); + } + + /** + * Gets the stored procedure object + * @return the stored procedure object or null + */ + public CosmosStoredProcedure storedProcedure() { + return this.storedProcedure; + } + + /** + * Gets the Activity ID for the request. + * + * @return the activity id. + */ + @Override + public String activityId() { + if(storedProcedureResponse != null){ + return this.storedProcedureResponse.getActivityId(); + } + return super.activityId(); + } + + /** + * Gets the token used for managing client's consistency requirements. + * + * @return the session token. + */ + @Override + public String sessionToken() { + if(storedProcedureResponse != null){ + return this.storedProcedureResponse.getSessionToken(); + } + return super.sessionToken(); + } + + /** + * Gets the HTTP status code associated with the response. + * + * @return the status code. + */ + @Override + public int statusCode() { + if(storedProcedureResponse != null){ + return this.storedProcedureResponse.getStatusCode(); + } + return super.statusCode(); + } + + /** + * Gets the number of index paths (terms) generated by the operation. + * + * @return the request charge. + */ + @Override + public double requestCharge() { + if(storedProcedureResponse != null){ + return storedProcedureResponse.getRequestCharge(); + } + return super.requestCharge(); + } + + /** + * Gets the response of the stored procedure as a string. + * + * @return the response as a string. + */ + public String responseAsString() { + return this.storedProcedureResponse.getResponseAsString(); + } + + /** + * Gets the output from stored procedure console.log() statements. + * + * @return the output string from the stored procedure console.log() statements. + */ + public String scriptLog() { + return this.storedProcedureResponse.getScriptLog(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTrigger.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTrigger.java new file mode 100644 index 0000000000000..e0ff10e1b286f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTrigger.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.Trigger; +import reactor.core.publisher.Mono; + +public class CosmosTrigger { + + private CosmosContainer container; + private String id; + + CosmosTrigger(String id, CosmosContainer container) { + this.id = id; + this.container = container; + } + + /** + * Get the id of the {@link CosmosTrigger} + * @return the id of the {@link CosmosTrigger} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosTrigger} + * @param id the id of the {@link CosmosTrigger} + * @return the same {@link CosmosTrigger} that had the id set + */ + CosmosTrigger id(String id) { + this.id = id; + return this; + } + + /** + * Reads a cosmos trigger by the trigger link. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the read trigger. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response for the read cosmos trigger or an error. + */ + public Mono read() { + return container.getDatabase() + .getDocClientWrapper() + .readTrigger(getLink(), null) + .map(response -> new CosmosTriggerResponse(response, container)) + .single(); + } + + + /** + * Replaces a cosmos trigger. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the replaced trigger. + * In case of failure the {@link Mono} will error. + * + * @param triggerSettings the cosmos trigger properties. + * @return an {@link Mono} containing the single resource response with the replaced cosmos trigger or an error. + */ + public Mono replace(CosmosTriggerProperties triggerSettings) { + return container.getDatabase() + .getDocClientWrapper() + .replaceTrigger(new Trigger(triggerSettings.toJson()), null) + .map(response -> new CosmosTriggerResponse(response, container)) + .single(); + } + + /** + * Deletes a cosmos trigger. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the deleted trigger. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response for the deleted cosmos trigger or an error. + */ + public Mono delete() { + return container.getDatabase() + .getDocClientWrapper() + .deleteTrigger(getLink(), null) + .map(response -> new CosmosResponse(response.getResource())) + .single(); + } + + String URIPathSegment() { + return Paths.TRIGGERS_PATH_SEGMENT; + } + + String parentLink() { + return container.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerProperties.java new file mode 100644 index 0000000000000..e221e9faa7fe8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerProperties.java @@ -0,0 +1,145 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.Trigger; +import org.apache.commons.lang3.StringUtils; + +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosTriggerProperties extends Resource { + + /** + * Constructor + */ + public CosmosTriggerProperties(){ + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the trigger properties. + */ + CosmosTriggerProperties(String jsonString){ + super(jsonString); + } + + CosmosTriggerProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + /** + * Sets the id + * + * @param id the name of the resource. + * @return the current cosmos trigger properties instance + */ + public CosmosTriggerProperties id(String id) { + super.id(id); + return this; + } + + /** + * Get the body of the trigger. + * + * @return the body of the trigger. + */ + public String body() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the trigger. + * + * @param body the body of the trigger. + * @return the CosmosTriggerProperties. + */ + public CosmosTriggerProperties body(String body) { + super.set(Constants.Properties.BODY, body); + return this; + } + + /** + * Get the type of the trigger. + * + * @return the trigger type. + */ + public TriggerType triggerType() { + TriggerType result = TriggerType.PRE; + try { + result = TriggerType.valueOf( + StringUtils.upperCase(super.getString(Constants.Properties.TRIGGER_TYPE))); + } catch (IllegalArgumentException e) { + // ignore the exception and return the default + this.getLogger().warn("INVALID triggerType value {}.", super.getString(Constants.Properties.TRIGGER_TYPE)); + } + return result; + } + + /** + * Set the type of the resource. + * + * @param triggerType the trigger type. + * @return the CosmosTriggerProperties. + */ + public CosmosTriggerProperties triggerType(TriggerType triggerType) { + super.set(Constants.Properties.TRIGGER_TYPE, triggerType.toString()); + return this; + } + + /** + * Get the operation type of the trigger. + * + * @return the trigger operation. + */ + public TriggerOperation triggerOperation() { + TriggerOperation result = TriggerOperation.CREATE; + try { + result = TriggerOperation.valueOf( + StringUtils.upperCase(super.getString(Constants.Properties.TRIGGER_OPERATION))); + } catch (IllegalArgumentException e) { + // ignore the exception and return the default + this.getLogger().warn("INVALID triggerOperation value {}.", super.getString(Constants.Properties.TRIGGER_OPERATION)); + } + return result; + } + + /** + * Set the operation type of the trigger. + * + * @param triggerOperation the trigger operation. + * @return the CosmosTriggerProperties. + */ + public CosmosTriggerProperties triggerOperation(TriggerOperation triggerOperation) { + super.set(Constants.Properties.TRIGGER_OPERATION, triggerOperation.toString()); + return this; + } + + static List getFromV2Results(List results) { + return results.stream().map(trigger -> new CosmosTriggerProperties(trigger.toJson())).collect(Collectors.toList()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerResponse.java new file mode 100644 index 0000000000000..4cf3d4b12782f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosTriggerResponse.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.Trigger; + +public class CosmosTriggerResponse extends CosmosResponse { + + private CosmosTriggerProperties cosmosTriggerProperties; + private CosmosTrigger cosmosTrigger; + + CosmosTriggerResponse(ResourceResponse response, CosmosContainer container) { + super(response); + if(response.getResource() != null) { + super.resourceSettings(new CosmosTriggerProperties(response)); + cosmosTriggerProperties = new CosmosTriggerProperties(response); + cosmosTrigger = new CosmosTrigger(cosmosTriggerProperties.id(), container); + } + } + + /** + * Gets the cosmos trigger properties or null + * + * @return {@link CosmosTriggerProperties} + */ + public CosmosTriggerProperties properties() { + return cosmosTriggerProperties; + } + + /** + * Gets the cosmos trigger object or null + * + * @return {@link CosmosTrigger} + */ + public CosmosTrigger trigger() { + return cosmosTrigger; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUser.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUser.java new file mode 100644 index 0000000000000..08c61dae6150a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUser.java @@ -0,0 +1,197 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.Permission; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class CosmosUser { + CosmosDatabase database; + private String id; + + CosmosUser(String id, CosmosDatabase database) { + this.id = id; + this.database = database; + } + + /** + * Get the id of the {@link CosmosUser} + * @return the id of the {@link CosmosUser} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosUser} + * @param id the id of the {@link CosmosUser} + * @return the same {@link CosmosUser} that had the id set + */ + CosmosUser id(String id) { + this.id = id; + return this; + } + + /** + * Reads a cosmos user + * @return a {@link Mono} containing the single resource response with the read user or an error. + */ + public Mono read() { + return this.database.getDocClientWrapper() + .readUser(getLink(), null) + .map(response -> new CosmosUserResponse(response, database)).single(); + } + + /** + * REPLACE a cosmos user + * + * @param userSettings the user properties to use + * @return a {@link Mono} containing the single resource response with the replaced user or an error. + */ + public Mono replace(CosmosUserProperties userSettings) { + return this.database.getDocClientWrapper() + .replaceUser(userSettings.getV2User(), null) + .map(response -> new CosmosUserResponse(response, database)).single(); + } + + /** + * Delete a cosmos user + * + * @return a {@link Mono} containing the single resource response with the deleted user or an error. + */ + public Mono delete() { + return this.database.getDocClientWrapper() + .deleteUser(getLink(), null) + .map(response -> new CosmosUserResponse(response, database)).single(); + } + + /** + * Creates a permission. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the created permission. + * In case of failure the {@link Mono} will error. + * + * @param permissionSettings the permission properties to create. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the created permission or an error. + */ + public Mono createPermission(CosmosPermissionProperties permissionSettings, CosmosPermissionRequestOptions options) { + if(options == null){ + options = new CosmosPermissionRequestOptions(); + } + Permission permission = permissionSettings.getV2Permissions(); + return database.getDocClientWrapper() + .createPermission(getLink(), permission, options.toRequestOptions()) + .map(response -> new CosmosPermissionResponse(response, this)) + .single(); + } + + /** + * Upserts a permission. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the upserted permission. + * In case of failure the {@link Mono} will error. + * + * @param permissionSettings the permission properties to upsert. + * @param options the request options. + * @return an {@link Mono} containing the single resource response with the upserted permission or an error. + */ + public Mono upsertPermission(CosmosPermissionProperties permissionSettings, CosmosPermissionRequestOptions options) { + Permission permission = permissionSettings.getV2Permissions(); + if(options == null){ + options = new CosmosPermissionRequestOptions(); + } + return database.getDocClientWrapper() + .upsertPermission(getLink(), permission, options.toRequestOptions()) + .map(response -> new CosmosPermissionResponse(response, this)) + .single(); + } + + + /** + * Reads all permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read permissions. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read permissions or an error. + */ + public Flux> readAllPermissions(FeedOptions options) { + return getDatabase().getDocClientWrapper() + .readPermissions(getLink(), options) + .map(response-> BridgeInternal.createFeedResponse(CosmosPermissionProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Query for permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained permissions. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @return an {@link Flux} containing one or several feed response pages of the obtained permissions or an error. + */ + public Flux> queryPermissions(String query) { + return queryPermissions(query); + } + + /** + * Query for permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained permissions. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained permissions or an error. + */ + public Flux> queryPermissions(String query, FeedOptions options) { + return getDatabase().getDocClientWrapper() + .queryPermissions(getLink(), query, options) + .map(response-> BridgeInternal.createFeedResponse(CosmosPermissionProperties.getFromV2Results(response.results()), + response.responseHeaders())); + } + + /** + * Get cosmos permission without making a call to backend + * @param id the id + * @return the cosmos permission + */ + public CosmosPermission getPermission(String id){ + return new CosmosPermission(id, this); + } + + String URIPathSegment() { + return Paths.USERS_PATH_SEGMENT; + } + + String parentLink() { + return database.getLink() ; + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } + + /** + * Gets the parent Database + * + * @return the (@link CosmosDatabase) + */ + public CosmosDatabase getDatabase() { + return database; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunction.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunction.java new file mode 100644 index 0000000000000..3229de163ca60 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunction.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.UserDefinedFunction; +import reactor.core.publisher.Mono; + +public class CosmosUserDefinedFunction { + + private CosmosContainer container; + private String id; + + CosmosUserDefinedFunction(String id, CosmosContainer container) { + this.id = id; + this.container = container; + } + + /** + * Get the id of the {@link CosmosUserDefinedFunction} + * @return the id of the {@link CosmosUserDefinedFunction} + */ + public String id() { + return id; + } + + /** + * Set the id of the {@link CosmosUserDefinedFunction} + * @param id the id of the {@link CosmosUserDefinedFunction} + * @return the same {@link CosmosUserDefinedFunction} that had the id set + */ + CosmosUserDefinedFunction id(String id) { + this.id = id; + return this; + } + + /** + * Read a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the read user defined + * function. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response for the read user defined function or an error. + */ + public Mono read() { + return container.getDatabase().getDocClientWrapper().readUserDefinedFunction(getLink(), null) + .map(response -> new CosmosUserDefinedFunctionResponse(response, container)).single(); + } + + /** + * Replaces a cosmos user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the replaced user + * defined function. + * In case of failure the {@link Mono} will error. + * + * @param udfSettings the cosmos user defined function properties. + * @return an {@link Mono} containing the single resource response with the replaced cosmos user defined function + * or an error. + */ + public Mono replace(CosmosUserDefinedFunctionProperties udfSettings) { + return container.getDatabase() + .getDocClientWrapper() + .replaceUserDefinedFunction(new UserDefinedFunction(udfSettings.toJson()) + , null) + .map(response -> new CosmosUserDefinedFunctionResponse(response, container)) + .single(); + } + + /** + * Deletes a cosmos user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response for the deleted user defined function. + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the single resource response for the deleted cosmos user defined function or + * an error. + */ + public Mono delete() { + return container.getDatabase() + .getDocClientWrapper() + .deleteUserDefinedFunction(this.getLink(), null) + .map(response -> new CosmosResponse(response.getResource())) + .single(); + } + + String URIPathSegment() { + return Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT; + } + + String parentLink() { + return container.getLink(); + } + + String getLink() { + StringBuilder builder = new StringBuilder(); + builder.append(parentLink()); + builder.append("/"); + builder.append(URIPathSegment()); + builder.append("/"); + builder.append(id()); + return builder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionProperties.java new file mode 100644 index 0000000000000..9296a0b59f007 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionProperties.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.UserDefinedFunction; + +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosUserDefinedFunctionProperties extends Resource { + + /** + * Constructor + */ + public CosmosUserDefinedFunctionProperties(){ + super(); + } + + CosmosUserDefinedFunctionProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the cosmos user defined function properties. + */ + CosmosUserDefinedFunctionProperties(String jsonString) { + super(jsonString); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of cosmos user defined function properties + */ + public CosmosUserDefinedFunctionProperties id(String id) { + super.id(id); + return this; + } + + /** + * Get the body of the user defined function. + * + * @return the body. + */ + public String body() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the user defined function. + * + * @param body the body. + * @return the CosmosUserDefinedFunctionProperties. + */ + public CosmosUserDefinedFunctionProperties body(String body) { + super.set(Constants.Properties.BODY, body); + return this; + } + + static List getFromV2Results(List results) { + return results.stream().map(udf -> new CosmosUserDefinedFunctionProperties(udf.toJson())).collect(Collectors.toList()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionResponse.java new file mode 100644 index 0000000000000..0f3fb1d545c9e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserDefinedFunctionResponse.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.UserDefinedFunction; + +public class CosmosUserDefinedFunctionResponse extends CosmosResponse { + + private CosmosUserDefinedFunctionProperties cosmosUserDefinedFunctionProperties; + private CosmosUserDefinedFunction cosmosUserDefinedFunction; + + CosmosUserDefinedFunctionResponse(ResourceResponse response, CosmosContainer container) { + super(response); + if(response.getResource() != null) { + super.resourceSettings(new CosmosUserDefinedFunctionProperties(response)); + cosmosUserDefinedFunctionProperties = new CosmosUserDefinedFunctionProperties(response); + cosmosUserDefinedFunction = new CosmosUserDefinedFunction(cosmosUserDefinedFunctionProperties.id(), container); + } + } + + /** + * Gets the cosmos user defined function properties + * @return the cosmos user defined function properties + */ + public CosmosUserDefinedFunctionProperties properties() { + return cosmosUserDefinedFunctionProperties; + } + + /** + * Gets the cosmos user defined function object + * @return the cosmos user defined function object + */ + public CosmosUserDefinedFunction userDefinedFunction() { + return cosmosUserDefinedFunction; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserProperties.java new file mode 100644 index 0000000000000..37be2e3a866c7 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserProperties.java @@ -0,0 +1,74 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.User; + +import java.util.List; +import java.util.stream.Collectors; + +public class CosmosUserProperties extends Resource { + /** + * Initialize a user object. + */ + public CosmosUserProperties() { + super(); + } + + /** + * Gets the id + * @return the id of the user + */ + public String id() { + return super.id(); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of cosmos user properties + */ + public CosmosUserProperties id(String id) { + return (CosmosUserProperties) super.id(id); + } + + /** + * Initialize a user object from json string. + * + * @param jsonString the json string that represents the database user. + */ + CosmosUserProperties(String jsonString) { + super(jsonString); + } + + CosmosUserProperties(ResourceResponse response) { + super(response.getResource().toJson()); + } + + // Converting document collection to CosmosContainerProperties + CosmosUserProperties(User user){ + super(user.toJson()); + } + + /** + * Gets the self-link of the permissions associated with the user. + * + * @return the permissions link. + */ + String getPermissionsLink() { + String selfLink = this.selfLink(); + if (selfLink.endsWith("/")) { + return selfLink + super.getString(Constants.Properties.PERMISSIONS_LINK); + } else { + return selfLink + "/" + super.getString(Constants.Properties.PERMISSIONS_LINK); + } + } + + public User getV2User() { + return new User(this.toJson()); + } + + static List getFromV2Results(List results) { + return results.stream().map(CosmosUserProperties::new).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserResponse.java new file mode 100644 index 0000000000000..d566de6dd5b0e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/CosmosUserResponse.java @@ -0,0 +1,36 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.User; + +public class CosmosUserResponse extends CosmosResponse { + private CosmosUser user; + + CosmosUserResponse(ResourceResponse response, CosmosDatabase database) { + super(response); + if(response.getResource() == null){ + super.resourceSettings(null); + }else{ + super.resourceSettings(new CosmosUserProperties(response)); + this.user = new CosmosUser(resourceSettings().id(), database); + } + } + + /** + * Get cosmos user + * + * @return {@link CosmosUser} + */ + public CosmosUser user() { + return user; + } + + /** + * Gets the cosmos user properties + * + * @return {@link CosmosUserProperties} + */ + public CosmosUserProperties properties(){ + return resourceSettings(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/DataType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/DataType.java new file mode 100644 index 0000000000000..d2aed00eb006a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/DataType.java @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.WordUtils; + +/** + * Data types in the Azure Cosmos DB database service. + */ +public enum DataType { + /** + * Represents a numeric data type. + */ + NUMBER, + + /** + * Represents a string data type. + */ + STRING, + + /** + * Represent a point data type. + */ + POINT, + + /** + * Represents a line string data type. + */ + LINE_STRING, + + /** + * Represent a polygon data type. + */ + POLYGON, + + /** + * Represent a multi-polygon data type. + */ + MULTI_POLYGON; + + @Override + public String toString() { + return StringUtils.remove(WordUtils.capitalizeFully(this.name(), '_'), '_'); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ExcludedPath.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ExcludedPath.java new file mode 100644 index 0000000000000..34ddd2bd9265c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ExcludedPath.java @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; + +/** + * Represents an excluded path of the IndexingPolicy in the Azure Cosmos DB database service. + */ +public class ExcludedPath extends JsonSerializable { + + /** + * Constructor. + */ + public ExcludedPath() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the excluded path. + */ + ExcludedPath(String jsonString) { + super(jsonString); + } + + /** + * Gets path. + * + * @return the path. + */ + public String path() { + return super.getString(Constants.Properties.PATH); + } + + /** + * Sets path. + * + * @param path the path. + * @return the Exculded path. + */ + public ExcludedPath path(String path) { + super.set(Constants.Properties.PATH, path); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedOptions.java new file mode 100644 index 0000000000000..56a45b4330d8a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedOptions.java @@ -0,0 +1,361 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import java.util.Map; + +/** + * Specifies the options associated with feed methods (enumeration operations) + * in the Azure Cosmos DB database service. + */ +public final class FeedOptions { + private String sessionToken; + private String partitionKeyRangeId; + private Boolean enableScanInQuery; + private Boolean emitVerboseTracesInQuery; + private Boolean enableCrossPartitionQuery; + private int maxDegreeOfParallelism; + private int maxBufferedItemCount; + private int responseContinuationTokenLimitInKb; + private Integer maxItemCount; + private String requestContinuation; + private PartitionKey partitionkey; + private boolean populateQueryMetrics; + private Map properties; + + public FeedOptions() { + } + + public FeedOptions(FeedOptions options) { + this.sessionToken = options.sessionToken; + this.partitionKeyRangeId = options.partitionKeyRangeId; + this.enableScanInQuery = options.enableScanInQuery; + this.emitVerboseTracesInQuery = options.emitVerboseTracesInQuery; + this.enableCrossPartitionQuery = options.enableCrossPartitionQuery; + this.maxDegreeOfParallelism = options.maxDegreeOfParallelism; + this.maxBufferedItemCount = options.maxBufferedItemCount; + this.responseContinuationTokenLimitInKb = options.responseContinuationTokenLimitInKb; + this.maxItemCount = options.maxItemCount; + this.requestContinuation = options.requestContinuation; + this.partitionkey = options.partitionkey; + this.populateQueryMetrics = options.populateQueryMetrics; + } + + /** + * Gets the partitionKeyRangeId. + * + * @return the partitionKeyRangeId. + */ + String partitionKeyRangeIdInternal() { + return this.partitionKeyRangeId; + } + + /** + * Sets the partitionKeyRangeId. + * + * @param partitionKeyRangeId the partitionKeyRangeId. + * @return the FeedOptions. + */ + FeedOptions partitionKeyRangeIdInternal(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + return this; + } + + /** + * Gets the session token for use with session consistency. + * + * @return the session token. + */ + public String sessionToken() { + return this.sessionToken; + } + + /** + * Sets the session token for use with session consistency. + * + * @param sessionToken the session token. + * @return the FeedOptions. + */ + public FeedOptions sessionToken(String sessionToken) { + this.sessionToken = sessionToken; + return this; + } + + /** + * Gets the option to allow scan on the queries which couldn't be served as + * indexing was opted out on the requested paths. + * + * @return the option of enable scan in query. + */ + public Boolean enableScanInQuery() { + return this.enableScanInQuery; + } + + /** + * Sets the option to allow scan on the queries which couldn't be served as + * indexing was opted out on the requested paths. + * + * @param enableScanInQuery the option of enable scan in query. + * @return the FeedOptions. + */ + public FeedOptions enableScanInQuery(Boolean enableScanInQuery) { + this.enableScanInQuery = enableScanInQuery; + return this; + } + + /** + * Gets the option to allow queries to emit out verbose traces for + * investigation. + * + * @return the emit verbose traces in query. + */ + public Boolean emitVerboseTracesInQuery() { + return this.emitVerboseTracesInQuery; + } + + /** + * Sets the option to allow queries to emit out verbose traces for + * investigation. + * + * @param emitVerboseTracesInQuery the emit verbose traces in query. + * @return the FeedOptions. + */ + public FeedOptions emitVerboseTracesInQuery(Boolean emitVerboseTracesInQuery) { + this.emitVerboseTracesInQuery = emitVerboseTracesInQuery; + return this; + } + + /** + * Gets the option to allow queries to run across all partitions of the + * collection. + * + * @return whether to allow queries to run across all partitions of the + * collection. + */ + public Boolean enableCrossPartitionQuery() { + return this.enableCrossPartitionQuery; + } + + /** + * Sets the option to allow queries to run across all partitions of the + * collection. + * + * @param enableCrossPartitionQuery whether to allow queries to run across all + * partitions of the collection. + * @return the FeedOptions. + */ + public FeedOptions enableCrossPartitionQuery(Boolean enableCrossPartitionQuery) { + this.enableCrossPartitionQuery = enableCrossPartitionQuery; + return this; + } + + /** + * Gets the number of concurrent operations run client side during parallel + * query execution. + * + * @return number of concurrent operations run client side during parallel query + * execution. + */ + public int maxDegreeOfParallelism() { + return maxDegreeOfParallelism; + } + + /** + * Sets the number of concurrent operations run client side during parallel + * query execution. + * + * @param maxDegreeOfParallelism number of concurrent operations. + * @return the FeedOptions. + */ + public FeedOptions maxDegreeOfParallelism(int maxDegreeOfParallelism) { + this.maxDegreeOfParallelism = maxDegreeOfParallelism; + return this; + } + + /** + * Gets the maximum number of items that can be buffered client side during + * parallel query execution. + * + * @return maximum number of items that can be buffered client side during + * parallel query execution. + */ + public int maxBufferedItemCount() { + return maxBufferedItemCount; + } + + /** + * Sets the maximum number of items that can be buffered client side during + * parallel query execution. + * + * @param maxBufferedItemCount maximum number of items. + * @return the FeedOptions. + */ + public FeedOptions maxBufferedItemCount(int maxBufferedItemCount) { + this.maxBufferedItemCount = maxBufferedItemCount; + return this; + } + + /** + * Sets the ResponseContinuationTokenLimitInKb request option for document query + * requests in the Azure Cosmos DB service. + * + * ResponseContinuationTokenLimitInKb is used to limit the length of + * continuation token in the query response. Valid values are >= 1. + * + * The continuation token contains both required and optional fields. The + * required fields are necessary for resuming the execution from where it was + * stooped. The optional fields may contain serialized index lookup work that + * was done but not yet utilized. This avoids redoing the work again in + * subsequent continuations and hence improve the query performance. Setting the + * maximum continuation size to 1KB, the Azure Cosmos DB service will only + * serialize required fields. Starting from 2KB, the Azure Cosmos DB service + * would serialize as much as it could fit till it reaches the maximum specified + * size. + * + * @param limitInKb continuation token size limit. + * @return the FeedOptions. + */ + public FeedOptions responseContinuationTokenLimitInKb(int limitInKb) { + this.responseContinuationTokenLimitInKb = limitInKb; + return this; + } + + /** + * Gets the ResponseContinuationTokenLimitInKb request option for document query + * requests in the Azure Cosmos DB service. If not already set returns 0. + * + * ResponseContinuationTokenLimitInKb is used to limit the length of + * continuation token in the query response. Valid values are >= 1. + * + * @return return set ResponseContinuationTokenLimitInKb, or 0 if not set + */ + public int responseContinuationTokenLimitInKb() { + return responseContinuationTokenLimitInKb; + } + + + /** + * Gets the maximum number of items to be returned in the enumeration + * operation. + * + * @return the max number of items. + */ + public Integer maxItemCount() { + return this.maxItemCount; + } + + /** + * Sets the maximum number of items to be returned in the enumeration + * operation. + * + * @param maxItemCount the max number of items. + * @return the FeedOptionsBase. + */ + public FeedOptions maxItemCount(Integer maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + /** + * Gets the request continuation token. + * + * @return the request continuation. + */ + public String requestContinuation() { + return this.requestContinuation; + } + + /** + * Sets the request continuation token. + * + * @param requestContinuation + * the request continuation. + * @return the FeedOptionsBase. + */ + public FeedOptions requestContinuation(String requestContinuation) { + this.requestContinuation = requestContinuation; + return this; + } + + /** + * Gets the partition key used to identify the current request's target + * partition. + * + * @return the partition key. + */ + public PartitionKey partitionKey() { + return this.partitionkey; + } + + /** + * Sets the partition key used to identify the current request's target + * partition. + * + * @param partitionkey + * the partition key value. + * @return the FeedOptionsBase. + */ + public FeedOptions partitionKey(PartitionKey partitionkey) { + this.partitionkey = partitionkey; + return this; + } + + /** + * Gets the option to enable populate query metrics + * @return whether to enable populate query metrics + */ + public boolean populateQueryMetrics() { + return populateQueryMetrics; + } + + /** + * Sets the option to enable/disable getting metrics relating to query execution on document query requests + * @param populateQueryMetrics whether to enable or disable query metrics + * @return the FeedOptionsBase. + */ + public FeedOptions populateQueryMetrics(boolean populateQueryMetrics) { + this.populateQueryMetrics = populateQueryMetrics; + return this; + } + + /** + * Gets the properties + * + * @return Map of request options properties + */ + public Map properties() { + return properties; + } + + /** + * Sets the properties used to identify the request token. + * + * @param properties the properties. + * @return the FeedOptionsBase. + */ + public FeedOptions properties(Map properties) { + this.properties = properties; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponse.java new file mode 100644 index 0000000000000..ce9d880e2db1c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponse.java @@ -0,0 +1,407 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.QueryMetricsConstants; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +public class FeedResponse { + + private final List results; + private final Map header; + private final HashMap usageHeaders; + private final HashMap quotaHeaders; + private final boolean useEtagAsContinuation; + boolean nochanges; + private final ConcurrentMap queryMetricsMap; + private final String DefaultPartition = "0"; + private final FeedResponseDiagnostics feedResponseDiagnostics; + + FeedResponse(List results, Map headers) { + this(results, headers, false, false, new ConcurrentHashMap<>()); + } + + FeedResponse(List results, Map headers, ConcurrentMap queryMetricsMap) { + this(results, headers, false, false, queryMetricsMap); + } + + FeedResponse(List results, Map header, boolean nochanges) { + this(results, header, true, nochanges, new ConcurrentHashMap<>()); + } + + // TODO: need to more sure the query metrics can round trip just from the headers. + // We can then remove it as a parameter. + private FeedResponse( + List results, + Map header, + boolean useEtagAsContinuation, + boolean nochanges, + ConcurrentMap queryMetricsMap) { + this.results = results; + this.header = header; + this.usageHeaders = new HashMap<>(); + this.quotaHeaders = new HashMap<>(); + this.useEtagAsContinuation = useEtagAsContinuation; + this.nochanges = nochanges; + this.queryMetricsMap = new ConcurrentHashMap<>(queryMetricsMap); + this.feedResponseDiagnostics = new FeedResponseDiagnostics(queryMetricsMap); + } + + /** + * Results. + * + * @return the list of results. + */ + public List results() { + return results; + } + + /** + * Gets the maximum quota for database resources within the account from the Azure Cosmos DB service. + * + * @return The maximum quota for the account. + */ + public long databaseQuota() { + return this.maxQuotaHeader(Constants.Quota.DATABASE); + } + + /** + * Gets the current number of database resources within the account from the Azure Cosmos DB service. + * + * @return The current number of databases. + */ + public long databaseUsage() { + return this.currentQuotaHeader(Constants.Quota.DATABASE); + } + + /** + * Gets the maximum quota for collection resources within an account from the Azure Cosmos DB service. + * + * @return The maximum quota for the account. + */ + public long collectionQuota() { + return this.maxQuotaHeader(Constants.Quota.COLLECTION); + } + + /** + * Gets the current number of collection resources within the account from the Azure Cosmos DB service. + * + * @return The current number of collections. + */ + public long collectionUsage() { + return this.currentQuotaHeader(Constants.Quota.COLLECTION); + } + + /** + * Gets the maximum quota for user resources within an account from the Azure Cosmos DB service. + * + * @return The maximum quota for the account. + */ + public long userQuota() { + return this.maxQuotaHeader(Constants.Quota.USER); + } + + /** + * Gets the current number of user resources within the account from the Azure Cosmos DB service. + * + * @return The current number of users. + */ + public long userUsage() { + return this.currentQuotaHeader(Constants.Quota.USER); + } + + /** + * Gets the maximum quota for permission resources within an account from the Azure Cosmos DB service. + * + * @return The maximum quota for the account. + */ + public long permissionQuota() { + return this.maxQuotaHeader(Constants.Quota.PERMISSION); + } + + /** + * Gets the current number of permission resources within the account from the Azure Cosmos DB service. + * + * @return The current number of permissions. + */ + public long permissionUsage() { + return this.currentQuotaHeader(Constants.Quota.PERMISSION); + } + + /** + * Gets the maximum size of a collection in kilobytes from the Azure Cosmos DB service. + * + * @return The maximum quota in kilobytes. + */ + public long collectionSizeQuota() { + return this.maxQuotaHeader(Constants.Quota.COLLECTION_SIZE); + } + + /** + * Gets the current size of a collection in kilobytes from the Azure Cosmos DB service. + * + * @return The current size of a collection in kilobytes. + */ + public long collectionSizeUsage() { + return this.currentQuotaHeader(Constants.Quota.COLLECTION_SIZE); + } + + /** + * Gets the maximum quota of stored procedures for a collection from the Azure Cosmos DB service. + * + * @return The maximum stored procedure quota. + */ + public long storedProceduresQuota() { + return this.maxQuotaHeader(Constants.Quota.STORED_PROCEDURE); + } + + /** + * Gets the current number of stored procedures for a collection from the Azure Cosmos DB service. + * + * @return The current number of stored procedures. + */ + public long storedProceduresUsage() { + return this.currentQuotaHeader(Constants.Quota.STORED_PROCEDURE); + } + + /** + * Gets the maximum quota of triggers for a collection from the Azure Cosmos DB service. + * + * @return The maximum triggers quota. + */ + public long triggersQuota() { + return this.maxQuotaHeader(Constants.Quota.TRIGGER); + } + + /** + * Get the current number of triggers for a collection from the Azure Cosmos DB service. + * + * @return The current number of triggers. + */ + public long triggersUsage() { + return this.currentQuotaHeader(Constants.Quota.TRIGGER); + } + + /** + * Gets the maximum quota of user defined functions for a collection from the Azure Cosmos DB service. + * + * @return The maximum user defined functions quota. + */ + public long userDefinedFunctionsQuota() { + return this.maxQuotaHeader(Constants.Quota.USER_DEFINED_FUNCTION); + } + + /** + * Gets the current number of user defined functions for a collection from the Azure Cosmos DB service. + * + * @return the current number of user defined functions. + */ + public long userDefinedFunctionsUsage() { + return this.currentQuotaHeader(Constants.Quota.USER_DEFINED_FUNCTION); + } + + /** + * Gets the maximum size limit for this entity from the Azure Cosmos DB service. + * + * @return the maximum size limit for this entity. + * Measured in kilobytes for document resources and in counts for other resources. + */ + public String maxResourceQuota() { + return getValueOrNull(header, + HttpConstants.HttpHeaders.MAX_RESOURCE_QUOTA); + } + + /** + * Gets the current size of this entity from the Azure Cosmos DB service. + * + * @return the current size for this entity. Measured in kilobytes for document resources + * and in counts for other resources. + */ + public String currentResourceQuotaUsage() { + return getValueOrNull(header, + HttpConstants.HttpHeaders.CURRENT_RESOURCE_QUOTA_USAGE); + } + + /** + * Gets the number of index paths (terms) generated by the operation. + * + * @return the request charge. + */ + public double requestCharge() { + String value = getValueOrNull(header, + HttpConstants.HttpHeaders.REQUEST_CHARGE); + if (StringUtils.isEmpty(value)) { + return 0; + } + return Double.valueOf(value); + } + + /** + * Gets the activity ID for the request. + * + * @return the activity id. + */ + public String activityId() { + return getValueOrNull(header, HttpConstants.HttpHeaders.ACTIVITY_ID); + } + + /** + * Gets the continuation token to be used for continuing the enumeration. + * + * @return the response continuation. + */ + public String continuationToken() { + String headerName = useEtagAsContinuation + ? HttpConstants.HttpHeaders.E_TAG + : HttpConstants.HttpHeaders.CONTINUATION; + return getValueOrNull(header, headerName); + } + + /** + * Gets the session token for use in session consistency. + * + * @return the session token. + */ + public String sessionToken() { + return getValueOrNull(header, HttpConstants.HttpHeaders.SESSION_TOKEN); + } + + /** + * Gets the response headers. + * + * @return the response headers. + */ + public Map responseHeaders() { + return header; + } + + private String queryMetricsString(){ + return getValueOrNull(responseHeaders(), + HttpConstants.HttpHeaders.QUERY_METRICS); + } + + /** + * Gets the feed response diagnostics + * @return Feed response diagnostics + */ + public FeedResponseDiagnostics feedResponseDiagnostics() { + return this.feedResponseDiagnostics; + } + + ConcurrentMap queryMetrics() { + if (queryMetricsMap != null && !queryMetricsMap.isEmpty()) { + return queryMetricsMap; + } + + //We parse query metrics for un-partitioned collection here + if (!StringUtils.isEmpty(queryMetricsString())) { + String qm = queryMetricsString(); + qm += String.format(";%s=%.2f", QueryMetricsConstants.RequestCharge, requestCharge()); + queryMetricsMap.put(DefaultPartition, QueryMetrics.createFromDelimitedString(qm)); + } + return queryMetricsMap; + } + + ConcurrentMap queryMetricsMap(){ + return queryMetricsMap; + } + + private long currentQuotaHeader(String headerName) { + if (this.usageHeaders.size() == 0 && !StringUtils.isEmpty(this.maxResourceQuota()) && + !StringUtils.isEmpty(this.currentResourceQuotaUsage())) { + this.populateQuotaHeader(this.maxResourceQuota(), this.currentResourceQuotaUsage()); + } + + if (this.usageHeaders.containsKey(headerName)) { + return this.usageHeaders.get(headerName); + } + + return 0; + } + + private long maxQuotaHeader(String headerName) { + if (this.quotaHeaders.size() == 0 && + !StringUtils.isEmpty(this.maxResourceQuota()) && + !StringUtils.isEmpty(this.currentResourceQuotaUsage())) { + this.populateQuotaHeader(this.maxResourceQuota(), this.currentResourceQuotaUsage()); + } + + if (this.quotaHeaders.containsKey(headerName)) { + return this.quotaHeaders.get(headerName); + } + + return 0; + } + + private void populateQuotaHeader(String headerMaxQuota, + String headerCurrentUsage) { + String[] headerMaxQuotaWords = headerMaxQuota.split(Constants.Quota.DELIMITER_CHARS, -1); + String[] headerCurrentUsageWords = headerCurrentUsage.split(Constants.Quota.DELIMITER_CHARS, -1); + + for (int i = 0; i < headerMaxQuotaWords.length; ++i) { + if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.DATABASE)) { + this.quotaHeaders.put(Constants.Quota.DATABASE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.DATABASE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.COLLECTION)) { + this.quotaHeaders.put(Constants.Quota.COLLECTION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.COLLECTION, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.USER)) { + this.quotaHeaders.put(Constants.Quota.USER, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.USER, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.PERMISSION)) { + this.quotaHeaders.put(Constants.Quota.PERMISSION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.PERMISSION, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.COLLECTION_SIZE)) { + this.quotaHeaders.put(Constants.Quota.COLLECTION_SIZE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.COLLECTION_SIZE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.STORED_PROCEDURE)) { + this.quotaHeaders.put(Constants.Quota.STORED_PROCEDURE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.STORED_PROCEDURE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.TRIGGER)) { + this.quotaHeaders.put(Constants.Quota.TRIGGER, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.TRIGGER, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.USER_DEFINED_FUNCTION)) { + this.quotaHeaders.put(Constants.Quota.USER_DEFINED_FUNCTION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.USER_DEFINED_FUNCTION, + Long.valueOf(headerCurrentUsageWords[i + 1])); + } + } + } + + private static String getValueOrNull(Map map, String key) { + if (map != null) { + return map.get(key); + } + return null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponseDiagnostics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponseDiagnostics.java new file mode 100644 index 0000000000000..acabc5c5f32d9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/FeedResponseDiagnostics.java @@ -0,0 +1,38 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.QueryMetrics; +import org.apache.commons.lang3.StringUtils; + +import java.util.Map; + +public class FeedResponseDiagnostics { + + private Map queryMetricsMap; + + FeedResponseDiagnostics(Map queryMetricsMap) { + this.queryMetricsMap = queryMetricsMap; + } + + Map queryMetricsMap() { + return queryMetricsMap; + } + + FeedResponseDiagnostics queryMetricsMap(Map queryMetricsMap) { + this.queryMetricsMap = queryMetricsMap; + return this; + } + + /** + * Returns the textual representation of feed response metrics + * @return Textual representation of feed response metrics + */ + @Override + public String toString() { + if (queryMetricsMap == null || queryMetricsMap.isEmpty()) { + return StringUtils.EMPTY; + } + StringBuilder stringBuilder = new StringBuilder(); + queryMetricsMap.forEach((key, value) -> stringBuilder.append(key).append("=").append(value.toString()).append("\n")); + return stringBuilder.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ForbiddenException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ForbiddenException.java new file mode 100644 index 0000000000000..9cc3142107948 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ForbiddenException.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class ForbiddenException extends CosmosClientException { + ForbiddenException() { + this(RMResources.Forbidden); + } + + public ForbiddenException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.FORBIDDEN, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + ForbiddenException(String message) { + this(message, null, null, null); + } + + ForbiddenException(String message, HttpHeaders headers, String requestUrlString) { + this(message, null, headers, requestUrlString); + } + + public ForbiddenException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + ForbiddenException(Exception innerException) { + this(RMResources.Forbidden, innerException, null, null); + } + + ForbiddenException(String message, + Exception innerException, + HttpHeaders headers, + String requestUrlString) { + super(String.format("%s: %s", RMResources.Forbidden, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.FORBIDDEN, + requestUrlString); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/GoneException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/GoneException.java new file mode 100644 index 0000000000000..8979ee64c4058 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/GoneException.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +public class GoneException extends CosmosClientException { + + public GoneException(String msg) { + this(msg, null); + } + public GoneException() { + this(RMResources.Gone, null); + } + + public GoneException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.GONE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public GoneException(String message, String requestUri) { + this(message, null, new HashMap<>(), requestUri); + } + + GoneException(String message, + Exception innerException, + URI requestUri, + String localIpAddress) { + this(message(localIpAddress, message), innerException, null, requestUri); + } + + GoneException(Exception innerException) { + this(RMResources.Gone, innerException, new HashMap<>(), null); + } + + public GoneException(String message, HttpHeaders headers, URI requestUrl) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.GONE, requestUrl != null ? requestUrl.toString() : null); + } + + GoneException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.GONE, requestUriString); + } + + public GoneException(String message, + Exception innerException, + HttpHeaders headers, + URI requestUrl) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.GONE, requestUrl != null ? requestUrl.toString() : null); + } + + public GoneException(String message, + Exception innerException, + Map headers, + String requestUriString) { + super(message, innerException, headers, HttpConstants.StatusCodes.GONE, requestUriString); + } + + GoneException(CosmosError cosmosError, Map headers) { + super(HttpConstants.StatusCodes.GONE, cosmosError, headers); + } + + private static String message(String localIP, String baseMessage) { + if (!Strings.isNullOrEmpty(localIP)) { + return String.format( + RMResources.ExceptionMessageAddIpAddress, + baseMessage, + localIP); + } + + return baseMessage; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/HashIndex.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/HashIndex.java new file mode 100644 index 0000000000000..a501d27846967 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/HashIndex.java @@ -0,0 +1,136 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a hash index in the Azure Cosmos DB database service. + */ +public final class HashIndex extends Index { + + /** + * Specifies an instance of HashIndex class with specified DataType. + *

    + * Here is an example to instantiate HashIndex class passing in the DataType: + *

    +     * {@code
    +     *
    +     * HashIndex hashIndex = new HashIndex(DataType.STRING);
    +     *
    +     * }
    +     * 
    + * + * @param dataType the data type. + */ + public HashIndex(DataType dataType) { + super(IndexKind.HASH); + this.dataType(dataType); + } + + /** + * Initializes a new instance of the HashIndex class with specified DataType and precision. + *

    + * Here is an example to instantiate HashIndex class passing in the DataType: + *

    +     * {@code
    +     *
    +     * HashIndex hashIndex = new HashIndex(DataType.STRING, 3);
    +     *
    +     * }
    +     * 
    + * + * @param dataType the data type. + * @param precision the precision. + */ + public HashIndex(DataType dataType, int precision) { + super(IndexKind.HASH); + this.dataType(dataType); + this.precision(precision); + } + + /** + * Initializes a new instance of the HashIndex class with json string. + * + * @param jsonString the json string that represents the index. + */ + HashIndex(String jsonString) { + super(jsonString, IndexKind.HASH); + if (this.dataType() == null) { + throw new IllegalArgumentException("The jsonString doesn't contain a valid 'dataType'."); + } + } + + /** + * Gets data type. + * + * @return the data type. + */ + public DataType dataType() { + DataType result = null; + try { + result = DataType.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.DATA_TYPE))); + } catch (IllegalArgumentException e) { + // Ignore exception and let the caller handle null value. + this.getLogger().warn("INVALID index dataType value {}.", super.getString(Constants.Properties.DATA_TYPE)); + } + return result; + } + + /** + * Sets data type. + * + * @param dataType the data type. + * @return the Hash Index. + */ + public HashIndex dataType(DataType dataType) { + super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + return this; + } + + /** + * Gets precision. + * + * @return the precision. + */ + public int precision() { + return super.getInt(Constants.Properties.PRECISION); + } + + /** + * Sets precision. + * + * @param precision the precision. + * @return the Hash Index. + */ + public HashIndex precision(int precision) { + super.set(Constants.Properties.PRECISION, precision); + return this; + } + + boolean hasPrecision() { + return super.has(Constants.Properties.PRECISION); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IncludedPath.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IncludedPath.java new file mode 100644 index 0000000000000..b18424cf89990 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IncludedPath.java @@ -0,0 +1,138 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Represents an included path of the IndexingPolicy in the Azure Cosmos DB database service. + */ +public class IncludedPath extends JsonSerializable { + + private Collection indexes; + + /** + * Constructor. + */ + public IncludedPath() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the included path. + */ + public IncludedPath(String jsonString) { + super(jsonString); + } + + /** + * Gets path. + * + * @return the path. + */ + public String path() { + return super.getString(Constants.Properties.PATH); + } + + /** + * Sets path. + * + * @param path the path. + * @return the Included Path. + */ + public IncludedPath path(String path) { + super.set(Constants.Properties.PATH, path); + return this; + } + + /** + * Gets the paths that are chosen to be indexed by the user. + * + * @return the included paths. + */ + public Collection indexes() { + if (this.indexes == null) { + this.indexes = this.indexCollection(); + + if (this.indexes == null) { + this.indexes = new ArrayList(); + } + } + + return this.indexes; + } + + public IncludedPath indexes(Collection indexes) { + this.indexes = indexes; + return this; + } + + private Collection indexCollection() { + if (this.propertyBag != null && this.propertyBag.has(Constants.Properties.INDEXES)) { + ArrayNode jsonArray = (ArrayNode) this.propertyBag.get(Constants.Properties.INDEXES); + Collection result = new ArrayList(); + + for (int i = 0; i < jsonArray.size(); i++) { + JsonNode jsonObject = jsonArray.get(i); + + IndexKind indexKind = IndexKind.valueOf(StringUtils.upperCase( + jsonObject.get(Constants.Properties.INDEX_KIND).asText())); + switch (indexKind) { + case HASH: + result.add(new HashIndex(jsonObject.toString())); + break; + case RANGE: + result.add(new RangeIndex(jsonObject.toString())); + break; + case SPATIAL: + result.add(new SpatialIndex(jsonObject.toString())); + break; + } + } + + return result; + } + + return null; + } + + @Override + void populatePropertyBag() { + if (this.indexes != null) { + for (Index index : this.indexes) { + index.populatePropertyBag(); + } + + super.set(Constants.Properties.INDEXES, this.indexes); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Index.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Index.java new file mode 100644 index 0000000000000..7a91b006f7cb2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Index.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents the index of a collection in the Azure Cosmos DB database service. + */ +public abstract class Index extends JsonSerializable { + + /** + * Constructor. + * + * @param indexKind the kind of the index + */ + Index(IndexKind indexKind) { + super(); + this.kind(indexKind); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the index. + * @param indexKind the kind of the index + */ + Index(String jsonString, IndexKind indexKind) { + super(jsonString); + this.kind(indexKind); + } + + /** + * Returns an instance of RangeIndex class with specified DataType. + *

    + * Here is an example to create RangeIndex instance passing in the DataType: + *

    +     * {@code
    +     *
    +     * RangeIndex rangeIndex = Index.RANGE(DataType.NUMBER);
    +     *
    +     * }
    +     * 
    + * + * @param dataType the data type. + * @return an instance of RangeIndex type. + */ + public static RangeIndex Range(DataType dataType) { + return new RangeIndex(dataType); + } + + /** + * Returns an instance of RangeIndex class with specified DataType and precision. + *

    + * Here is an example to create RangeIndex instance passing in the DataType and precision: + *

    +     * {@code
    +     *
    +     * RangeIndex rangeIndex = Index.RANGE(DataType.NUMBER, -1);
    +     *
    +     * }
    +     * 
    + * + * @param dataType specifies the target data type for the index path specification. + * @param precision specifies the precision to be used for the data type associated with this index. + * @return an instance of RangeIndex type. + */ + public static RangeIndex Range(DataType dataType, int precision) { + return new RangeIndex(dataType, precision); + } + + /** + * Returns an instance of HashIndex class with specified DataType. + *

    + * Here is an example to create HashIndex instance passing in the DataType: + *

    +     * {@code
    +     *
    +     * HashIndex hashIndex = Index.HASH(DataType.STRING);
    +     * }
    +     * 
    + * + * @param dataType specifies the target data type for the index path specification. + * @return an instance of HashIndex type. + */ + public static HashIndex Hash(DataType dataType) { + return new HashIndex(dataType); + } + + /** + * Returns an instance of HashIndex class with specified DataType and precision. + *

    + * Here is an example to create HashIndex instance passing in the DataType and precision: + *

    + * HashIndex hashIndex = Index.HASH(DataType.STRING, 3); + * + * @param dataType specifies the target data type for the index path specification. + * @param precision specifies the precision to be used for the data type associated with this index. + * @return an instance of HashIndex type. + */ + public static HashIndex Hash(DataType dataType, int precision) { + return new HashIndex(dataType, precision); + } + + /** + * Returns an instance of SpatialIndex class with specified DataType. + *

    + * Here is an example to create SpatialIndex instance passing in the DataType: + *

    + * SpatialIndex spatialIndex = Index.SPATIAL(DataType.POINT); + * + * @param dataType specifies the target data type for the index path specification. + * @return an instance of SpatialIndex type. + */ + public static SpatialIndex Spatial(DataType dataType) { + return new SpatialIndex(dataType); + } + + /** + * Gets index kind. + * + * @return the index kind. + */ + public IndexKind kind() { + IndexKind result = null; + try { + result = IndexKind.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.INDEX_KIND))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID index kind value %s.", super.getString(Constants.Properties.INDEX_KIND)); + } + + return result; + } + + /** + * Sets index kind. + * + * @param indexKind the index kind. + */ + private Index kind(IndexKind indexKind) { + super.set(Constants.Properties.INDEX_KIND, indexKind.toString()); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexKind.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexKind.java new file mode 100644 index 0000000000000..cea3ec493419b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexKind.java @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * These are the indexing types available for indexing a path in the Azure Cosmos DB database service. + * For additional details, refer to + * http://azure.microsoft.com/documentation/articles/documentdb-indexing-policies/#ConfigPolicy. + */ +public enum IndexKind { + // The index entries are hashed to serve point look up queries. + // Can be used to serve queries like: SELECT * FROM docs d WHERE d.prop = 5 + HASH, + + // The index entries are ordered. RANGE indexes are optimized for inequality predicate queries with efficient range + // scans. + // Can be used to serve queries like: SELECT * FROM docs d WHERE d.prop > 5 + RANGE, + + // The index entries are indexed to serve spatial queries like below: + // SELECT * FROM Root r WHERE ST_DISTANCE({"type":"POINT","coordinates":[71.0589,42.3601]}, r.location) $LE 10000 + SPATIAL; + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingDirective.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingDirective.java new file mode 100644 index 0000000000000..3e692aa840225 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingDirective.java @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * Specifies whether or not the resource is to be indexed in the Azure Cosmos DB database service. + */ +public enum IndexingDirective { + + /** + * Use any pre-defined/pre-configured defaults. + */ + DEFAULT, + + /** + * Index the resource. + */ + INCLUDE, + + /** + * Do not index the resource. + */ + EXCLUDE; + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingMode.java new file mode 100644 index 0000000000000..e745eab1c68e3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingMode.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * Specifies the supported indexing modes in the Azure Cosmos DB database service. + */ +public enum IndexingMode { + /** + * Index is updated synchronously with a create or update operation. + *

    + * With consistent indexing, query behavior is the same as the default consistency level for the collection. The + * index is always kept up to date with the data. + */ + CONSISTENT, + + /** + * Index is updated asynchronously with respect to a create or update operation. + *

    + * With lazy indexing, queries are eventually consistent. The index is updated when the collection is idle. + */ + LAZY, + + /** + * No index is provided. + *

    + * Setting IndexingMode to "NONE" drops the index. Use this if you don't want to maintain the index for a document + * collection, to save the storage cost or improve the write throughput. Your queries will degenerate to scans of + * the entire collection. + */ + NONE; + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingPolicy.java new file mode 100644 index 0000000000000..588d7297b1f9b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/IndexingPolicy.java @@ -0,0 +1,285 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Represents the indexing policy configuration for a collection in the Azure Cosmos DB database service. + */ +public final class IndexingPolicy extends JsonSerializable { + + private static final String DEFAULT_PATH = "/*"; + + private List includedPaths; + private List excludedPaths; + private List> compositeIndexes; + private List spatialIndexes; + + /** + * Constructor. + */ + public IndexingPolicy() { + this.automatic(true); + this.indexingMode(IndexingMode.CONSISTENT); + } + + /** + * Initializes a new instance of the IndexingPolicy class with the specified set of indexes as + * default index specifications for the root path. + *

    + * The following example shows how to override the default indexingPolicy for root path: + *

    +     * {@code
    +     * HashIndex hashIndexOverride = Index.HASH(DataType.STRING, 5);
    +     * RangeIndex rangeIndexOverride = Index.RANGE(DataType.NUMBER, 2);
    +     * SpatialIndex spatialIndexOverride = Index.SPATIAL(DataType.POINT);
    +     *
    +     * IndexingPolicy indexingPolicy = new IndexingPolicy(hashIndexOverride, rangeIndexOverride, spatialIndexOverride);
    +     * }
    +     * 
    + *

    + * If you would like to just override the indexingPolicy for Numbers you can specify just that: + *

    +     * {@code
    +     * RangeIndex rangeIndexOverride = Index.RANGE(DataType.NUMBER, 2);
    +     *
    +     * IndexingPolicy indexingPolicy = new IndexingPolicy(rangeIndexOverride);
    +     * }
    +     * 
    + * + * @param defaultIndexOverrides comma separated set of indexes that serve as default index specifications for the root path. + */ + public IndexingPolicy(Index[] defaultIndexOverrides) { + this(); + + if (defaultIndexOverrides == null) { + throw new IllegalArgumentException("defaultIndexOverrides is null."); + } + + IncludedPath includedPath = new IncludedPath(); + includedPath.path(IndexingPolicy.DEFAULT_PATH); + includedPath.indexes(new ArrayList(Arrays.asList(defaultIndexOverrides))); + this.includedPaths().add(includedPath); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the indexing policy. + */ + IndexingPolicy(String jsonString) { + super(jsonString); + } + + /** + * Gets whether automatic indexing is enabled for a collection. + *

    + * In automatic indexing, documents can be explicitly excluded from indexing using RequestOptions. In manual + * indexing, documents can be explicitly included. + * + * @return the automatic + */ + public Boolean automatic() { + return super.getBoolean(Constants.Properties.AUTOMATIC); + } + + /** + * Sets whether automatic indexing is enabled for a collection. + *

    + * In automatic indexing, documents can be explicitly excluded from indexing using RequestOptions. In manual + * indexing, documents can be explicitly included. + * + * @param automatic the automatic + * @return the Indexing Policy. + */ + public IndexingPolicy automatic(boolean automatic) { + super.set(Constants.Properties.AUTOMATIC, automatic); + return this; + } + + /** + * Gets the indexing mode (consistent or lazy). + * + * @return the indexing mode. + */ + public IndexingMode indexingMode() { + IndexingMode result = IndexingMode.LAZY; + try { + result = IndexingMode.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.INDEXING_MODE))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID indexingMode value {}.", super.getString(Constants.Properties.INDEXING_MODE)); + } + return result; + } + + /** + * Sets the indexing mode (consistent or lazy). + * + * @param indexingMode the indexing mode. + * @return the Indexing Policy. + */ + public IndexingPolicy indexingMode(IndexingMode indexingMode) { + super.set(Constants.Properties.INDEXING_MODE, indexingMode.toString()); + return this; + } + + /** + * Gets the paths that are chosen to be indexed by the user. + * + * @return the included paths. + */ + public List includedPaths() { + if (this.includedPaths == null) { + this.includedPaths = super.getList(Constants.Properties.INCLUDED_PATHS, IncludedPath.class); + + if (this.includedPaths == null) { + this.includedPaths = new ArrayList(); + } + } + + return this.includedPaths; + } + + public void setIncludedPaths(List includedPaths) { + this.includedPaths = includedPaths; + } + + /** + * Gets the paths that are not indexed. + * + * @return the excluded paths. + */ + public List excludedPaths() { + if (this.excludedPaths == null) { + this.excludedPaths = super.getList(Constants.Properties.EXCLUDED_PATHS, ExcludedPath.class); + + if (this.excludedPaths == null) { + this.excludedPaths = new ArrayList(); + } + } + + return this.excludedPaths; + } + + public IndexingPolicy excludedPaths(List excludedPaths) { + this.excludedPaths = excludedPaths; + return this; + } + + /** + * Gets the composite indexes for additional indexes. + * + * @return the composite indexes. + */ + public List> compositeIndexes() { + if (this.compositeIndexes == null) { + this.compositeIndexes = new ArrayList<>(); + ArrayNode compositeIndexes = (ArrayNode) super.get(Constants.Properties.COMPOSITE_INDEXES); + for (int i = 0; i < compositeIndexes.size(); i ++) { + ArrayNode compositeIndex = (ArrayNode) compositeIndexes.get(i); + ArrayList compositePaths = new ArrayList(); + for (int j = 0; j < compositeIndex.size(); j ++) { + CompositePath candidateCompositePath = new CompositePath(compositeIndex.get(j).toString()); + compositePaths.add(candidateCompositePath); + } + this.compositeIndexes.add(compositePaths); + } + } + + return this.compositeIndexes; + } + + /** + * Sets the composite indexes for additional indexes. + * + * @param compositeIndexes the composite indexes. + * @return the Indexing Policy. + */ + public IndexingPolicy compositeIndexes(List> compositeIndexes) { + this.compositeIndexes = compositeIndexes; + super.set(Constants.Properties.COMPOSITE_INDEXES, this.compositeIndexes); + return this; + } + + /** + * Sets the spatial indexes for additional indexes. + * + * @return the spatial indexes. + */ + public List spatialIndexes() { + if (this.spatialIndexes == null) { + this.spatialIndexes = super.getList(Constants.Properties.SPATIAL_INDEXES, SpatialSpec.class); + + if (this.spatialIndexes == null) { + this.spatialIndexes = new ArrayList(); + } + } + + return this.spatialIndexes; + } + + /** + * Sets the spatial indexes for additional indexes. + * + * @param spatialIndexes the spatial indexes. + * @return the Indexing Policy. + */ + public IndexingPolicy spatialIndexes(List spatialIndexes) { + this.spatialIndexes = spatialIndexes; + super.set(Constants.Properties.SPATIAL_INDEXES, this.spatialIndexes); + return this; + } + + @Override + void populatePropertyBag() { + // If indexing mode is not 'none' and not paths are set, set them to the defaults + if (this.indexingMode() != IndexingMode.NONE && this.includedPaths().size() == 0 && + this.excludedPaths().size() == 0) { + IncludedPath includedPath = new IncludedPath(); + includedPath.path(IndexingPolicy.DEFAULT_PATH); + this.includedPaths().add(includedPath); + } + + if (this.includedPaths != null) { + for (IncludedPath includedPath : this.includedPaths) { + includedPath.populatePropertyBag(); + } + super.set(Constants.Properties.INCLUDED_PATHS, this.includedPaths); + } + + if (this.excludedPaths != null) { + for (ExcludedPath excludedPath : this.excludedPaths) { + excludedPath.populatePropertyBag(); + } + super.set(Constants.Properties.EXCLUDED_PATHS, this.excludedPaths); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InternalServerErrorException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InternalServerErrorException.java new file mode 100644 index 0000000000000..407ba1dab51d5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InternalServerErrorException.java @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.net.URL; +import java.util.Map; + +/** + * This exception is thrown when DocumentServiceRequest contains x-ms-documentdb-partitionkeyrangeid + * header and such range id doesn't exist. + *

    + * No retries should be made in this case, as either split or merge might have happened and query/readfeed + * must take appropriate actions. + */ +public class InternalServerErrorException extends CosmosClientException { + + InternalServerErrorException() { + this(RMResources.InternalServerError); + } + + public InternalServerErrorException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public InternalServerErrorException(String message) { + this(message, null, (Map) null, null); + } + + + InternalServerErrorException(String message, Exception innerException) { + this(message, innerException, (HttpHeaders) null, (String) null); + } + + InternalServerErrorException(Exception innerException) { + this(RMResources.InternalServerError, innerException, (HttpHeaders) null, (String) null); + } + + public InternalServerErrorException(String message, HttpHeaders headers, URI requestUri) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUri != null ? requestUri.toString() : null); + } + + InternalServerErrorException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUriString); + } + + InternalServerErrorException(String message, HttpHeaders headers, URL requestUrl) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUrl != null ? requestUrl.toString() : null); + } + + InternalServerErrorException(String message, Exception innerException, HttpHeaders headers, URI requestUri) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUri != null ? requestUri.toString() : null); + } + + InternalServerErrorException(String message, Exception innerException, HttpHeaders headers, String requestUriString) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUriString); + } + + public InternalServerErrorException(String message, Exception innerException, Map headers, String requestUriString) { + super(message, innerException, headers, HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, requestUriString); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InvalidPartitionException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InvalidPartitionException.java new file mode 100644 index 0000000000000..8231f73701d60 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/InvalidPartitionException.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class InvalidPartitionException extends CosmosClientException { + + private static final long serialVersionUID = 1L; + + public InvalidPartitionException() { + this(RMResources.Gone); + } + + public InvalidPartitionException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.GONE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public InvalidPartitionException(String msg) { + super(HttpConstants.StatusCodes.GONE, msg); + setSubStatus(); + } + + public InvalidPartitionException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.GONE, resourceAddress); + setSubStatus(); + } + + public InvalidPartitionException(String message, HttpHeaders headers, String requestUri) { + this(message, null, headers, requestUri); + } + + InvalidPartitionException(Exception innerException) { + this(RMResources.Gone, innerException, null, null); + } + + InvalidPartitionException(String message, + Exception innerException, + HttpHeaders headers, + String requestUri) { + super(String.format("%s: %s", RMResources.Gone, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.GONE, + requestUri); + + setSubStatus(); + } + + private void setSubStatus() { + this.responseHeaders().put( + WFConstants.BackendHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE)); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/JsonSerializable.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/JsonSerializable.java new file mode 100644 index 0000000000000..8d8ef71da9b92 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/JsonSerializable.java @@ -0,0 +1,603 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Represents a base resource that can be serialized to JSON in the Azure Cosmos DB database service. + */ +public class JsonSerializable { + private final static Logger logger = LoggerFactory.getLogger(JsonSerializable.class); + private final static ObjectMapper OBJECT_MAPPER = Utils.getSimpleObjectMapper(); + private ObjectMapper om; + transient ObjectNode propertyBag = null; + + protected JsonSerializable() { + this.propertyBag = OBJECT_MAPPER.createObjectNode(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the JsonSerializable. + * @param objectMapper the custom object mapper + */ + JsonSerializable(String jsonString, ObjectMapper objectMapper) { + // TODO: Made package private due to #153. #171 adding custom serialization options back. + this.propertyBag = fromJson(jsonString); + this.om = objectMapper; + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the JsonSerializable. + */ + protected JsonSerializable(String jsonString) { + this.propertyBag = fromJson(jsonString); + } + + /** + * Constructor. + * + * @param objectNode the {@link ObjectNode} that represent the {@link JsonSerializable} + */ + JsonSerializable(ObjectNode objectNode) { + this.propertyBag = objectNode; + } + + private ObjectMapper getMapper() { + // TODO: Made package private due to #153. #171 adding custom serialization options back. + if (this.om != null) { return this.om; } + return OBJECT_MAPPER; + } + + void setMapper(ObjectMapper om) { + this.om = om; + } + + private static void checkForValidPOJO(Class c) { + if (c.isAnonymousClass() || c.isLocalClass()) { + throw new IllegalArgumentException( + String.format("%s can't be an anonymous or local class.", c.getName())); + } + if (c.isMemberClass() && !Modifier.isStatic(c.getModifiers())) { + throw new IllegalArgumentException( + String.format("%s must be static if it's a member class.", c.getName())); + } + } + + public Logger getLogger() { + return logger; + } + + void populatePropertyBag() { + } + + /** + * Returns the propertybag(JSONObject) in a hashMap + * + * @return the HashMap. + */ + public Map getMap() { + return getMapper().convertValue(this.propertyBag, HashMap.class); + } + + /** + * Checks whether a property exists. + * + * @param propertyName the property to look up. + * @return true if the property exists. + */ + public boolean has(String propertyName) { + return this.propertyBag.has(propertyName); + } + + /** + * Removes a value by propertyName. + * + * @param propertyName the property to remove. + */ + void remove(String propertyName) { + this.propertyBag.remove(propertyName); + } + + /** + * Sets the value of a property. + * + * @param the type of the object. + * @param propertyName the property to set. + * @param value the value of the property. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + void set(String propertyName, T value) { + if (value == null) { + // Sets null. + this.propertyBag.putNull(propertyName); + } else if (value instanceof Collection) { + // Collection. + ArrayNode jsonArray = propertyBag.arrayNode(); + this.internalSetCollection(propertyName, (Collection) value, jsonArray); + this.propertyBag.set(propertyName, jsonArray); + } else if (value instanceof JsonNode) { + this.propertyBag.set(propertyName, (JsonNode) value); + } else if (value instanceof JsonSerializable) { + // JsonSerializable + JsonSerializable castedValue = (JsonSerializable) value; + if (castedValue != null) { + castedValue.populatePropertyBag(); + } + this.propertyBag.set(propertyName, castedValue != null ? castedValue.propertyBag : null); + } else { + // POJO, ObjectNode, number (includes int, float, double etc), boolean, + // and string. + this.propertyBag.set(propertyName, getMapper().valueToTree(value)); + } + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void internalSetCollection(String propertyName, Collection collection, ArrayNode targetArray) { + for (T childValue : collection) { + if (childValue == null) { + // Sets null. + targetArray.addNull(); + } else if (childValue instanceof Collection) { + // When T is also a Collection, use recursion. + ArrayNode childArray = targetArray.addArray(); + this.internalSetCollection(propertyName, (Collection) childValue, childArray); + } else if (childValue instanceof JsonNode) { + targetArray.add((JsonNode) childValue); + } else if (childValue instanceof JsonSerializable) { + // JsonSerializable + JsonSerializable castedValue = (JsonSerializable) childValue; + castedValue.populatePropertyBag(); + targetArray.add(castedValue.propertyBag != null ? castedValue.propertyBag : this.getMapper().createObjectNode()); + } else { + // POJO, JSONObject, NUMBER (includes Int, Float, Double etc), + // Boolean, and STRING. + targetArray.add(this.getMapper().valueToTree(childValue)); + } + } + } + + /** + * Gets a property value as Object. + * + * @param propertyName the property to get. + * @return the value of the property. + */ + public Object get(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return getValue(this.propertyBag.get(propertyName)); + } else { + return null; + } + } + + /** + * Gets a string value. + * + * @param propertyName the property to get. + * @return the string value. + */ + public String getString(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return this.propertyBag.get(propertyName).asText(); + } else { + return null; + } + } + + /** + * Gets a boolean value. + * + * @param propertyName the property to get. + * @return the boolean value. + */ + public Boolean getBoolean(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return this.propertyBag.get(propertyName).asBoolean(); + } else { + return null; + } + } + + /** + * Gets an integer value. + * + * @param propertyName the property to get. + * @return the boolean value + */ + public Integer getInt(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return Integer.valueOf(this.propertyBag.get(propertyName).asInt()); + } else { + return null; + } + } + + /** + * Gets a long value. + * + * @param propertyName the property to get. + * @return the long value + */ + public Long getLong(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return Long.valueOf(this.propertyBag.get(propertyName).asLong()); + } else { + return null; + } + } + + /** + * Gets a double value. + * + * @param propertyName the property to get. + * @return the double value. + */ + public Double getDouble(String propertyName) { + if (this.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + return new Double(this.propertyBag.get(propertyName).asDouble()); + } else { + return null; + } + } + + /** + * Gets an object value. + * + * @param the type of the object. + * @param propertyName the property to get. + * @param c the class of the object. If c is a POJO class, it must be a member (and not an anonymous or local) + * and a static one. + * @param convertFromCamelCase boolean indicating if String should be converted from camel case to upper case separated by underscore, + * before converting to required class. + * @return the object value. + */ + public T getObject(String propertyName, Class c, boolean ... convertFromCamelCase) { + if (this.propertyBag.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + JsonNode jsonObj = propertyBag.get(propertyName); + if (Number.class.isAssignableFrom(c) || String.class.isAssignableFrom(c) + || Boolean.class.isAssignableFrom(c) || Object.class == c) { + // NUMBER, STRING, Boolean + return c.cast(getValue(jsonObj)); + } else if (Enum.class.isAssignableFrom(c)) { + try { + String value = String.class.cast(getValue(jsonObj)); + value = convertFromCamelCase.length > 0 && convertFromCamelCase[0] ? Strings.fromCamelCaseToUpperCase(value) : value; + return c.cast(c.getMethod("valueOf", String.class).invoke(null, value)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to create enum.", e); + } + } else if (JsonSerializable.class.isAssignableFrom(c)) { + try { + Constructor constructor = c.getDeclaredConstructor(String.class); + if(Modifier.isPrivate(constructor.getModifiers())) { + constructor.setAccessible(true); + } + return constructor.newInstance(toJson(jsonObj)); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + } else { + // POJO + JsonSerializable.checkForValidPOJO(c); + try { + return this.getMapper().treeToValue(jsonObj, c); + } catch (IOException e) { + throw new IllegalStateException("Failed to get POJO.", e); + } + } + } + + return null; + } + + /** + * Gets an object List. + * + * @param the type of the objects in the List. + * @param propertyName the property to get + * @param c the class of the object. If c is a POJO class, it must be a member (and not an anonymous or local) + * and a static one. + * @param convertFromCamelCase boolean indicating if String should be converted from camel case to upper case separated by underscore, + * before converting to required class. + * @return the object collection. + */ + public List getList(String propertyName, Class c, boolean ... convertFromCamelCase) { + if (this.propertyBag.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + ArrayNode jsonArray = (ArrayNode) this.propertyBag.get(propertyName); + ArrayList result = new ArrayList(); + + boolean isBaseClass = false; + boolean isEnumClass = false; + boolean isJsonSerializable = false; + + // Check once. + if (Number.class.isAssignableFrom(c) || String.class.isAssignableFrom(c) + || Boolean.class.isAssignableFrom(c) || Object.class == c) { + isBaseClass = true; + } else if (Enum.class.isAssignableFrom(c)) { + isEnumClass = true; + } else if (JsonSerializable.class.isAssignableFrom(c)) { + isJsonSerializable = true; + } else { + JsonSerializable.checkForValidPOJO(c); + } + + for (JsonNode n : jsonArray) { + if (isBaseClass) { + // NUMBER, STRING, Boolean + result.add(c.cast(getValue(n))); + } else if (isEnumClass) { + try { + String value = String.class.cast(getValue(n)); + value = convertFromCamelCase.length > 0 && convertFromCamelCase[0] ? Strings.fromCamelCaseToUpperCase(value) : value; + result.add(c.cast(c.getMethod("valueOf", String.class).invoke(null, value))); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to create enum.", e); + } + } else if (isJsonSerializable) { + // JsonSerializable + try { + Constructor constructor = c.getDeclaredConstructor(String.class); + if(Modifier.isPrivate(constructor.getModifiers())) { + constructor.setAccessible(true); + } + result.add(constructor.newInstance(toJson(n))); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + } else { + // POJO + try { + result.add(this.getMapper().treeToValue(n, c)); + } catch (IOException e) { + throw new IllegalStateException("Failed to get POJO.", e); + } + } + } + return result; + } + return null; + } + + /** + * Gets an object collection. + * + * @param the type of the objects in the collection. + * @param propertyName the property to get + * @param c the class of the object. If c is a POJO class, it must be a member (and not an anonymous or local) + * and a static one. + * @param convertFromCamelCase boolean indicating if String should be converted from camel case to upper case separated by underscore, + * before converting to required class. + * @return the object collection. + */ + public Collection getCollection(String propertyName, Class c, boolean ... convertFromCamelCase) { + return getList(propertyName, c, convertFromCamelCase); + } + + /** + * Gets a JSONObject. + * + * @param propertyName the property to get. + * @return the JSONObject. + */ + ObjectNode getObject(String propertyName) { + if (this.propertyBag.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + ObjectNode jsonObj = (ObjectNode) this.propertyBag.get(propertyName); + return jsonObj; + } + return null; + } + + /** + * Gets a JSONObject collection. + * + * @param propertyName the property to get. + * @return the JSONObject collection. + */ + Collection getCollection(String propertyName) { + Collection result = null; + if (this.propertyBag.has(propertyName) && this.propertyBag.hasNonNull(propertyName)) { + result = new ArrayList(); + + for (JsonNode n : this.propertyBag.findValues(propertyName)) { + result.add((ObjectNode) n); + } + } + + return result; + } + + /** + * Gets the value of a property identified by an array of property names that forms the path. + * + * @param propertyNames that form the path to the property to get. + * @return the value of the property. + */ + public Object getObjectByPath(List propertyNames) { + ObjectNode propBag = this.propertyBag; + JsonNode value = null; + String propertyName = null; + Integer matchedProperties = 0; + Iterator iterator = propertyNames.iterator(); + if (iterator.hasNext()) { + do { + propertyName = iterator.next(); + if (propBag.has(propertyName)) { + matchedProperties++; + value = propBag.get(propertyName); + if (!value.isObject()) { + break; + } + propBag = (ObjectNode) value; + } else { + break; + } + } while (iterator.hasNext()); + + if (value != null && matchedProperties == propertyNames.size()) { + return getValue(value); + } + } + + return null; + } + + static Object getValue(JsonNode value) { + if (value.isValueNode()) { + switch (value.getNodeType()) { + case BOOLEAN: + return value.asBoolean(); + case NUMBER: + if (value.isInt()) { + return value.asInt(); + } else if (value.isLong()) { + return value.asLong(); + } else if (value.isDouble()) { + return value.asDouble(); + } + case STRING : + return value.asText(); + } + } + return value; + } + + private ObjectNode fromJson(String json){ + try { + return (ObjectNode) getMapper().readTree(json); + } catch (IOException e) { + throw new IllegalArgumentException(String.format("Unable to parse JSON %s", json), e); + } + } + + private String toJson(Object object){ + try { + return getMapper().writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Unable to convert JSON to STRING", e); + } + } + + private String toPrettyJson(Object object){ + try { + return getMapper().writerWithDefaultPrettyPrinter().writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Unable to convert JSON to STRING", e); + } + } + + /** + * Converts to an Object (only POJOs and JSONObject are supported). + * + * @param the type of the object. + * @param c the class of the object, either a POJO class or JSONObject. If c is a POJO class, it must be a member + * (and not an anonymous or local) and a static one. + * @return the POJO. + */ + public T toObject(Class c) { + if (JsonSerializable.class.isAssignableFrom(c) || String.class.isAssignableFrom(c) + || Number.class.isAssignableFrom(c) || Boolean.class.isAssignableFrom(c)) { + throw new IllegalArgumentException("c can only be a POJO class or JSONObject"); + } + if (ObjectNode.class.isAssignableFrom(c)) { + // JSONObject + if (ObjectNode.class != c) { + throw new IllegalArgumentException("We support JSONObject but not its sub-classes."); + } + return c.cast(this.propertyBag); + } else { + // POJO + JsonSerializable.checkForValidPOJO(c); + try { + return this.getMapper().readValue(this.toJson(), c); + } catch (IOException e) { + throw new IllegalStateException("Failed to get POJO.", e); + } + } + } + + /** + * Converts to a JSON string. + * + * @return the JSON string. + */ + public String toJson() { + return this.toJson(SerializationFormattingPolicy.NONE); + } + + /** + * Converts to a JSON string. + * + * @param formattingPolicy the formatting policy to be used. + * @return the JSON string. + */ + public String toJson(SerializationFormattingPolicy formattingPolicy) { + this.populatePropertyBag(); + if (SerializationFormattingPolicy.INDENTED.equals(formattingPolicy) ) { + return toPrettyJson(propertyBag); + } else { + return toJson(propertyBag); + } + } + + /** + * Gets Simple STRING representation of property bag. + * + * For proper conversion to json and inclusion of the default values + * use {@link #toJson()}. + * + * @return string representation of property bag. + */ + public String toString() { + return toJson(propertyBag); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/LockedException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/LockedException.java new file mode 100644 index 0000000000000..36c22c3c965d2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/LockedException.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class LockedException extends CosmosClientException { + private static final long serialVersionUID = 1L; + + LockedException() { + this(RMResources.Locked); + } + + public LockedException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.LOCKED, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + LockedException(String msg) { + super(HttpConstants.StatusCodes.LOCKED, msg); + } + + LockedException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.LOCKED, resourceAddress); + } + + public LockedException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + LockedException(Exception innerException) { + this(RMResources.Locked, innerException, null, null); + } + + LockedException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format("%s: %s", RMResources.Locked, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.LOCKED, + requestUriString); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/MethodNotAllowedException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/MethodNotAllowedException.java new file mode 100644 index 0000000000000..f81f09bf57527 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/MethodNotAllowedException.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class MethodNotAllowedException extends CosmosClientException { + MethodNotAllowedException() { + this(RMResources.MethodNotAllowed); + } + + public MethodNotAllowedException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.METHOD_NOT_ALLOWED, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + MethodNotAllowedException(String message) { + this(message, null, null, null); + } + + MethodNotAllowedException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + MethodNotAllowedException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + MethodNotAllowedException(Exception innerException) { + this(RMResources.MethodNotAllowed, innerException, null, null); + } + + public MethodNotAllowedException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format("%s: %s", RMResources.MethodNotAllowed, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.METHOD_NOT_ALLOWED, + requestUriString); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/NotFoundException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/NotFoundException.java new file mode 100644 index 0000000000000..bf3c5752004f9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/NotFoundException.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class NotFoundException extends CosmosClientException { + private static final long serialVersionUID = 1L; + + public NotFoundException() { + this(RMResources.NotFound); + } + + public NotFoundException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.NOTFOUND, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public NotFoundException(String message) { + this(message, null, (HttpHeaders) null, null); + } + + public NotFoundException(String message, Map headers, String requestUri) { + this(message, null, headers, requestUri); + } + + NotFoundException(String message, HttpHeaders headers, String requestUri) { + this(message, null, headers, requestUri); + } + + public NotFoundException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + NotFoundException(Exception innerException) { + this(RMResources.NotFound, innerException, (Map) null, null); + } + + NotFoundException(String message, + Exception innerException, + HttpHeaders headers, + String requestUri) { + this(message, innerException, HttpUtils.asMap(headers), requestUri); + } + + NotFoundException(String message, + Exception innerException, + Map headers, + String requestUri) { + super(String.format("%s: %s", RMResources.NotFound, message), + innerException, + headers, + HttpConstants.StatusCodes.NOTFOUND, + requestUri); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionIsMigratingException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionIsMigratingException.java new file mode 100644 index 0000000000000..3589cf67d5235 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionIsMigratingException.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class PartitionIsMigratingException extends CosmosClientException { + + private static final long serialVersionUID = 1L; + + public PartitionIsMigratingException() { + this(RMResources.Gone); + } + + public PartitionIsMigratingException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.GONE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + PartitionIsMigratingException(String msg) { + super(HttpConstants.StatusCodes.GONE, msg); + setSubStatus(); + } + + PartitionIsMigratingException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.GONE, resourceAddress); + setSubStatus(); + } + + public PartitionIsMigratingException(String message, HttpHeaders headers, String requestUri) { + this(message, null, headers, requestUri); + } + + PartitionIsMigratingException(Exception innerException) { + this(RMResources.Gone, innerException, null, null); + } + + PartitionIsMigratingException(String message, + Exception innerException, + HttpHeaders headers, + String requestUri) { + super(String.format("%s: %s", RMResources.Gone, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.GONE, + requestUri); + + setSubStatus(); + } + + private void setSubStatus() { + this.responseHeaders().put( + WFConstants.BackendHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION)); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKey.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKey.java new file mode 100644 index 0000000000000..ff4130e6152da --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKey.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; + +/** + * Represents a partition key value in the Azure Cosmos DB database service. A + * partition key identifies the partition where the document is stored in. + */ +public class PartitionKey { + + private PartitionKeyInternal internalPartitionKey; + + PartitionKey(PartitionKeyInternal partitionKeyInternal) { + this.internalPartitionKey = partitionKeyInternal; + } + + /** + * Constructor. CREATE a new instance of the PartitionKey object. + * + * @param key the value of the partition key. + */ + @SuppressWarnings("serial") + public PartitionKey(final Object key) { + this.internalPartitionKey = PartitionKeyInternal.fromObjectArray(new Object[] { key }, true); + } + + /** + * Create a new instance of the PartitionKey object from a serialized JSON + * partition key. + * + * @param jsonString the JSON string representation of this PartitionKey object. + * @return the PartitionKey instance. + */ + public static PartitionKey fromJsonString(String jsonString) { + return new PartitionKey(PartitionKeyInternal.fromJsonString(jsonString)); + } + + public static PartitionKey None = new PartitionKey(PartitionKeyInternal.None); + + /** + * Serialize the PartitionKey object to a JSON string. + * + * @return the string representation of this PartitionKey object. + */ + public String toString() { + return this.internalPartitionKey.toJson(); + } + + // TODO: make private + public PartitionKeyInternal getInternalPartitionKey() { + return internalPartitionKey; + } + + /** + * Overrides the Equal operator for object comparisons between two instances of + * {@link PartitionKey} + * + * @param other The object to compare with. + * @return True if two object instance are considered equal. + */ + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + + if (this == other) { + return true; + } + + PartitionKey otherKey = Utils.as(other, PartitionKey.class); + return otherKey != null && this.internalPartitionKey.equals(otherKey.internalPartitionKey); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinition.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinition.java new file mode 100644 index 0000000000000..b35ae9eb6562f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinition.java @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a partition key definition in the Azure Cosmos DB database service. A partition key definition specifies which + * document property is used as the partition key in a collection that has multiple partitions. + */ +public final class PartitionKeyDefinition extends JsonSerializable { + private List paths; + private PartitionKind kind; + private PartitionKeyDefinitionVersion version; + private Boolean systemKey; + + /** + * Constructor. Creates a new instance of the PartitionKeyDefinition object. + */ + public PartitionKeyDefinition() { + this.kind(PartitionKind.HASH); + } + + /** + * Constructor. Creates a new instance of the PartitionKeyDefinition object from a + * JSON string. + * + * @param jsonString the JSON string that represents the partition key definition. + */ + PartitionKeyDefinition(String jsonString) { + super(jsonString); + } + + /** + * Sets the partition algorithm used to calculate the partition id given a partition key. + * + * @return the partition algorithm. + */ + public PartitionKind kind() { + if (this.kind == null) { + this.kind = super.getObject(Constants.Properties.PARTITION_KIND, PartitionKind.class, true); + } + + return this.kind; + } + + /** + * Sets the partition algorithm used to calculate the partition id given a partition key. + * + * @param kind the partition algorithm. + * @return this PartitionKeyDefinition. + */ + public PartitionKeyDefinition kind(PartitionKind kind) { + this.kind = kind; + return this; + } + + public PartitionKeyDefinitionVersion version() { + if (this.version == null) { + Object versionObject = super.getObject(Constants.Properties.PARTITION_KEY_DEFINITION_VERSION, Object.class); + if (versionObject == null) { + this.version = null; + } else { + String versionStr = String.valueOf(versionObject); + if (StringUtils.isNumeric(versionStr)) { + this.version = PartitionKeyDefinitionVersion.valueOf(String.format("V%d", Integer.parseInt(versionStr))); + } else { + this.version = !Strings.isNullOrEmpty(versionStr) + ? PartitionKeyDefinitionVersion.valueOf(StringUtils.upperCase(versionStr)) + : null; + } + } + } + + return this.version; + } + + public PartitionKeyDefinition version(PartitionKeyDefinitionVersion version) { + this.version = version; + return this; + } + + /** + * Gets the document property paths for the partition key. + * + * @return the paths to the document properties that form the partition key. + */ + public List paths() { + if (this.paths == null) { + if (super.has(Constants.Properties.PARTITION_KEY_PATHS)) { + paths = super.getList(Constants.Properties.PARTITION_KEY_PATHS, String.class); + } else { + paths = new ArrayList<>(); + } + } + + return paths; + } + + /** + * Sets the document property paths for the partition key. + * + * @param paths the paths to document properties that form the partition key. + * @return this PartitionKeyDefinition. + */ + public PartitionKeyDefinition paths(List paths) { + if (paths == null || paths.size() == 0) { + throw new IllegalArgumentException("paths must not be null or empty."); + } + + this.paths = paths; + return this; + } + + /** + * Indicates if the partition key is generated by the system. + * + * @return the boolean indicating is it is a system key. + */ + Boolean isSystemKey() { + if (this.systemKey == null) { + if (super.has(Constants.Properties.SYSTEM_KEY)) { + this.systemKey = super.getBoolean(Constants.Properties.SYSTEM_KEY); + } else { + this.systemKey = false; + } + } + + return this.systemKey; + } + + PartitionKeyInternal getNonePartitionKeyValue() { + if (this.paths().size() == 0 || this.isSystemKey()) { + return PartitionKeyInternal.Empty; + } else { + return PartitionKeyInternal.UndefinedPartitionKey; + } + } + + @Override + void populatePropertyBag() { + if (this.kind != null) { + super.set(Constants.Properties.PARTITION_KIND, kind.toString()); + } + if (this.paths != null) { + super.set(Constants.Properties.PARTITION_KEY_PATHS, paths); + } + + if (this.version != null) { + super.set(Constants.Properties.PARTITION_KEY_DEFINITION_VERSION, version.toString()); + } + super.populatePropertyBag(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinitionVersion.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinitionVersion.java new file mode 100644 index 0000000000000..296ac803b2f92 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyDefinitionVersion.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Partitioning version. + */ +public enum PartitionKeyDefinitionVersion { + + /** + * Original version of hash partitioning. + */ + V1(1), + + /** + * Enhanced version of hash partitioning - offers better distribution of long partition keys and uses less storage. + * + * This version should be used for any practical purpose, but it is available in newer SDKs only. + */ + V2(2); + + int val; + + PartitionKeyDefinitionVersion(int val) { + this.val = val; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeGoneException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeGoneException.java new file mode 100644 index 0000000000000..cc1e9cc2c340b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeGoneException.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * This exception is thrown when DocumentServiceRequest contains x-ms-documentdb-partitionkeyrangeid + * header and such range id doesn't exist. + *

    + * No retries should be made in this case, as either split or merge might have happened and query/readfeed + * must take appropriate actions. + */ +public class PartitionKeyRangeGoneException extends CosmosClientException { + + public PartitionKeyRangeGoneException() { + this(RMResources.Gone); + } + + public PartitionKeyRangeGoneException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.GONE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + this.setSubstatus(); + } + + public PartitionKeyRangeGoneException(String message) { + this(message, null, null, null); + } + + PartitionKeyRangeGoneException(String message, Exception innerException) { + this(message, innerException, null, null); + } + + PartitionKeyRangeGoneException(Exception innerException) { + this(RMResources.Gone, innerException, null, null); + } + + + public PartitionKeyRangeGoneException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.GONE, requestUriString); + this.setSubstatus(); + } + + PartitionKeyRangeGoneException(String message, Exception innerException, HttpHeaders headers, String requestUriString) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.GONE, requestUriString); + this.setSubstatus(); + } + + private void setSubstatus() { + this.responseHeaders().put(WFConstants.BackendHeaders.SUB_STATUS, Integer.toString(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeIsSplittingException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeIsSplittingException.java new file mode 100644 index 0000000000000..40c596fd31035 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKeyRangeIsSplittingException.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class PartitionKeyRangeIsSplittingException extends CosmosClientException { + + private static final long serialVersionUID = 1L; + + public PartitionKeyRangeIsSplittingException() { + this(RMResources.Gone); + } + + public PartitionKeyRangeIsSplittingException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.GONE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + PartitionKeyRangeIsSplittingException(String msg) { + super(HttpConstants.StatusCodes.GONE, msg); + setSubStatus(); + } + + PartitionKeyRangeIsSplittingException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.GONE, resourceAddress); + setSubStatus(); + } + + public PartitionKeyRangeIsSplittingException(String message, HttpHeaders headers, String requestUri) { + this(message, null, headers, requestUri); + } + + PartitionKeyRangeIsSplittingException(Exception innerException) { + this(RMResources.Gone, innerException, null, null); + } + + PartitionKeyRangeIsSplittingException(String message, + Exception innerException, + HttpHeaders headers, + String requestUri) { + super(String.format("%s: %s", RMResources.Gone, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.GONE, + requestUri); + + setSubStatus(); + } + + private void setSubStatus() { + this.responseHeaders().put( + WFConstants.BackendHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.COMPLETING_SPLIT)); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKind.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKind.java new file mode 100644 index 0000000000000..62aac4aa3fcd1 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PartitionKind.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * Specifies the partition scheme for an multiple-partitioned collection in the Azure Cosmos DB database service. + */ +public enum PartitionKind { + /** + * The Partition of a document is calculated based on the hash value of the PartitionKey. + */ + HASH; + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PermissionMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PermissionMode.java new file mode 100644 index 0000000000000..33b40d376f280 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PermissionMode.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * Enumeration specifying applicability of permission in the Azure Cosmos DB database service. + */ +public enum PermissionMode { + /** + * Permission applicable for read operations only. + */ + READ(0x1), + + /** + * Permission applicable for all operations. + */ + ALL(0x2); + + private int value; + + PermissionMode(int value) { + this.value = value; + } + + /** + * Gets the numerical value of the permission mode. + * + * @return the numerical value. + */ + public int getValue() { + return value; + } + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PreconditionFailedException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PreconditionFailedException.java new file mode 100644 index 0000000000000..d1bffd27c4f12 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/PreconditionFailedException.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class PreconditionFailedException extends CosmosClientException { + + private static final long serialVersionUID = 1L; + + PreconditionFailedException() { + this(RMResources.PreconditionFailed); + } + + public PreconditionFailedException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.PRECONDITION_FAILED, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + PreconditionFailedException(String msg) { + super(HttpConstants.StatusCodes.PRECONDITION_FAILED, msg); + } + + PreconditionFailedException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.PRECONDITION_FAILED, resourceAddress); + } + + public PreconditionFailedException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + PreconditionFailedException(Exception innerException) { + this(RMResources.PreconditionFailed, innerException, null, null); + } + + PreconditionFailedException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format("%s: %s", RMResources.PreconditionFailed, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.PRECONDITION_FAILED, + requestUriString); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RangeIndex.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RangeIndex.java new file mode 100644 index 0000000000000..a27b4ca0fa583 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RangeIndex.java @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a range index in the Azure Cosmos DB database service. + */ +public final class RangeIndex extends Index { + + /** + * Initializes a new instance of the RangeIndex class with specified DataType. + *

    + * Here is an example to instantiate RangeIndex class passing in the DataType: + *

    +     * {@code
    +     *
    +     * RangeIndex rangeIndex = new RangeIndex(DataType.NUMBER);
    +     *
    +     * }
    +     * 
    + * + * @param dataType the data type. + */ + public RangeIndex(DataType dataType) { + super(IndexKind.RANGE); + this.dataType(dataType); + } + + /** + * Initializes a new instance of the RangeIndex class with specified DataType and precision. + *
    +     * {@code
    +     *
    +     * RangeIndex rangeIndex = new RangeIndex(DataType.NUMBER, -1);
    +     *
    +     * }
    +     * 
    + * @param dataType the data type of the RangeIndex + * @param precision the precision of the RangeIndex + */ + public RangeIndex(DataType dataType, int precision) { + super(IndexKind.RANGE); + this.dataType(dataType); + this.precision(precision); + } + + /** + * Initializes a new instance of the RangeIndex class with json string. + * + * @param jsonString the json string that represents the index. + */ + RangeIndex(String jsonString) { + super(jsonString, IndexKind.RANGE); + if (this.dataType() == null) { + throw new IllegalArgumentException("The jsonString doesn't contain a valid 'dataType'."); + } + } + + /** + * Gets data type. + * + * @return the data type. + */ + public DataType dataType() { + DataType result = null; + try { + result = DataType.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.DATA_TYPE))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID index dataType value {}.", super.getString(Constants.Properties.DATA_TYPE)); + } + return result; + } + + /** + * Sets data type. + * + * @param dataType the data type. + * @return the RangeIndex. + */ + public RangeIndex dataType(DataType dataType) { + super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + return this; + } + + /** + * Gets precision. + * + * @return the precision. + */ + public int precision() { + return super.getInt(Constants.Properties.PRECISION); + } + + /** + * Sets precision. + * + * @param precision the precision. + * @return the RangeIndex. + */ + public RangeIndex precision(int precision) { + super.set(Constants.Properties.PRECISION, precision); + return this; + } + + boolean hasPrecision() { + return super.has(Constants.Properties.PRECISION); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestEntityTooLargeException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestEntityTooLargeException.java new file mode 100644 index 0000000000000..ae4b889f81e77 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestEntityTooLargeException.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class RequestEntityTooLargeException extends CosmosClientException { + private static final long serialVersionUID = 1L; + + RequestEntityTooLargeException() { + this(RMResources.RequestEntityTooLarge); + } + + public RequestEntityTooLargeException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + RequestEntityTooLargeException(String msg) { + super(HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE, msg); + } + + RequestEntityTooLargeException(String msg, String resourceAddress) { + super(msg, null, null, HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE, resourceAddress); + } + + public RequestEntityTooLargeException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + RequestEntityTooLargeException(Exception innerException) { + this(RMResources.RequestEntityTooLarge, innerException, null, null); + } + + RequestEntityTooLargeException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format(RMResources.RequestEntityTooLarge, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE, + requestUriString); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestRateTooLargeException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestRateTooLargeException.java new file mode 100644 index 0000000000000..af5e25c77da89 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestRateTooLargeException.java @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class RequestRateTooLargeException extends CosmosClientException { + + public RequestRateTooLargeException() { + this(RMResources.TooManyRequests, null); + } + + public RequestRateTooLargeException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.NOTFOUND, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + RequestRateTooLargeException(String message, URI requestUri) { + this(message, null, null, requestUri); + } + + RequestRateTooLargeException(String message, + Exception innerException, + URI requestUri) { + this(message, innerException, null, requestUri); + } + + RequestRateTooLargeException(Exception innerException) { + this(RMResources.TooManyRequests, innerException, null, null); + } + + public RequestRateTooLargeException(String message, HttpHeaders headers, URI requestUri) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.TOO_MANY_REQUESTS, requestUri != null ? requestUri.toString() : null); + } + + RequestRateTooLargeException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.TOO_MANY_REQUESTS, requestUriString); + } + + RequestRateTooLargeException(String message, + Exception innerException, + HttpHeaders headers, + URI requestUri) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.TOO_MANY_REQUESTS, requestUri != null ? requestUri.toString() : null); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestTimeoutException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestTimeoutException.java new file mode 100644 index 0000000000000..5acea29c958c0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RequestTimeoutException.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class RequestTimeoutException extends CosmosClientException { + + public RequestTimeoutException() { + this(RMResources.RequestTimeout, null); + } + + public RequestTimeoutException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.REQUEST_TIMEOUT, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + public RequestTimeoutException(String message, URI requestUri) { + this(message, null, null, requestUri); + } + + RequestTimeoutException(String message, + Exception innerException, + URI requestUri, + String localIpAddress) { + this(message(localIpAddress, message), innerException, null, requestUri); + } + + RequestTimeoutException(Exception innerException) { + this(RMResources.Gone, innerException, (HttpHeaders) null, null); + } + + public RequestTimeoutException(String message, HttpHeaders headers, URI requestUrl) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.REQUEST_TIMEOUT, requestUrl != null ? requestUrl.toString() : null); + } + + RequestTimeoutException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.REQUEST_TIMEOUT, requestUriString); + } + + RequestTimeoutException(String message, + Exception innerException, + HttpHeaders headers, + URI requestUrl) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.REQUEST_TIMEOUT, requestUrl != null ? requestUrl.toString() : null); + } + + private static String message(String localIP, String baseMessage) { + if (!Strings.isNullOrEmpty(localIP)) { + return String.format( + RMResources.ExceptionMessageAddIpAddress, + baseMessage, + localIP); + } + + return baseMessage; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Resource.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Resource.java new file mode 100644 index 0000000000000..99ad792972083 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/Resource.java @@ -0,0 +1,225 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.lang3.StringUtils; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +/** + * Represents the base resource in the Azure Cosmos DB database service. + */ +public class Resource extends JsonSerializable { + private String altLink; + + static void validateResource(Resource resource) { + if (!StringUtils.isEmpty(resource.id())) { + if (resource.id().indexOf('/') != -1 || resource.id().indexOf('\\') != -1 || + resource.id().indexOf('?') != -1 || resource.id().indexOf('#') != -1) { + throw new IllegalArgumentException("Id contains illegal chars."); + } + + if (resource.id().endsWith(" ")) { + throw new IllegalArgumentException("Id ends with a space."); + } + } + } + + /** + * Copy constructor. + * + * @param resource resource to by copied. + */ + protected Resource(Resource resource) { + this.id(resource.id()); + this.resourceId(resource.resourceId()); + this.selfLink(resource.selfLink()); + this.altLink(resource.altLink()); + this.timestamp(resource.timestamp()); + this.etag(resource.etag()); + } + + /** + * Constructor. + */ + protected Resource() { + super(); + } + + /** + * Constructor. + * + * @param objectNode the {@link ObjectNode} that represent the + * {@link JsonSerializable} + */ + Resource(ObjectNode objectNode) { + super(objectNode); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the resource. + * @param objectMapper the custom object mapper + */ + Resource(String jsonString, ObjectMapper objectMapper) { + // TODO: Made package private due to #153. #171 adding custom serialization options back. + super(jsonString, objectMapper); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the resource. + */ + protected Resource(String jsonString) { + super(jsonString); + } + + /** + * Gets the name of the resource. + * + * @return the name of the resource. + */ + public String id() { + return super.getString(Constants.Properties.ID); + } + + /** + * Sets the name of the resource. + * + * @param id the name of the resource. + * @return the resource. + */ + public Resource id(String id) { + super.set(Constants.Properties.ID, id); + return this; + } + + /** + * Gets the ID associated with the resource. + * + * @return the ID associated with the resource. + */ + public String resourceId() { + return super.getString(Constants.Properties.R_ID); + } + + // TODO: make private + /** + * Set the ID associated with the resource. + * + * @param resourceId the ID associated with the resource. + * @return the resource. + */ + public Resource resourceId(String resourceId) { + super.set(Constants.Properties.R_ID, resourceId); + return this; + } + + /** + * Get the self-link associated with the resource. + * + * @return the self link. + */ + public String selfLink() { + return super.getString(Constants.Properties.SELF_LINK); + } + + /** + * Set the self-link associated with the resource. + * + * @param selfLink the self link. + */ + Resource selfLink(String selfLink) { + super.set(Constants.Properties.SELF_LINK, selfLink); + return this; + } + + /** + * Get the last modified timestamp associated with the resource. + * + * @return the timestamp. + */ + public OffsetDateTime timestamp() { + Long seconds = super.getLong(Constants.Properties.LAST_MODIFIED); + if (seconds == null) + return null; + return OffsetDateTime.ofInstant(Instant.ofEpochSecond(seconds.longValue()), ZoneOffset.UTC); + } + + /** + * Set the last modified timestamp associated with the resource. + * + * @param timestamp the timestamp. + */ + Resource timestamp(OffsetDateTime timestamp) { + long seconds = timestamp.toEpochSecond(); + super.set(Constants.Properties.LAST_MODIFIED, seconds); + return this; + } + + /** + * Get the entity tag associated with the resource. + * + * @return the e tag. + */ + public String etag() { + return super.getString(Constants.Properties.E_TAG); + } + + /** + * Set the self-link associated with the resource. + * + * @param eTag the e tag. + */ + Resource etag(String eTag) { + super.set(Constants.Properties.E_TAG, eTag); + return this; + } + + /** + * Sets the alt-link associated with the resource from the Azure Cosmos DB + * service. + * + * @param altLink + */ + Resource altLink(String altLink) { + this.altLink = altLink; + return this; + } + + /** + * Gets the alt-link associated with the resource from the Azure Cosmos DB + * service. + */ + String altLink() { + return this.altLink; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryOptions.java new file mode 100644 index 0000000000000..e560f03dc2195 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryOptions.java @@ -0,0 +1,120 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Encapsulates retry options in the Azure Cosmos DB database service. + */ +public class RetryOptions { + private int maxRetryAttemptsOnThrottledRequests; + private int maxRetryWaitTimeInSeconds; + + /** + * Creates a new instance of the RetryOptions class and initializes all + * properties to default values. + */ + public RetryOptions() { + this.maxRetryAttemptsOnThrottledRequests = 9; + this.maxRetryWaitTimeInSeconds = 30; + } + + /** + * Gets the maximum number of retries in the case where the request fails + * because the service has applied rate limiting on the client. + * + * @return the maximum number of retries. + */ + public int maxRetryAttemptsOnThrottledRequests() { + return this.maxRetryAttemptsOnThrottledRequests; + } + + /** + * Sets the maximum number of retries in the case where the request fails + * because the service has applied rate limiting on the client. + *

    + * When a client is sending requests faster than the allowed rate, the + * service will return HttpStatusCode 429 (Too Many Request) to throttle the + * client. The current implementation in the SDK will then wait for the + * amount of time the service tells it to wait and retry after the time has + * elapsed. + *

    + * The default value is 9. This means in the case where the request is + * throttled, the same request will be issued for a maximum of 10 times to + * the server before an error is returned to the application. + * + * @param maxRetryAttemptsOnThrottledRequests the max number of retry attempts on failed requests due to a + * throttle error. + * @return the RetryOptions. + */ + public RetryOptions maxRetryAttemptsOnThrottledRequests(int maxRetryAttemptsOnThrottledRequests) { + if (maxRetryAttemptsOnThrottledRequests < 0) { + throw new IllegalArgumentException("maxRetryAttemptsOnThrottledRequests value must be a positive integer."); + } + + this.maxRetryAttemptsOnThrottledRequests = maxRetryAttemptsOnThrottledRequests; + return this; + } + + /** + * Gets the maximum retry time in seconds. + * + * @return the maximum retry time in seconds. + */ + public int maxRetryWaitTimeInSeconds() { + return this.maxRetryWaitTimeInSeconds; + } + + /** + * Sets the maximum retry time in seconds. + *

    + * When a request fails due to a throttle error, the service sends back a + * response that contains a value indicating the client should not retry + * before the time period has elapsed (Retry-After). The MaxRetryWaitTime + * flag allows the application to set a maximum wait time for all retry + * attempts. If the cumulative wait time exceeds the MaxRetryWaitTime, the + * SDK will stop retrying and return the error to the application. + *

    + * The default value is 30 seconds. + * + * @param maxRetryWaitTimeInSeconds the maximum number of seconds a request will be retried. + * @return the RetryOptions. + */ + public RetryOptions maxRetryWaitTimeInSeconds(int maxRetryWaitTimeInSeconds) { + if (maxRetryWaitTimeInSeconds < 0 || maxRetryWaitTimeInSeconds > Integer.MAX_VALUE / 1000) { + throw new IllegalArgumentException( + "value must be a positive integer between the range of 0 to " + Integer.MAX_VALUE / 1000); + } + + this.maxRetryWaitTimeInSeconds = maxRetryWaitTimeInSeconds; + return this; + } + + @Override + public String toString() { + return "RetryOptions{" + + "maxRetryAttemptsOnThrottledRequests=" + maxRetryAttemptsOnThrottledRequests + + ", maxRetryWaitTimeInSeconds=" + maxRetryWaitTimeInSeconds + + '}'; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryWithException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryWithException.java new file mode 100644 index 0000000000000..de0f66c62ca3b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/RetryWithException.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class RetryWithException extends CosmosClientException { + + public RetryWithException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.RETRY_WITH, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + RetryWithException(String message, URI requestUri) { + this(message, null, null, requestUri); + } + + RetryWithException(String message, + Exception innerException, + URI requestUri) { + this(message, innerException, null, requestUri); + } + + public RetryWithException(String message, HttpHeaders headers, URI requestUri) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.RETRY_WITH, requestUri != null ? requestUri.toString() : null); + } + + RetryWithException(String message, HttpHeaders headers, String requestUriString) { + super(message, null, HttpUtils.asMap(headers), HttpConstants.StatusCodes.RETRY_WITH, requestUriString); + } + + RetryWithException(String message, + Exception innerException, + HttpHeaders headers, + URI requestUri) { + super(message, innerException, HttpUtils.asMap(headers), HttpConstants.StatusCodes.RETRY_WITH, requestUri != null ? requestUri.toString() : null); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SerializationFormattingPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SerializationFormattingPolicy.java new file mode 100644 index 0000000000000..fde6c6334ee6d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SerializationFormattingPolicy.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * The formatting policy associated with JSON serialization in the Azure Cosmos DB database service. + */ +public enum SerializationFormattingPolicy { + + /** + * No additional formatting required. + */ + NONE, + + /** + * Indent the fields appropriately. + */ + INDENTED +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ServiceUnavailableException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ServiceUnavailableException.java new file mode 100644 index 0000000000000..39e712676ff3a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/ServiceUnavailableException.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class ServiceUnavailableException extends CosmosClientException { + ServiceUnavailableException() { + this(RMResources.ServiceUnavailable); + } + + public ServiceUnavailableException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.NOTFOUND, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + ServiceUnavailableException(String message) { + this(message, null, null, null); + } + + ServiceUnavailableException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + public ServiceUnavailableException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + ServiceUnavailableException(Exception innerException) { + this(RMResources.ServiceUnavailable, innerException, null, null); + } + + public ServiceUnavailableException(String message, + Exception innerException, + HttpHeaders headers, + String requestUriString) { + super(String.format("%s: %s", RMResources.ServiceUnavailable, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.SERVICE_UNAVAILABLE, + requestUriString); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialIndex.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialIndex.java new file mode 100644 index 0000000000000..77bb0fa3b6b6a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialIndex.java @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a spatial index in the Azure Cosmos DB database service. + */ +final class SpatialIndex extends Index { + + /** + * Initializes a new instance of the SpatialIndex class. + *

    + * Here is an example to instantiate SpatialIndex class passing in the DataType + *

    +     * {@code
    +     *
    +     * SpatialIndex spatialIndex = new SpatialIndex(DataType.POINT);
    +     *
    +     * }
    +     * 
    + * + * @param dataType specifies the target data type for the index path specification. + */ + SpatialIndex(DataType dataType) { + super(IndexKind.SPATIAL); + this.dataType(dataType); + } + + /** + * Initializes a new instance of the SpatialIndex class. + * + * @param jsonString the json string that represents the index. + */ + SpatialIndex(String jsonString) { + super(jsonString, IndexKind.SPATIAL); + if (this.dataType() == null) { + throw new IllegalArgumentException("The jsonString doesn't contain a valid 'dataType'."); + } + } + + /** + * Gets data type. + * + * @return the data type. + */ + public DataType dataType() { + DataType result = null; + try { + result = DataType.valueOf(StringUtils.upperCase(super.getString(Constants.Properties.DATA_TYPE))); + } catch (IllegalArgumentException e) { + this.getLogger().warn("INVALID index dataType value {}.", super.getString(Constants.Properties.DATA_TYPE)); + } + return result; + } + + /** + * Sets data type. + * + * @param dataType the data type. + * @return the SpatialIndex. + */ + public SpatialIndex dataType(DataType dataType) { + super.set(Constants.Properties.DATA_TYPE, dataType.toString()); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialSpec.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialSpec.java new file mode 100644 index 0000000000000..6c20175b6511b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialSpec.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class SpatialSpec extends JsonSerializable { + + private List spatialTypes; + + /** + * Constructor. + */ + public SpatialSpec() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the included path. + */ + SpatialSpec(String jsonString) { + super(jsonString); + } + + + /** + * Gets path. + * + * @return the path. + */ + public String path() { + return super.getString(Constants.Properties.PATH); + } + + /** + * Sets path. + * + * @param path the path. + * @return the SpatialSpec. + */ + public SpatialSpec path(String path) { + super.set(Constants.Properties.PATH, path); + return this; + } + + /** + * Gets the collection of spatial types. + * + * @return the collection of spatial types. + */ + public List spatialTypes() { + if (this.spatialTypes == null) { + this.spatialTypes = super.getList(Constants.Properties.TYPES, SpatialType.class, true); + + if (this.spatialTypes == null) { + this.spatialTypes = new ArrayList(); + } + } + + return this.spatialTypes; + } + + /** + * Sets the collection of spatial types. + * + * @param spatialTypes the collection of spatial types. + * @return the SpatialSpec. + */ + public SpatialSpec spatialTypes(List spatialTypes) { + this.spatialTypes = spatialTypes; + Collection spatialTypeNames = new ArrayList(); + for (SpatialType spatialType : this.spatialTypes) { + spatialTypeNames.add(spatialType.toString()); + } + super.set(Constants.Properties.TYPES, spatialTypeNames); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialType.java new file mode 100644 index 0000000000000..cd53b197c4378 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SpatialType.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.WordUtils; + +/** + * Defines the target data type of an index path specification in the Azure Cosmos DB service. + * + */ +public enum SpatialType { + /** + * Represent a point data type. + */ + POINT, + + /** + * Represent a line string data type. + */ + LINE_STRING, + + /** + * Represent a polygon data type. + */ + POLYGON, + + /** + * Represent a multi-polygon data type. + */ + MULTI_POLYGON; + + @Override + public String toString() { + return StringUtils.remove(WordUtils.capitalizeFully(this.name(), '_'), '_'); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameter.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameter.java new file mode 100644 index 0000000000000..e5da14d40a873 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameter.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +/** + * Represents a SQL parameter in the SqlQuerySpec used for queries in the Azure Cosmos DB database service. + */ +public final class SqlParameter extends JsonSerializable { + + + /** + * Initializes a new instance of the SqlParameter class. + */ + public SqlParameter() { + super(); + } + + /** + * Initializes a new instance of the SqlParameter class with the name and value of the parameter. + * + * @param name the name of the parameter. + * @param value the value of the parameter. + */ + public SqlParameter(String name, Object value) { + super(); + this.name(name); + this.value(value); + } + + /** + * Gets the name of the parameter. + * + * @return the name of the parameter. + */ + public String name() { + return super.getString("name"); + } + + /** + * Sets the name of the parameter. + * + * @param name the name of the parameter. + * @return the SqlParameter. + */ + public SqlParameter name(String name) { + super.set("name", name); + return this; + } + + /** + * Gets the value of the parameter. + * + * @param c the class of the parameter value. + * @param the type of the parameter + * @return the value of the parameter. + */ + public Object value(Class c) { + return super.getObject("value", c); + } + + /** + * Sets the value of the parameter. + * + * @param value the value of the parameter. + * @return the SqlParameter. + */ + public SqlParameter value(Object value) { + super.set("value", value); + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameterList.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameterList.java new file mode 100644 index 0000000000000..ff1d9620f00cc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlParameterList.java @@ -0,0 +1,187 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +/** + * Represents a collection of SQL parameters to for a SQL query in the Azure Cosmos DB database service. + */ +public final class SqlParameterList implements List { + + private List parameters; + + /** + * Initializes a new instance of the SqlParameterList class. + */ + public SqlParameterList() { + this.parameters = new ArrayList(); + } + + /** + * Initializes a new instance of the SqlParameterList class from an array of parameters. + * + * @param parameters the array of parameters. + */ + public SqlParameterList(SqlParameter... parameters) { + if (parameters == null) { + throw new IllegalArgumentException("parameters"); + } + + this.parameters = Arrays.asList(parameters); + } + + /** + * Initializes a new instance of the SqlParameterList class from a collection of parameters. + * + * @param parameters the collection of parameters. + */ + public SqlParameterList(Collection parameters) { + if (parameters == null) { + throw new IllegalArgumentException("parameters"); + } + + this.parameters = new ArrayList(parameters); + } + + @Override + public boolean add(SqlParameter parameter) { + return this.parameters.add(parameter); + } + + @Override + public boolean addAll(Collection parameters) { + return this.parameters.addAll(parameters); + } + + @Override + public boolean addAll(int index, Collection c) { + return this.parameters.addAll(index, c); + } + + @Override + public void clear() { + this.parameters.clear(); + } + + @Override + public SqlParameter get(int index) { + return this.parameters.get(index); + } + + @Override + public SqlParameter set(int index, SqlParameter element) { + return this.parameters.set(index, element); + } + + @Override + public void add(int index, SqlParameter element) { + this.parameters.add(index, element); + } + + @Override + public SqlParameter remove(int index) { + return this.parameters.remove(index); + } + + @Override + public int indexOf(Object o) { + return this.parameters.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return this.parameters.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return this.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return this.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return this.parameters.subList(fromIndex, toIndex); + } + + @Override + public boolean contains(Object parameter) { + return this.parameters.contains(parameter); + } + + @Override + public boolean containsAll(Collection parameters) { + return this.parameters.containsAll(parameters); + } + + @Override + public boolean isEmpty() { + return this.parameters.isEmpty(); + } + + @Override + public Iterator iterator() { + return this.parameters.iterator(); + } + + @Override + public boolean remove(Object parameter) { + return this.parameters.remove(parameter); + } + + @Override + public boolean removeAll(Collection parameters) { + return this.parameters.removeAll(parameters); + } + + @Override + public boolean retainAll(Collection parameters) { + return this.parameters.retainAll(parameters); + } + + @Override + public int size() { + return this.parameters.size(); + } + + @Override + public Object[] toArray() { + return this.parameters.toArray(); + } + + @Override + public T[] toArray(T[] parameters) { + return this.parameters.toArray(parameters); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlQuerySpec.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlQuerySpec.java new file mode 100644 index 0000000000000..e5a6805e9e1c7 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/SqlQuerySpec.java @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * Represents a SQL query in the Azure Cosmos DB database service. + */ +public final class SqlQuerySpec extends JsonSerializable { + + private SqlParameterList parameters; + + /** + * Initializes a new instance of the SqlQuerySpec class. + */ + public SqlQuerySpec() { + super(); + } + + /** + * Initializes a new instance of the SqlQuerySpec class with the text of the + * query. + * + * @param queryText + * the query text. + */ + public SqlQuerySpec(String queryText) { + super(); + this.queryText(queryText); + } + + /** + * Initializes a new instance of the SqlQuerySpec class with the text of the + * query and parameters. + * + * @param queryText the query text. + * @param parameters the query parameters. + */ + public SqlQuerySpec(String queryText, SqlParameterList parameters) { + super(); + this.queryText(queryText); + this.parameters = parameters; + } + + /** + * Gets the text of the query. + * + * @return the query text. + */ + public String queryText() { + return super.getString("query"); + } + + /** + * Sets the text of the query. + * + * @param queryText + * the query text. + * @return the SqlQuerySpec. + */ + public SqlQuerySpec queryText(String queryText) { + super.set("query", queryText); + return this; + } + + /** + * Gets the collection of query parameters. + * + * @return the query parameters. + */ + public SqlParameterList parameters() { + if (this.parameters == null) { + Collection sqlParameters = super.getCollection("parameters", SqlParameter.class); + if (sqlParameters == null) { + sqlParameters = new ArrayList(); + } + + this.parameters = new SqlParameterList(sqlParameters); + } + + return this.parameters; + } + + /** + * Sets the collection of query parameters. + * + * @param parameters + * the query parameters. + * @return the SqlQuerySpec. + */ + public SqlQuerySpec parameters(SqlParameterList parameters) { + this.parameters = parameters; + return this; + } + + @Override + void populatePropertyBag() { + boolean defaultParameters = (this.parameters != null && this.parameters.size() != 0); + + if (defaultParameters) { + super.set("parameters", this.parameters); + } else { + super.remove("parameters"); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TokenResolver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TokenResolver.java new file mode 100644 index 0000000000000..67fc295d87861 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TokenResolver.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import java.util.Map; + +/** + * This interface is for client side implementation, which can be used for initializing + * AsyncDocumentClient without passing master key, resource token and permission feed.
    + *
    + * Each time the SDK create request for CosmosDB, authorization token is generated based on that + * request at client side which enables creation of one AsyncDocumentClient per application shared across various users + * with different resource permissions. + */ +@FunctionalInterface +public interface TokenResolver { + + /** + * This method will consume the request information and based on that it will generate the authorization token. + * @param properties the user properties. + * @param requestVerb Request verb i.e. GET, POST, PUT etc. + * @param resourceIdOrFullName ResourceID or resource full name. + * @param resourceType Resource type i.e. Database, DocumentCollection, Document etc. + * @return The authorization token. + */ + public String getAuthorizationToken(String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties); + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerOperation.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerOperation.java new file mode 100644 index 0000000000000..e7d624655db0f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerOperation.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * Specifies the operations on which a trigger should be executed in the Azure Cosmos DB database service. + */ +public enum TriggerOperation { + /** + * ALL operations. + */ + ALL(0x0), + + /** + * CREATE operations only. + */ + CREATE(0x1), + + /** + * UPDATE operations only. + */ + UPDATE(0x2), + + /** + * DELETE operations only. + */ + DELETE(0x3), + + /** + * REPLACE operations only. + */ + REPLACE(0x4); + + private int value; + + TriggerOperation(int value) { + this.value = value; + } + + /** + * Gets the numerical value of the trigger operation. + * + * @return the numerical value. + */ + public int getValue() { + return value; + } + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerType.java new file mode 100644 index 0000000000000..9717d7a01ab7b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/TriggerType.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.text.WordUtils; + +/** + * The trigger type in the Azure Cosmos DB database service. + */ +public enum TriggerType { + /** + * Trigger should be executed before the associated operation(s). + */ + PRE(0x0), + + /** + * Trigger should be executed after the associated operation(s). + */ + POST(0x1); + + private int value; + + TriggerType(int value) { + this.value = value; + } + + /** + * Gets the numerical value of the trigger type. + * + * @return the numerical value. + */ + public int getValue() { + return value; + } + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UnauthorizedException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UnauthorizedException.java new file mode 100644 index 0000000000000..69d77ceb7d0fb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UnauthorizedException.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; + +import java.net.URI; +import java.util.Map; + +public class UnauthorizedException extends CosmosClientException { + + UnauthorizedException() { + this(RMResources.Unauthorized); + } + + public UnauthorizedException(CosmosError cosmosError, long lsn, String partitionKeyRangeId, Map responseHeaders) { + super(HttpConstants.StatusCodes.UNAUTHORIZED, cosmosError, responseHeaders); + BridgeInternal.setLSN(this, lsn); + BridgeInternal.setPartitionKeyRangeId(this, partitionKeyRangeId); + } + + UnauthorizedException(String message) { + this(message, null, null, null); + } + + UnauthorizedException(String message, HttpHeaders headers, String requestUriString) { + this(message, null, headers, requestUriString); + } + + public UnauthorizedException(String message, HttpHeaders headers, URI requestUri) { + this(message, headers, requestUri != null ? requestUri.toString() : null); + } + + UnauthorizedException(Exception innerException) { + this(RMResources.Unauthorized, innerException, null, null); + } + + UnauthorizedException(String message, + Exception innerException, + HttpHeaders headers, + String requestUri) { + super(String.format("%s: %s", RMResources.Unauthorized, message), + innerException, + HttpUtils.asMap(headers), + HttpConstants.StatusCodes.UNAUTHORIZED, + requestUri); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKey.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKey.java new file mode 100644 index 0000000000000..1b33988b52dd5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKey.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2016 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Represents a unique key on that enforces uniqueness constraint on documents in the collection in the Azure Cosmos DB service. + * + * 1) For partitioned collections, the value of partition key is implicitly a part of each unique key. + * 2) Uniqueness constraint is also enforced for missing values. + * For instance, if unique key policy defines a unique key with single property path, there could be only one document that has missing value for this property. + * @see UniqueKeyPolicy + */ +public class UniqueKey extends JsonSerializable { + private List paths; + + public UniqueKey() { + super(); + } + + UniqueKey(String jsonString) { + super(jsonString); + } + + /** + * Gets the paths, a set of which must be unique for each document in the Azure Cosmos DB service. + * + * The paths to enforce uniqueness on. Each path is a rooted path of the unique property in the document, + * such as "/name/first". + * + * @return the unique paths. + */ + public Collection paths() { + if (this.paths == null) { + this.paths = super.getList(Constants.Properties.PATHS, String.class); + + if (this.paths == null) { + this.paths = new ArrayList(); + } + } + + return this.paths; + } + + + /** + * Sets the paths, a set of which must be unique for each document in the Azure Cosmos DB service. + * + * The paths to enforce uniqueness on. Each path is a rooted path of the unique property in the document, + * such as "/name/first". + * + * @param paths the unique paths. + * @return the Unique Key. + */ + public UniqueKey paths(List paths) { + this.paths = paths; + return this; + } + + @Override + void populatePropertyBag() { + if (paths != null) { + super.set(Constants.Properties.PATHS, paths); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKeyPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKeyPolicy.java new file mode 100644 index 0000000000000..4435493c6b565 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/UniqueKeyPolicy.java @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Constants; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Represents the unique key policy configuration for specifying uniqueness constraints on documents in the + * collection in the Azure Cosmos DB service. + */ +public class UniqueKeyPolicy extends JsonSerializable { + private List uniqueKeys; + + public UniqueKeyPolicy() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the Unique Key policy. + */ + UniqueKeyPolicy(String jsonString) { + super(jsonString); + } + + /** + * Gets or sets collection of {@link UniqueKey} that guarantee uniqueness of documents in collection + * in the Azure Cosmos DB service. + * + * @return the unique keys. + */ + public Collection uniqueKeys() { + if (this.uniqueKeys == null) { + this.uniqueKeys = super.getList(Constants.Properties.UNIQUE_KEYS, UniqueKey.class); + if (this.uniqueKeys == null) { + this.uniqueKeys = new ArrayList<>(); + } + } + return this.uniqueKeys; + } + + public UniqueKeyPolicy uniqueKeys(List uniqueKeys) { + if (uniqueKeys == null) { + throw new IllegalArgumentException("uniqueKeys cannot be null."); + } + this.uniqueKeys = uniqueKeys; + return this; + } + + @Override + void populatePropertyBag() { + if (this.uniqueKeys != null) { + for(UniqueKey uniqueKey: uniqueKeys) { + uniqueKey.populatePropertyBag(); + } + super.set(Constants.Properties.UNIQUE_KEYS, uniqueKeys); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AsyncDocumentClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AsyncDocumentClient.java new file mode 100644 index 0000000000000..0c0f0d5808a53 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AsyncDocumentClient.java @@ -0,0 +1,1339 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.TokenResolver; +import reactor.core.publisher.Flux; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +/** + * Provides a client-side logical representation of the Azure Cosmos DB + * database service. This async client is used to configure and execute requests + * against the service. + * + *

    + * {@link AsyncDocumentClient} async APIs return project reactor's {@link + * Flux}, and so you can use project reactor {@link Flux} functionality. + * The async {@link Flux} based APIs perform the requested operation only after + * subscription. + * + *

    + * The service client encapsulates the endpoint and credentials used to access + * the Cosmos DB service. + *

    + * To instantiate you can use the {@link Builder} + *

    + * {@code
    + * ConnectionPolicy connectionPolicy = new ConnectionPolicy();
    + * connectionPolicy.connectionMode(ConnectionMode.DIRECT);
    + * AsyncDocumentClient client = new AsyncDocumentClient.Builder()
    + *         .withServiceEndpoint(serviceEndpoint)
    + *         .withMasterKeyOrResourceToken(masterKey)
    + *         .withConnectionPolicy(connectionPolicy)
    + *         .withConsistencyLevel(ConsistencyLevel.SESSION)
    + *         .build();
    + * }
    + * 
    + */ +public interface AsyncDocumentClient { + + /** + * Helper class to build {@link AsyncDocumentClient} instances + * as logical representation of the Azure Cosmos DB database service. + * + *
    +     * {@code
    +     * ConnectionPolicy connectionPolicy = new ConnectionPolicy();
    +     * connectionPolicy.connectionMode(ConnectionMode.DIRECT);
    +     * AsyncDocumentClient client = new AsyncDocumentClient.Builder()
    +     *         .withServiceEndpoint(serviceEndpoint)
    +     *         .withMasterKeyOrResourceToken(masterKey)
    +     *         .withConnectionPolicy(connectionPolicy)
    +     *         .withConsistencyLevel(ConsistencyLevel.SESSION)
    +     *         .build();
    +     * }
    +     * 
    + */ + class Builder { + + Configs configs = new Configs(); + ConnectionPolicy connectionPolicy; + ConsistencyLevel desiredConsistencyLevel; + List permissionFeed; + String masterKeyOrResourceToken; + URI serviceEndpoint; + TokenResolver tokenResolver; + + public Builder withServiceEndpoint(String serviceEndpoint) { + try { + this.serviceEndpoint = new URI(serviceEndpoint); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getMessage()); + } + return this; + } + + /** + * New method withMasterKeyOrResourceToken will take either master key or resource token + * and perform authentication for accessing resource. + * + * @param masterKeyOrResourceToken MasterKey or resourceToken for authentication. + * @return current Builder. + * @deprecated use {@link #withMasterKeyOrResourceToken(String)} instead. + */ + @Deprecated + public Builder withMasterKey(String masterKeyOrResourceToken) { + this.masterKeyOrResourceToken = masterKeyOrResourceToken; + return this; + } + + /** + * This method will accept the master key , additionally it can also consume + * resource token too for authentication. + * + * @param masterKeyOrResourceToken MasterKey or resourceToken for authentication. + * @return current Builder. + */ + public Builder withMasterKeyOrResourceToken(String masterKeyOrResourceToken) { + this.masterKeyOrResourceToken = masterKeyOrResourceToken; + return this; + } + + /** + * This method will accept the permission list , which contains the + * resource tokens needed to access resources. + * + * @param permissionFeed Permission list for authentication. + * @return current Builder. + */ + public Builder withPermissionFeed(List permissionFeed) { + this.permissionFeed = permissionFeed; + return this; + } + + public Builder withConsistencyLevel(ConsistencyLevel desiredConsistencyLevel) { + this.desiredConsistencyLevel = desiredConsistencyLevel; + return this; + } + + public Builder withConfigs(Configs configs) { + this.configs = configs; + return this; + } + + public Builder withConnectionPolicy(ConnectionPolicy connectionPolicy) { + this.connectionPolicy = connectionPolicy; + return this; + } + + /** + * This method will accept tokenResolver which is rx function, it takes arguments
    + * T1 requestVerb(STRING),
    + * T2 resourceIdOrFullName(STRING),
    + * T3 resourceType(com.azure.data.cosmos.internal.ResourceType),
    + * T4 request headers(Map)
    + *
    + * and return
    + * R authenticationToken(STRING)
    + * + * @param tokenResolver tokenResolver function for authentication. + * @return current Builder. + */ + /*public Builder withTokenResolver(Func4, STRING> tokenResolver) { + this.tokenResolver = tokenResolver; + return this; + }*/ + + /** + * This method will accept functional interface TokenResolver which helps in generation authorization + * token per request. AsyncDocumentClient can be successfully initialized with this API without passing any MasterKey, ResourceToken or PermissionFeed. + * @param tokenResolver The tokenResolver + * @return current Builder. + */ + public Builder withTokenResolver(TokenResolver tokenResolver) { + this.tokenResolver = tokenResolver; + return this; + } + + private void ifThrowIllegalArgException(boolean value, String error) { + if (value) { + throw new IllegalArgumentException(error); + } + } + + public AsyncDocumentClient build() { + + ifThrowIllegalArgException(this.serviceEndpoint == null, "cannot build client without service endpoint"); + ifThrowIllegalArgException( + this.masterKeyOrResourceToken == null && (permissionFeed == null || permissionFeed.isEmpty()) && this.tokenResolver == null, + "cannot build client without any one of masterKey, resource token, permissionFeed and tokenResolver"); + + RxDocumentClientImpl client = new RxDocumentClientImpl(serviceEndpoint, + masterKeyOrResourceToken, + permissionFeed, + connectionPolicy, + desiredConsistencyLevel, + configs, + tokenResolver); + client.init(); + return client; + } + + public Configs getConfigs() { + return configs; + } + + public void setConfigs(Configs configs) { + this.configs = configs; + } + + public ConnectionPolicy getConnectionPolicy() { + return connectionPolicy; + } + + public void setConnectionPolicy(ConnectionPolicy connectionPolicy) { + this.connectionPolicy = connectionPolicy; + } + + public ConsistencyLevel getDesiredConsistencyLevel() { + return desiredConsistencyLevel; + } + + public void setDesiredConsistencyLevel(ConsistencyLevel desiredConsistencyLevel) { + this.desiredConsistencyLevel = desiredConsistencyLevel; + } + + public List getPermissionFeed() { + return permissionFeed; + } + + public void setPermissionFeed(List permissionFeed) { + this.permissionFeed = permissionFeed; + } + + public String getMasterKeyOrResourceToken() { + return masterKeyOrResourceToken; + } + + public void setMasterKeyOrResourceToken(String masterKeyOrResourceToken) { + this.masterKeyOrResourceToken = masterKeyOrResourceToken; + } + + public URI getServiceEndpoint() { + return serviceEndpoint; + } + + public void setServiceEndpoint(URI serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + } + + public TokenResolver getTokenResolver() { + return tokenResolver; + } + + public void setTokenResolver(TokenResolver tokenResolver) { + this.tokenResolver = tokenResolver; + } + } + + /** + * Gets the default service endpoint as passed in by the user during construction. + * + * @return the service endpoint URI + */ + URI getServiceEndpoint(); + + /** + * Gets the current write endpoint chosen based on availability and preference. + * + * @return the write endpoint URI + */ + URI getWriteEndpoint(); + + /** + * Gets the current read endpoint chosen based on availability and preference. + * + * @return the read endpoint URI + */ + URI getReadEndpoint(); + + /** + * Gets the connection policy + * + * @return the connection policy + */ + ConnectionPolicy getConnectionPolicy(); + + /** + * Creates a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created database. + * In case of failure the {@link Flux} will error. + * + * @param database the database. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created database or an error. + */ + Flux> createDatabase(Database database, RequestOptions options); + + /** + * Deletes a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the deleted database. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the deleted database or an error. + */ + Flux> deleteDatabase(String databaseLink, RequestOptions options); + + /** + * Reads a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read database. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read database or an error. + */ + Flux> readDatabase(String databaseLink, RequestOptions options); + + /** + * Reads all databases. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of read databases or an error. + */ + Flux> readDatabases(FeedOptions options); + + /** + * Query for databases. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read databases. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of read databases or an error. + */ + Flux> queryDatabases(String query, FeedOptions options); + + /** + * Query for databases. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the obtained databases. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained databases or an error. + */ + Flux> queryDatabases(SqlQuerySpec querySpec, FeedOptions options); + + /** + * Creates a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created collection. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param collection the collection. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created collection or an error. + */ + Flux> createCollection(String databaseLink, DocumentCollection collection, + RequestOptions options); + + /** + * Replaces a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced document collection. + * In case of failure the {@link Flux} will error. + * + * @param collection the document collection to use. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced document collection or an error. + */ + Flux> replaceCollection(DocumentCollection collection, RequestOptions options); + + /** + * Deletes a document collection by the collection link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted database. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted database or an error. + */ + Flux> deleteCollection(String collectionLink, RequestOptions options); + + /** + * Reads a document collection by the collection link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read collection. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read collection or an error. + */ + Flux> readCollection(String collectionLink, RequestOptions options); + + /** + * Reads all document collections in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read collections. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param options the fee options. + * @return an {@link Flux} containing one or several feed response pages of the read collections or an error. + */ + Flux> readCollections(String databaseLink, FeedOptions options); + + /** + * Query for document collections in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the obtained collections. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained collections or an error. + */ + Flux> queryCollections(String databaseLink, String query, FeedOptions options); + + /** + * Query for document collections in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the obtained collections. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained collections or an error. + */ + Flux> queryCollections(String databaseLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Creates a document. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created document. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param document the document represented as a POJO or Document object. + * @param options the request options. + * @param disableAutomaticIdGeneration the flag for disabling automatic id generation. + * @return an {@link Flux} containing the single resource response with the created document or an error. + */ + Flux> createDocument(String collectionLink, Object document, RequestOptions options, + boolean disableAutomaticIdGeneration); + + /** + * Upserts a document. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted document. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param document the document represented as a POJO or Document object to upsert. + * @param options the request options. + * @param disableAutomaticIdGeneration the flag for disabling automatic id generation. + * @return an {@link Flux} containing the single resource response with the upserted document or an error. + */ + Flux> upsertDocument(String collectionLink, Object document, RequestOptions options, + boolean disableAutomaticIdGeneration); + + /** + * Replaces a document using a POJO object. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced document. + * In case of failure the {@link Flux} will error. + * + * @param documentLink the document link. + * @param document the document represented as a POJO or Document object. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced document or an error. + */ + Flux> replaceDocument(String documentLink, Object document, RequestOptions options); + + /** + * Replaces a document with the passed in document. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced document. + * In case of failure the {@link Flux} will error. + * + * @param document the document to replace (containing the document id). + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced document or an error. + */ + Flux> replaceDocument(Document document, RequestOptions options); + + /** + * Deletes a document by the document link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted document. + * In case of failure the {@link Flux} will error. + * + * @param documentLink the document link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted document or an error. + */ + Flux> deleteDocument(String documentLink, RequestOptions options); + + /** + * Reads a document by the document link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read document. + * In case of failure the {@link Flux} will error. + * + * @param documentLink the document link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read document or an error. + */ + Flux> readDocument(String documentLink, RequestOptions options); + + /** + * Reads all documents in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the read documents. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read documents or an error. + */ + Flux> readDocuments(String collectionLink, FeedOptions options); + + + /** + * Query for documents in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the obtained documents. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained document or an error. + */ + Flux> queryDocuments(String collectionLink, String query, FeedOptions options); + + /** + * Query for documents in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response of the obtained documents. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained documents or an error. + */ + Flux> queryDocuments(String collectionLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Query for documents change feed in a document collection. + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained documents. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param changeFeedOptions the change feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained documents or an error. + */ + Flux> queryDocumentChangeFeed(String collectionLink, + ChangeFeedOptions changeFeedOptions); + + /** + * Reads all partition key ranges in a document collection. + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained partition key ranges. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the link to the parent document collection. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained partition key ranges or an error. + */ + Flux> readPartitionKeyRanges(String collectionLink, FeedOptions options); + + /** + * Creates a stored procedure. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created stored procedure. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param storedProcedure the stored procedure to create. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created stored procedure or an error. + */ + Flux> createStoredProcedure(String collectionLink, StoredProcedure storedProcedure, + RequestOptions options); + + /** + * Upserts a stored procedure. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted stored procedure. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param storedProcedure the stored procedure to upsert. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the upserted stored procedure or an error. + */ + Flux> upsertStoredProcedure(String collectionLink, StoredProcedure storedProcedure, + RequestOptions options); + + /** + * Replaces a stored procedure. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced stored procedure. + * In case of failure the {@link Flux} will error. + * + * @param storedProcedure the stored procedure to use. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced stored procedure or an error. + */ + Flux> replaceStoredProcedure(StoredProcedure storedProcedure, RequestOptions options); + + /** + * Deletes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted stored procedure. + * In case of failure the {@link Flux} will error. + * + * @param storedProcedureLink the stored procedure link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted stored procedure or an error. + */ + Flux> deleteStoredProcedure(String storedProcedureLink, RequestOptions options); + + /** + * READ a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read stored procedure. + * In case of failure the {@link Flux} will error. + * + * @param storedProcedureLink the stored procedure link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read stored procedure or an error. + */ + Flux> readStoredProcedure(String storedProcedureLink, RequestOptions options); + + /** + * Reads all stored procedures in a document collection link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read stored procedures. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read stored procedures or an error. + */ + Flux> readStoredProcedures(String collectionLink, FeedOptions options); + + /** + * Query for stored procedures in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained stored procedures. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained stored procedures or an error. + */ + Flux> queryStoredProcedures(String collectionLink, String query, FeedOptions options); + + /** + * Query for stored procedures in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained stored procedures. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained stored procedures or an error. + */ + Flux> queryStoredProcedures(String collectionLink, SqlQuerySpec querySpec, + FeedOptions options); + + /** + * Executes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the stored procedure response. + * In case of failure the {@link Flux} will error. + * + * @param storedProcedureLink the stored procedure link. + * @param procedureParams the array of procedure parameter values. + * @return an {@link Flux} containing the single resource response with the stored procedure response or an error. + */ + Flux executeStoredProcedure(String storedProcedureLink, Object[] procedureParams); + + /** + * Executes a stored procedure by the stored procedure link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the stored procedure response. + * In case of failure the {@link Flux} will error. + * + * @param storedProcedureLink the stored procedure link. + * @param options the request options. + * @param procedureParams the array of procedure parameter values. + * @return an {@link Flux} containing the single resource response with the stored procedure response or an error. + */ + Flux executeStoredProcedure(String storedProcedureLink, RequestOptions options, + Object[] procedureParams); + + /** + * Creates a trigger. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created trigger. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param trigger the trigger. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created trigger or an error. + */ + Flux> createTrigger(String collectionLink, Trigger trigger, RequestOptions options); + + /** + * Upserts a trigger. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted trigger. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param trigger the trigger to upsert. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the upserted trigger or an error. + */ + Flux> upsertTrigger(String collectionLink, Trigger trigger, RequestOptions options); + + /** + * Replaces a trigger. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced trigger. + * In case of failure the {@link Flux} will error. + * + * @param trigger the trigger to use. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced trigger or an error. + */ + Flux> replaceTrigger(Trigger trigger, RequestOptions options); + + /** + * Deletes a trigger. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted trigger. + * In case of failure the {@link Flux} will error. + * + * @param triggerLink the trigger link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted trigger or an error. + */ + Flux> deleteTrigger(String triggerLink, RequestOptions options); + + /** + * Reads a trigger by the trigger link. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the read trigger. + * In case of failure the {@link Flux} will error. + * + * @param triggerLink the trigger link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the read trigger or an error. + */ + Flux> readTrigger(String triggerLink, RequestOptions options); + + /** + * Reads all triggers in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read triggers. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read triggers or an error. + */ + Flux> readTriggers(String collectionLink, FeedOptions options); + + /** + * Query for triggers. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained triggers. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained triggers or an error. + */ + Flux> queryTriggers(String collectionLink, String query, FeedOptions options); + + /** + * Query for triggers. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained triggers. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained triggers or an error. + */ + Flux> queryTriggers(String collectionLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Creates a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created user defined function. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param udf the user defined function. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created user defined function or an error. + */ + Flux> createUserDefinedFunction(String collectionLink, UserDefinedFunction udf, + RequestOptions options); + + /** + * Upserts a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted user defined function. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param udf the user defined function to upsert. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the upserted user defined function or an error. + */ + Flux> upsertUserDefinedFunction(String collectionLink, UserDefinedFunction udf, + RequestOptions options); + + /** + * Replaces a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced user defined function. + * In case of failure the {@link Flux} will error. + * + * @param udf the user defined function. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced user defined function or an error. + */ + Flux> replaceUserDefinedFunction(UserDefinedFunction udf, RequestOptions options); + + /** + * Deletes a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted user defined function. + * In case of failure the {@link Flux} will error. + * + * @param udfLink the user defined function link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted user defined function or an error. + */ + Flux> deleteUserDefinedFunction(String udfLink, RequestOptions options); + + /** + * READ a user defined function. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the read user defined function. + * In case of failure the {@link Flux} will error. + * + * @param udfLink the user defined function link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the read user defined function or an error. + */ + Flux> readUserDefinedFunction(String udfLink, RequestOptions options); + + /** + * Reads all user defined functions in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read user defined functions or an error. + */ + Flux> readUserDefinedFunctions(String collectionLink, FeedOptions options); + + /** + * Query for user defined functions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained user defined functions or an error. + */ + Flux> queryUserDefinedFunctions(String collectionLink, String query, + FeedOptions options); + + /** + * Query for user defined functions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained user defined functions. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained user defined functions or an error. + */ + Flux> queryUserDefinedFunctions(String collectionLink, SqlQuerySpec querySpec, + FeedOptions options); + + /** + * Reads a conflict. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read conflict. + * In case of failure the {@link Flux} will error. + * + * @param conflictLink the conflict link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read conflict or an error. + */ + Flux> readConflict(String conflictLink, RequestOptions options); + + /** + * Reads all conflicts in a document collection. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read conflicts. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read conflicts or an error. + */ + Flux> readConflicts(String collectionLink, FeedOptions options); + + /** + * Query for conflicts. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained conflicts. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained conflicts or an error. + */ + Flux> queryConflicts(String collectionLink, String query, FeedOptions options); + + /** + * Query for conflicts. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained conflicts. + * In case of failure the {@link Flux} will error. + * + * @param collectionLink the collection link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained conflicts or an error. + */ + Flux> queryConflicts(String collectionLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Deletes a conflict. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted conflict. + * In case of failure the {@link Flux} will error. + * + * @param conflictLink the conflict link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted conflict or an error. + */ + Flux> deleteConflict(String conflictLink, RequestOptions options); + + /** + * Creates a user. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created user. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param user the user to create. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created user or an error. + */ + Flux> createUser(String databaseLink, User user, RequestOptions options); + + /** + * Upserts a user. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted user. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param user the user to upsert. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the upserted user or an error. + */ + Flux> upsertUser(String databaseLink, User user, RequestOptions options); + + /** + * Replaces a user. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced user. + * In case of failure the {@link Flux} will error. + * + * @param user the user to use. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced user or an error. + */ + Flux> replaceUser(User user, RequestOptions options); + + /** + * Deletes a user. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted user. + * In case of failure the {@link Flux} will error. + * + * @param userLink the user link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted user or an error. + */ + Flux> deleteUser(String userLink, RequestOptions options); + + /** + * Reads a user. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read user. + * In case of failure the {@link Flux} will error. + * + * @param userLink the user link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read user or an error. + */ + Flux> readUser(String userLink, RequestOptions options); + + /** + * Reads all users in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read users. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read users or an error. + */ + Flux> readUsers(String databaseLink, FeedOptions options); + + /** + * Query for users. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained users. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained users or an error. + */ + Flux> queryUsers(String databaseLink, String query, FeedOptions options); + + /** + * Query for users. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained users. + * In case of failure the {@link Flux} will error. + * + * @param databaseLink the database link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained users or an error. + */ + Flux> queryUsers(String databaseLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Creates a permission. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the created permission. + * In case of failure the {@link Flux} will error. + * + * @param userLink the user link. + * @param permission the permission to create. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the created permission or an error. + */ + Flux> createPermission(String userLink, Permission permission, RequestOptions options); + + /** + * Upserts a permission. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the upserted permission. + * In case of failure the {@link Flux} will error. + * + * @param userLink the user link. + * @param permission the permission to upsert. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the upserted permission or an error. + */ + Flux> upsertPermission(String userLink, Permission permission, RequestOptions options); + + /** + * Replaces a permission. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced permission. + * In case of failure the {@link Flux} will error. + * + * @param permission the permission to use. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the replaced permission or an error. + */ + Flux> replacePermission(Permission permission, RequestOptions options); + + /** + * Deletes a permission. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response for the deleted permission. + * In case of failure the {@link Flux} will error. + * + * @param permissionLink the permission link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response for the deleted permission or an error. + */ + Flux> deletePermission(String permissionLink, RequestOptions options); + + /** + * Reads a permission. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read permission. + * In case of failure the {@link Flux} will error. + * + * @param permissionLink the permission link. + * @param options the request options. + * @return an {@link Flux} containing the single resource response with the read permission or an error. + */ + Flux> readPermission(String permissionLink, RequestOptions options); + + /** + * Reads all permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read permissions. + * In case of failure the {@link Flux} will error. + * + * @param permissionLink the permission link. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read permissions or an error. + */ + Flux> readPermissions(String permissionLink, FeedOptions options); + + /** + * Query for permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained permissions. + * In case of failure the {@link Flux} will error. + * + * @param permissionLink the permission link. + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained permissions or an error. + */ + Flux> queryPermissions(String permissionLink, String query, FeedOptions options); + + /** + * Query for permissions. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the obtained permissions. + * In case of failure the {@link Flux} will error. + * + * @param permissionLink the permission link. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained permissions or an error. + */ + Flux> queryPermissions(String permissionLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * Replaces an offer. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the replaced offer. + * In case of failure the {@link Flux} will error. + * + * @param offer the offer to use. + * @return an {@link Flux} containing the single resource response with the replaced offer or an error. + */ + Flux> replaceOffer(Offer offer); + + /** + * Reads an offer. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the read offer. + * In case of failure the {@link Flux} will error. + * + * @param offerLink the offer link. + * @return an {@link Flux} containing the single resource response with the read offer or an error. + */ + Flux> readOffer(String offerLink); + + /** + * Reads offers. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of the read offers. + * In case of failure the {@link Flux} will error. + * + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the read offers or an error. + */ + Flux> readOffers(FeedOptions options); + + /** + * Query for offers in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of obtained obtained offers. + * In case of failure the {@link Flux} will error. + * + * @param query the query. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained offers or an error. + */ + Flux> queryOffers(String query, FeedOptions options); + + /** + * Query for offers in a database. + *

    + * After subscription the operation will be performed. + * The {@link Flux} will contain one or several feed response pages of obtained obtained offers. + * In case of failure the {@link Flux} will error. + * + * @param querySpec the query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained offers or an error. + */ + Flux> queryOffers(SqlQuerySpec querySpec, FeedOptions options); + + /** + * Gets database account information. + *

    + * After subscription the operation will be performed. + * The {@link Flux} upon successful completion will contain a single resource response with the database account. + * In case of failure the {@link Flux} will error. + * + * @return an {@link Flux} containing the single resource response with the database account or an error. + */ + Flux getDatabaseAccount(); + + /** + * Close this {@link AsyncDocumentClient} instance and cleans up the resources. + */ + void close(); + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenProvider.java new file mode 100644 index 0000000000000..5e654336b6f05 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenProvider.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import java.util.Map; + +/** + * Represents types that can provide functionality to generate authorization token for the Azure Cosmos DB database + * service. + */ +public interface AuthorizationTokenProvider { + String generateKeyAuthorizationSignature(String verb, + String resourceIdOrFullName, + ResourceType resourceType, + Map headers); + + String getAuthorizationTokenUsingResourceTokens(Map resourceTokens, + String path, + String resourceId); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenType.java new file mode 100644 index 0000000000000..ec36d4d000981 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/AuthorizationTokenType.java @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +public enum AuthorizationTokenType { + Invalid, + PrimaryMasterKey, + PrimaryReadonlyMasterKey, + SecondaryMasterKey, + SecondaryReadonlyMasterKey, + SystemReadOnly, + SystemReadWrite, + SystemAll, + ResourceToken +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BackoffRetryUtility.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BackoffRetryUtility.java new file mode 100644 index 0000000000000..b319ede033e03 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BackoffRetryUtility.java @@ -0,0 +1,73 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class BackoffRetryUtility { + + // transforms a retryFunc to a function which can be used by Observable.retryWhen(.) + // also it invokes preRetryCallback prior to doing retry. + public static final Quadruple InitialArgumentValuePolicyArg = Quadruple.with(false, false, + Duration.ofSeconds(60), 0); + + // a helper method for invoking callback method given the retry policy. + // it also invokes the pre retry callback prior to retrying + + // a helper method for invoking callback method given the retry policy + + // a helper method for invoking callback method given the retry policy + static public Mono executeRetry(Callable> callbackMethod, + IRetryPolicy retryPolicy) { + + return Mono.defer(() -> { + // TODO: is defer required? + try { + return callbackMethod.call(); + } catch (Exception e) { + return Mono.error(e); + } + }).retryWhen(RetryUtils.toRetryWhenFunc(retryPolicy)); + } + + static public Mono executeAsync( + Function, Mono> callbackMethod, IRetryPolicy retryPolicy, + Function, Mono> inBackoffAlternateCallbackMethod, + Duration minBackoffForInBackoffCallback) { + + return Mono.defer(() -> { + // TODO: is defer required? + return callbackMethod.apply(InitialArgumentValuePolicyArg).onErrorResume( + RetryUtils.toRetryWithAlternateFunc(callbackMethod, retryPolicy, inBackoffAlternateCallbackMethod,minBackoffForInBackoffCallback)); + }); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseAuthorizationTokenProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseAuthorizationTokenProvider.java new file mode 100644 index 0000000000000..5b6bd3439f0e2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseAuthorizationTokenProvider.java @@ -0,0 +1,370 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.net.URI; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; + +/** + * This class is used internally by both client (for generating the auth header with master/system key) and by the GATEWAY when + * verifying the auth header in the Azure Cosmos DB database service. + */ +public class BaseAuthorizationTokenProvider implements AuthorizationTokenProvider { + + private static final String AUTH_PREFIX = "type=master&ver=1.0&sig="; + private final String masterKey; + private final Mac macInstance; + + public BaseAuthorizationTokenProvider(String masterKey) { + this.masterKey = masterKey; + byte[] masterKeyDecodedBytes = Utils.Base64Decoder.decode(this.masterKey.getBytes()); + SecretKey signingKey = new SecretKeySpec(masterKeyDecodedBytes, "HMACSHA256"); + try { + this.macInstance = Mac.getInstance("HMACSHA256"); + this.macInstance.init(signingKey); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new IllegalStateException(e); + } + } + + private static String getResourceSegment(ResourceType resourceType) { + switch (resourceType) { + case Attachment: + return Paths.ATTACHMENTS_PATH_SEGMENT; + case Database: + return Paths.DATABASES_PATH_SEGMENT; + case Conflict: + return Paths.CONFLICTS_PATH_SEGMENT; + case Document: + return Paths.DOCUMENTS_PATH_SEGMENT; + case DocumentCollection: + return Paths.COLLECTIONS_PATH_SEGMENT; + case Offer: + return Paths.OFFERS_PATH_SEGMENT; + case Permission: + return Paths.PERMISSIONS_PATH_SEGMENT; + case StoredProcedure: + return Paths.STORED_PROCEDURES_PATH_SEGMENT; + case Trigger: + return Paths.TRIGGERS_PATH_SEGMENT; + case UserDefinedFunction: + return Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT; + case User: + return Paths.USERS_PATH_SEGMENT; + case PartitionKeyRange: + return Paths.PARTITION_KEY_RANGES_PATH_SEGMENT; + case Media: + return Paths.MEDIA_PATH_SEGMENT; + case DatabaseAccount: + return ""; + default: + return null; + } + } + + /** + * This API is a helper method to create auth header based on client request using masterkey. + * + * @param verb the verb. + * @param resourceIdOrFullName the resource id or full name + * @param resourceType the resource type. + * @param headers the request headers. + * @return the key authorization signature. + */ + public String generateKeyAuthorizationSignature(String verb, + String resourceIdOrFullName, + ResourceType resourceType, + Map headers) { + return this.generateKeyAuthorizationSignature(verb, resourceIdOrFullName, + BaseAuthorizationTokenProvider.getResourceSegment(resourceType).toLowerCase(), headers); + } + + /** + * This API is a helper method to create auth header based on client request using masterkey. + * + * @param verb the verb + * @param resourceIdOrFullName the resource id or full name + * @param resourceSegment the resource segment + * @param headers the request headers + * @return the key authorization signature + */ + public String generateKeyAuthorizationSignature(String verb, + String resourceIdOrFullName, + String resourceSegment, + Map headers) { + if (verb == null || verb.isEmpty()) { + throw new IllegalArgumentException("verb"); + } + + if (resourceIdOrFullName == null) { + resourceIdOrFullName = ""; + } + + if (resourceSegment == null) { + throw new IllegalArgumentException("resourceSegment"); + } + + if (headers == null) { + throw new IllegalArgumentException("headers"); + } + + if (this.masterKey == null || this.masterKey.isEmpty()) { + throw new IllegalArgumentException("masterKey"); + } + + if(!PathsHelper.isNameBased(resourceIdOrFullName)) { + resourceIdOrFullName = resourceIdOrFullName.toLowerCase(Locale.ROOT); + } + + // Skipping lower casing of resourceId since it may now contain "ID" of the resource as part of the FullName + StringBuilder body = new StringBuilder(); + body.append(verb.toLowerCase()) + .append('\n') + .append(resourceSegment) + .append('\n') + .append(resourceIdOrFullName) + .append('\n'); + + if (headers.containsKey(HttpConstants.HttpHeaders.X_DATE)) { + body.append(headers.get(HttpConstants.HttpHeaders.X_DATE).toLowerCase()); + } + + body.append('\n'); + + if (headers.containsKey(HttpConstants.HttpHeaders.HTTP_DATE)) { + body.append(headers.get(HttpConstants.HttpHeaders.HTTP_DATE).toLowerCase()); + } + + body.append('\n'); + + Mac mac = null; + try { + mac = (Mac) this.macInstance.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + + byte[] digest = mac.doFinal(body.toString().getBytes()); + + String auth = Utils.encodeBase64String(digest); + + return AUTH_PREFIX + auth; + } + + /** + * This API is a helper method to create auth header based on client request using resourceTokens. + * + * @param resourceTokens the resource tokens. + * @param path the path. + * @param resourceId the resource id. + * @return the authorization token. + */ + public String getAuthorizationTokenUsingResourceTokens(Map resourceTokens, + String path, + String resourceId) { + if (resourceTokens == null) { + throw new IllegalArgumentException("resourceTokens"); + } + + String resourceToken = null; + if (resourceTokens.containsKey(resourceId) && resourceTokens.get(resourceId) != null) { + resourceToken = resourceTokens.get(resourceId); + } else if (StringUtils.isEmpty(path) || StringUtils.isEmpty(resourceId)) { + if (resourceTokens.size() > 0) { + resourceToken = resourceTokens.values().iterator().next(); + } + } else { + // Get the last resource id from the path and use that to find the corresponding token. + String[] pathParts = StringUtils.split(path, "/"); + String[] resourceTypes = {"dbs", "colls", "docs", "sprocs", "udfs", "triggers", "users", "permissions", + "attachments", "media", "conflicts"}; + HashSet resourceTypesSet = new HashSet(); + Collections.addAll(resourceTypesSet, resourceTypes); + + for (int i = pathParts.length - 1; i >= 0; --i) { + + if (!resourceTypesSet.contains(pathParts[i]) && resourceTokens.containsKey(pathParts[i])) { + resourceToken = resourceTokens.get(pathParts[i]); + } + } + } + + return resourceToken; + } + public String generateKeyAuthorizationSignature(String verb, URI uri, Map headers) { + if (StringUtils.isEmpty(verb)) { + throw new IllegalArgumentException(String.format(RMResources.StringArgumentNullOrEmpty, "verb")); + } + + if (uri == null) { + throw new IllegalArgumentException("uri"); + } + + if (headers == null) { + throw new IllegalArgumentException("headers"); + } + PathInfo pathInfo = new PathInfo(false, StringUtils.EMPTY, StringUtils.EMPTY, false); + getResourceTypeAndIdOrFullName(uri, pathInfo); + return generateKeyAuthorizationSignatureNew(verb, pathInfo.resourceIdOrFullName, pathInfo.resourcePath, + headers); + } + + public String generateKeyAuthorizationSignatureNew(String verb, String resourceIdValue, String resourceType, + Map headers) { + if (StringUtils.isEmpty(verb)) { + throw new IllegalArgumentException(String.format(RMResources.StringArgumentNullOrEmpty, "verb")); + } + + if (resourceType == null) { + throw new IllegalArgumentException(String.format(RMResources.StringArgumentNullOrEmpty, "resourceType")); // can be empty + } + + if (headers == null) { + throw new IllegalArgumentException("headers"); + } + // Order of the values included in the message payload is a protocol that + // clients/BE need to follow exactly. + // More headers can be added in the future. + // If any of the value is optional, it should still have the placeholder value + // of "" + // OperationType -> ResourceType -> ResourceId/OwnerId -> XDate -> Date + String verbInput = verb; + String resourceIdInput = resourceIdValue; + String resourceTypeInput = resourceType; + + String authResourceId = getAuthorizationResourceIdOrFullName(resourceTypeInput, resourceIdInput); + String payLoad = generateMessagePayload(verbInput, authResourceId, resourceTypeInput, headers); + Mac mac = null; + try { + mac = (Mac) this.macInstance.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + byte[] digest = mac.doFinal(payLoad.getBytes()); + String authorizationToken = Utils.encodeBase64String(digest); + String authtoken = AUTH_PREFIX + authorizationToken; + return HttpUtils.urlEncode(authtoken); + } + + private String generateMessagePayload(String verb, String resourceId, String resourceType, + Map headers) { + String xDate = headers.get(HttpConstants.HttpHeaders.X_DATE); + String date = headers.get(HttpConstants.HttpHeaders.HTTP_DATE); + // At-least one of date header should present + // https://docs.microsoft.com/en-us/rest/api/documentdb/access-control-on-documentdb-resources + if (StringUtils.isEmpty(xDate) && (StringUtils.isEmpty(date) || StringUtils.isWhitespace(date))) { + headers.put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + xDate = Utils.nowAsRFC1123(); + } + + // for name based, it is case sensitive, we won't use the lower case + if (!PathsHelper.isNameBased(resourceId)) { + resourceId = resourceId.toLowerCase(); + } + + StringBuilder payload = new StringBuilder(); + payload.append(verb.toLowerCase()) + .append('\n') + .append(resourceType.toLowerCase()) + .append('\n') + .append(resourceId) + .append('\n') + .append(xDate.toLowerCase()) + .append('\n') + .append(StringUtils.isEmpty(xDate) ? date.toLowerCase() : "") + .append('\n'); + + return payload.toString(); + } + + private String getAuthorizationResourceIdOrFullName(String resourceType, String resourceIdOrFullName) { + if (StringUtils.isEmpty(resourceType) || StringUtils.isEmpty(resourceIdOrFullName)) { + return resourceIdOrFullName; + } + if (PathsHelper.isNameBased(resourceIdOrFullName)) { + // resource fullname is always end with name (not type segment like docs/colls). + return resourceIdOrFullName; + } + + if (resourceType.equalsIgnoreCase(Paths.OFFERS_PATH_SEGMENT) + || resourceType.equalsIgnoreCase(Paths.PARTITIONS_PATH_SEGMENT) + || resourceType.equalsIgnoreCase(Paths.TOPOLOGY_PATH_SEGMENT) + || resourceType.equalsIgnoreCase(Paths.RID_RANGE_PATH_SEGMENT)) { + return resourceIdOrFullName; + } + + ResourceId parsedRId = ResourceId.parse(resourceIdOrFullName); + if (resourceType.equalsIgnoreCase(Paths.DATABASES_PATH_SEGMENT)) { + return parsedRId.getDatabaseId().toString(); + } else if (resourceType.equalsIgnoreCase(Paths.USERS_PATH_SEGMENT)) { + return parsedRId.getUserId().toString(); + } else if (resourceType.equalsIgnoreCase(Paths.COLLECTIONS_PATH_SEGMENT)) { + return parsedRId.getDocumentCollectionId().toString(); + } else if (resourceType.equalsIgnoreCase(Paths.DOCUMENTS_PATH_SEGMENT)) { + return parsedRId.getDocumentId().toString(); + } else { + // leaf node + return resourceIdOrFullName; + } + } + + private void getResourceTypeAndIdOrFullName(URI uri, PathInfo pathInfo) { + if (uri == null) { + throw new IllegalArgumentException("uri"); + } + + pathInfo.resourcePath = StringUtils.EMPTY; + pathInfo.resourceIdOrFullName = StringUtils.EMPTY; + + String[] segments = StringUtils.split(uri.toString(), Constants.Properties.PATH_SEPARATOR); + if (segments == null || segments.length < 1) { + throw new IllegalArgumentException(RMResources.InvalidUrl); + } + // Authorization code is fine with Uri not having resource id and path. + // We will just return empty in that case + String pathAndQuery = StringUtils.EMPTY ; + if(StringUtils.isNotEmpty(uri.getPath())) { + pathAndQuery+= uri.getPath(); + } + if(StringUtils.isNotEmpty(uri.getQuery())) { + pathAndQuery+="?"; + pathAndQuery+= uri.getQuery(); + } + if (!PathsHelper.tryParsePathSegments(pathAndQuery, pathInfo, null)) { + pathInfo.resourcePath = StringUtils.EMPTY; + pathInfo.resourceIdOrFullName = StringUtils.EMPTY; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseDatabaseAccountConfigurationProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseDatabaseAccountConfigurationProvider.java new file mode 100644 index 0000000000000..8fc51eadbe534 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/BaseDatabaseAccountConfigurationProvider.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConsistencyLevel; + +/** + * Used internally to provides functionality to work with database account configuration in the Azure Cosmos DB database service. + */ +public class BaseDatabaseAccountConfigurationProvider implements DatabaseAccountConfigurationProvider { + private ConsistencyLevel desiredConsistencyLevel; + private DatabaseAccount databaseAccount; + + public BaseDatabaseAccountConfigurationProvider(DatabaseAccount databaseAccount, ConsistencyLevel desiredConsistencyLevel) { + this.databaseAccount = databaseAccount; + this.desiredConsistencyLevel = desiredConsistencyLevel; + } + + public ConsistencyLevel getStoreConsistencyPolicy() { + ConsistencyLevel databaseAccountConsistency = this.databaseAccount.getConsistencyPolicy().defaultConsistencyLevel(); + if (this.desiredConsistencyLevel == null) { + return databaseAccountConsistency; + } else if (!Utils.isValidConsistency(databaseAccountConsistency, this.desiredConsistencyLevel)) { + throw new IllegalArgumentException(String.format( + "ConsistencyLevel %1s specified in the request is invalid when service is configured with consistency level %2s. Ensure the request consistency level is not stronger than the service consistency level.", + this.desiredConsistencyLevel.toString(), + databaseAccountConsistency.toString())); + } else { + return this.desiredConsistencyLevel; + } + } + + public int getMaxReplicaSetSize() { + return this.databaseAccount.getReplicationPolicy().getMaxReplicaSetSize(); + } + + @Override + public String getQueryEngineConfiguration() { + return databaseAccount.get("queryEngineConfiguration").toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Bytes.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Bytes.java new file mode 100644 index 0000000000000..0c8fc14fe6ad0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Bytes.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + + +public class Bytes { + + public static void reverse(byte[] bytes, int offset, int endIndex) { + for(int i = offset, j = endIndex - 1; i < j; --j, i++) { + byte aux = bytes[i]; + bytes[i] = bytes[j]; + bytes[j] = aux; + } + } + + public static void reverse(byte[] bytes) { + Bytes.reverse(bytes, 0, bytes.length); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ChangeFeedQueryImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ChangeFeedQueryImpl.java new file mode 100644 index 0000000000000..91b36e4bd4ff4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ChangeFeedQueryImpl.java @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.query.Paginator; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import reactor.core.publisher.Flux; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static com.azure.data.cosmos.CommonsBridgeInternal.partitionKeyRangeIdInternal; + +class ChangeFeedQueryImpl { + + private static final String IfNonMatchAllHeaderValue = "*"; + private final RxDocumentClientImpl client; + private final ResourceType resourceType; + private final Class klass; + private final String documentsLink; + private final ChangeFeedOptions options; + + public ChangeFeedQueryImpl(RxDocumentClientImpl client, + ResourceType resourceType, + Class klass, + String collectionLink, + ChangeFeedOptions changeFeedOptions) { + + this.client = client; + this.resourceType = resourceType; + this.klass = klass; + this.documentsLink = Utils.joinPath(collectionLink, Paths.DOCUMENTS_PATH_SEGMENT); + changeFeedOptions = changeFeedOptions != null ? changeFeedOptions: new ChangeFeedOptions(); + + + if (resourceType.isPartitioned() && partitionKeyRangeIdInternal(changeFeedOptions) == null && changeFeedOptions.partitionKey() == null) { + throw new IllegalArgumentException(RMResources.PartitionKeyRangeIdOrPartitionKeyMustBeSpecified); + } + + if (changeFeedOptions.partitionKey() != null && + !Strings.isNullOrEmpty(partitionKeyRangeIdInternal(changeFeedOptions))) { + + throw new IllegalArgumentException(String.format( + RMResources.PartitionKeyAndParitionKeyRangeIdBothSpecified + , "feedOptions")); + } + + String initialNextIfNoneMatch = null; + + boolean canUseStartFromBeginning = true; + if (changeFeedOptions.requestContinuation() != null) { + initialNextIfNoneMatch = changeFeedOptions.requestContinuation(); + canUseStartFromBeginning = false; + } + + if(changeFeedOptions.startDateTime() != null){ + canUseStartFromBeginning = false; + } + + if (canUseStartFromBeginning && !changeFeedOptions.startFromBeginning()) { + initialNextIfNoneMatch = IfNonMatchAllHeaderValue; + } + + this.options = getChangeFeedOptions(changeFeedOptions, initialNextIfNoneMatch); + } + + private RxDocumentServiceRequest createDocumentServiceRequest(String continuationToken, int pageSize) { + Map headers = new HashMap<>(); + + if (options.maxItemCount() != null) { + headers.put(HttpConstants.HttpHeaders.PAGE_SIZE, String.valueOf(options.maxItemCount())); + } + + // On REST level, change feed is using IF_NONE_MATCH/ETag instead of continuation. + if(continuationToken != null) { + headers.put(HttpConstants.HttpHeaders.IF_NONE_MATCH, continuationToken); + } + + headers.put(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.INCREMENTAL_FEED); + + if (options.partitionKey() != null) { + PartitionKeyInternal partitionKey = options.partitionKey().getInternalPartitionKey(); + headers.put(HttpConstants.HttpHeaders.PARTITION_KEY, partitionKey.toJson()); + } + + if(options.startDateTime() != null){ + String dateTimeInHttpFormat = Utils.zonedDateTimeAsUTCRFC1123(options.startDateTime()); + headers.put(HttpConstants.HttpHeaders.IF_MODIFIED_SINCE, dateTimeInHttpFormat); + } + + RxDocumentServiceRequest req = RxDocumentServiceRequest.create( + OperationType.ReadFeed, + resourceType, + documentsLink, + headers, + options); + + if (partitionKeyRangeIdInternal(options) != null) { + req.routeTo(new PartitionKeyRangeIdentity(partitionKeyRangeIdInternal(this.options))); + } + + return req; + } + + private ChangeFeedOptions getChangeFeedOptions(ChangeFeedOptions options, String continuationToken) { + ChangeFeedOptions newOps = new ChangeFeedOptions(options); + newOps.requestContinuation(continuationToken); + return newOps; + } + + public Flux> executeAsync() { + + BiFunction createRequestFunc = this::createDocumentServiceRequest; + + Function>> executeFunc = this::executeRequestAsync; + + return Paginator.getPaginatedChangeFeedQueryResultAsObservable(options, createRequestFunc, executeFunc, klass, options.maxItemCount() != null ? options.maxItemCount(): -1); + } + + private Flux> executeRequestAsync(RxDocumentServiceRequest request) { + return client.readFeed(request) + .map( rsp -> BridgeInternal.toChaneFeedResponsePage(rsp, klass)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClearingSessionContainerClientRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClearingSessionContainerClientRetryPolicy.java new file mode 100644 index 0000000000000..09b510367b480 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClearingSessionContainerClientRetryPolicy.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * This retry policy is designed to work with in a pair with ClientRetryPolicy. + * The inner retryPolicy must be a ClientRetryPolicy or a retry policy delegating to it. + * + * The expectation that is the outer retry policy in the retry policy chain and nobody can overwrite ShouldRetryResult. + * Once we clear the session we expect call to fail and throw exception to the client. Otherwise we may violate session consistency. + */ +public class ClearingSessionContainerClientRetryPolicy implements IDocumentClientRetryPolicy { + + private final static Logger logger = LoggerFactory.getLogger(ClearingSessionContainerClientRetryPolicy.class); + + private final IDocumentClientRetryPolicy retryPolicy; + private final ISessionContainer sessionContainer; + private RxDocumentServiceRequest request; + private boolean hasTriggered = false; + + public ClearingSessionContainerClientRetryPolicy(ISessionContainer sessionContainer, IDocumentClientRetryPolicy retryPolicy) { + this.sessionContainer = sessionContainer; + this.retryPolicy = retryPolicy; + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + this.request = request; + this.retryPolicy.onBeforeSendRequest(request); + } + + @Override + public Mono shouldRetry(Exception e) { + + return this.retryPolicy.shouldRetry(e).flatMap(shouldRetryResult -> { + + if (!shouldRetryResult.shouldRetry && !this.hasTriggered) + { + CosmosClientException clientException = Utils.as(e, CosmosClientException.class); + + if (this.request == null) { + // someone didn't call OnBeforeSendRequest - nothing we can do + logger.error("onBeforeSendRequest is not invoked, encountered failure due to request being null", e); + return Mono.just(ShouldRetryResult.error(e)); + } + + if (clientException != null && this.request.getIsNameBased() && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.NOTFOUND) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)) + { + // Clear the session token, because the collection name might be reused. + logger.warn("Clear the token for named base request {}", request.getResourceAddress()); + + this.sessionContainer.clearTokenByCollectionFullName(request.getResourceAddress()); + + this.hasTriggered = true; + } + } + + return Mono.just(shouldRetryResult); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClientRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClientRetryPolicy.java new file mode 100644 index 0000000000000..239899573eb5f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ClientRetryPolicy.java @@ -0,0 +1,228 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import com.azure.data.cosmos.RetryOptions; +import com.azure.data.cosmos.internal.directconnectivity.WebExceptionUtility; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.Duration; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * Client policy is combination of endpoint change retry + throttling retry. + */ +public class ClientRetryPolicy implements IDocumentClientRetryPolicy { + + private final static Logger logger = LoggerFactory.getLogger(ClientRetryPolicy.class); + + final static int RetryIntervalInMS = 1000; //Once we detect failover wait for 1 second before retrying request. + final static int MaxRetryCount = 120; + + private final IDocumentClientRetryPolicy throttlingRetry; + private final GlobalEndpointManager globalEndpointManager; + private final boolean enableEndpointDiscovery; + private int failoverRetryCount; + + private int sessionTokenRetryCount; + private boolean isReadRequest; + private boolean canUseMultipleWriteLocations; + private URL locationEndpoint; + private RetryContext retryContext; + private CosmosResponseDiagnostics cosmosResponseDiagnostics; + + public ClientRetryPolicy(GlobalEndpointManager globalEndpointManager, + boolean enableEndpointDiscovery, + RetryOptions retryOptions) { + + this.throttlingRetry = new ResourceThrottleRetryPolicy( + retryOptions.maxRetryAttemptsOnThrottledRequests(), + retryOptions.maxRetryWaitTimeInSeconds()); + this.globalEndpointManager = globalEndpointManager; + this.failoverRetryCount = 0; + this.enableEndpointDiscovery = enableEndpointDiscovery; + this.sessionTokenRetryCount = 0; + this.canUseMultipleWriteLocations = false; + this.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + + @Override + public Mono shouldRetry(Exception e) { + if (this.locationEndpoint == null) { + // on before request is not invoked because Document Service Request creation failed. + logger.error("locationEndpoint is null because ClientRetryPolicy::onBeforeRequest(.) is not invoked, " + + "probably request creation failed due to invalid options, serialization setting, etc."); + return Mono.just(ShouldRetryResult.error(e)); + } + + this.retryContext = null; + // Received 403.3 on write region, initiate the endpoint re-discovery + CosmosClientException clientException = Utils.as(e, CosmosClientException.class); + if (clientException != null && clientException.cosmosResponseDiagnostics() != null) { + this.cosmosResponseDiagnostics = clientException.cosmosResponseDiagnostics(); + } + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.FORBIDDEN) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.FORBIDDEN_WRITEFORBIDDEN)) + { + logger.warn("Endpoint not writable. Will refresh cache and retry. {}", e.toString()); + return this.shouldRetryOnEndpointFailureAsync(false); + } + + // Regional endpoint is not available yet for reads (e.g. add/ online of region is in progress) + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.FORBIDDEN) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.DATABASE_ACCOUNT_NOTFOUND) && + this.isReadRequest) + { + logger.warn("Endpoint not available for reads. Will refresh cache and retry. {}", e.toString()); + return this.shouldRetryOnEndpointFailureAsync(true); + } + + // Received Connection error (HttpRequestException), initiate the endpoint rediscovery + if (WebExceptionUtility.isNetworkFailure(e)) { + logger.warn("Endpoint not reachable. Will refresh cache and retry. {}" , e.toString()); + return this.shouldRetryOnEndpointFailureAsync(this.isReadRequest); + } + + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.NOTFOUND) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)) { + return Mono.just(this.shouldRetryOnSessionNotAvailable()); + } + + return this.throttlingRetry.shouldRetry(e); + } + + private ShouldRetryResult shouldRetryOnSessionNotAvailable() { + this.sessionTokenRetryCount++; + + if (!this.enableEndpointDiscovery) { + // if endpoint discovery is disabled, the request cannot be retried anywhere else + return ShouldRetryResult.noRetry(); + } else { + if (this.canUseMultipleWriteLocations) { + UnmodifiableList endpoints = this.isReadRequest ? this.globalEndpointManager.getReadEndpoints() : this.globalEndpointManager.getWriteEndpoints(); + + if (this.sessionTokenRetryCount > endpoints.size()) { + // When use multiple write locations is true and the request has been tried + // on all locations, then don't retry the request + return ShouldRetryResult.noRetry(); + } else { + this.retryContext = new RetryContext(this.sessionTokenRetryCount - 1, this.sessionTokenRetryCount > 1); + return ShouldRetryResult.retryAfter(Duration.ZERO); + } + } else { + if (this.sessionTokenRetryCount > 1) { + // When cannot use multiple write locations, then don't retry the request if + // we have already tried this request on the write location + return ShouldRetryResult.noRetry(); + } else { + this.retryContext = new RetryContext(this.sessionTokenRetryCount - 1, false); + return ShouldRetryResult.retryAfter(Duration.ZERO); + } + } + } + } + + private Mono shouldRetryOnEndpointFailureAsync(boolean isReadRequest) { + if (!this.enableEndpointDiscovery || this.failoverRetryCount > MaxRetryCount) { + logger.warn("ShouldRetryOnEndpointFailureAsync() Not retrying. Retry count = {}", this.failoverRetryCount); + return Mono.just(ShouldRetryResult.noRetry()); + } + + this.failoverRetryCount++; + + // Mark the current read endpoint as unavailable + if (this.isReadRequest) { + logger.warn("marking the endpoint {} as unavailable for read",this.locationEndpoint); + this.globalEndpointManager.markEndpointUnavailableForRead(this.locationEndpoint); + } else { + logger.warn("marking the endpoint {} as unavailable for write",this.locationEndpoint); + this.globalEndpointManager.markEndpointUnavailableForWrite(this.locationEndpoint); + } + + // Some requests may be in progress when the endpoint manager and client are closed. + // In that case, the request won't succeed since the http client is closed. + // Therefore just skip the retry here to avoid the delay because retrying won't go through in the end. + + Duration retryDelay = Duration.ZERO; + if (!this.isReadRequest) { + logger.debug("Failover happening. retryCount {}", this.failoverRetryCount); + if (this.failoverRetryCount > 1) { + //if retried both endpoints, follow regular retry interval. + retryDelay = Duration.ofMillis(ClientRetryPolicy.RetryIntervalInMS); + } + } else { + retryDelay = Duration.ofMillis(ClientRetryPolicy.RetryIntervalInMS); + } + this.retryContext = new RetryContext(this.failoverRetryCount, false); + return this.globalEndpointManager.refreshLocationAsync(null) + .then(Mono.just(ShouldRetryResult.retryAfter(retryDelay))); + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + this.isReadRequest = request.isReadOnlyRequest(); + this.canUseMultipleWriteLocations = this.globalEndpointManager.CanUseMultipleWriteLocations(request); + if (request.requestContext != null) { + request.requestContext.cosmosResponseDiagnostics = this.cosmosResponseDiagnostics; + } + + // clear previous location-based routing directive + if (request.requestContext != null) { + request.requestContext.ClearRouteToLocation(); + } + if (this.retryContext != null) { + // set location-based routing directive based on request retry context + request.requestContext.RouteToLocation(this.retryContext.retryCount, this.retryContext.retryRequestOnPreferredLocations); + } + + // Resolve the endpoint for the request and pin the resolution to the resolved endpoint + // This enables marking the endpoint unavailability on endpoint failover/unreachability + this.locationEndpoint = this.globalEndpointManager.resolveServiceEndpoint(request); + if (request.requestContext != null) { + request.requestContext.RouteToLocation(this.locationEndpoint); + } + } + private class RetryContext { + + public int retryCount; + public boolean retryRequestOnPreferredLocations; + + public RetryContext(int retryCount, + boolean retryRequestOnPreferredLocations) { + this.retryCount = retryCount; + this.retryRequestOnPreferredLocations = retryRequestOnPreferredLocations; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Configs.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Configs.java new file mode 100644 index 0000000000000..0913c35ba1ee0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Configs.java @@ -0,0 +1,177 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLException; + +public class Configs { + private static final Logger logger = LoggerFactory.getLogger(Configs.class); + private final SslContext sslContext; + + private static final String PROTOCOL = "cosmos.directModeProtocol"; + private static final Protocol DEFAULT_PROTOCOL = Protocol.TCP; + + private static final String UNAVAILABLE_LOCATIONS_EXPIRATION_TIME_IN_SECONDS = "COSMOS.UNAVAILABLE_LOCATIONS_EXPIRATION_TIME_IN_SECONDS"; + + private static final String MAX_HTTP_BODY_LENGTH_IN_BYTES = "COSMOS.MAX_HTTP_BODY_LENGTH_IN_BYTES"; + private static final String MAX_HTTP_INITIAL_LINE_LENGTH_IN_BYTES = "COSMOS.MAX_HTTP_INITIAL_LINE_LENGTH_IN_BYTES"; + private static final String MAX_HTTP_CHUNK_SIZE_IN_BYTES = "COSMOS.MAX_HTTP_CHUNK_SIZE_IN_BYTES"; + private static final String MAX_HTTP_HEADER_SIZE_IN_BYTES = "COSMOS.MAX_HTTP_HEADER_SIZE_IN_BYTES"; + private static final String MAX_DIRECT_HTTPS_POOL_SIZE = "COSMOS.MAX_DIRECT_HTTP_CONNECTION_LIMIT"; + + private static final int DEFAULT_UNAVAILABLE_LOCATIONS_EXPIRATION_TIME_IN_SECONDS = 5 * 60; + + private static final int DEFAULT_MAX_HTTP_BODY_LENGTH_IN_BYTES = 6 * 1024 * 1024; //6MB + private static final int DEFAULT_MAX_HTTP_INITIAL_LINE_LENGTH = 4096; //4KB + private static final int DEFAULT_MAX_HTTP_CHUNK_SIZE_IN_BYTES = 8192; //8KB + private static final int DEFAULT_MAX_HTTP_REQUEST_HEADER_SIZE = 32 * 1024; //32 KB + + private static final int MAX_NUMBER_OF_READ_BARRIER_READ_RETRIES = 6; + private static final int MAX_NUMBER_OF_PRIMARY_READ_RETRIES = 6; + private static final int MAX_NUMBER_OF_READ_QUORUM_RETRIES = 6; + private static final int DELAY_BETWEEN_READ_BARRIER_CALLS_IN_MS = 5; + + private static final int MAX_BARRIER_RETRIES_FOR_MULTI_REGION = 30; + private static final int BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION = 30; + + private static final int MAX_SHORT_BARRIER_RETRIES_FOR_MULTI_REGION = 4; + private static final int SHORT_BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION = 10; + private static final int CPU_CNT = Runtime.getRuntime().availableProcessors(); + private static final int DEFAULT_DIRECT_HTTPS_POOL_SIZE = CPU_CNT * 500; + + private static final String REACTOR_NETTY_CONNECTION_POOL_NAME = "reactor-netty-connection-pool"; + + public Configs() { + this.sslContext = sslContextInit(); + } + + private SslContext sslContextInit() { + try { + SslProvider sslProvider = SslContext.defaultClientProvider(); + return SslContextBuilder.forClient().sslProvider(sslProvider).build(); + } catch (SSLException sslException) { + logger.error("Fatal error cannot instantiate ssl context due to {}", sslException.getMessage(), sslException); + throw new IllegalStateException(sslException); + } + } + + public SslContext getSslContext() { + return this.sslContext; + } + + public Protocol getProtocol() { + String protocol = getJVMConfigAsString(PROTOCOL, DEFAULT_PROTOCOL.toString()); + try { + return Protocol.valueOf(StringUtils.upperCase(protocol.toLowerCase())); + } catch (Exception e) { + logger.error("Parsing protocol {} failed. Using the default {}.", protocol, DEFAULT_PROTOCOL, e); + return DEFAULT_PROTOCOL; + } + } + + public int getMaxNumberOfReadBarrierReadRetries() { + return MAX_NUMBER_OF_READ_BARRIER_READ_RETRIES; + } + + public int getMaxNumberOfPrimaryReadRetries() { + return MAX_NUMBER_OF_PRIMARY_READ_RETRIES; + } + + public int getMaxNumberOfReadQuorumRetries() { + return MAX_NUMBER_OF_READ_QUORUM_RETRIES; + } + + public int getDelayBetweenReadBarrierCallsInMs() { + return DELAY_BETWEEN_READ_BARRIER_CALLS_IN_MS; + } + + public int getMaxBarrierRetriesForMultiRegion() { + return MAX_BARRIER_RETRIES_FOR_MULTI_REGION; + } + + public int getBarrierRetryIntervalInMsForMultiRegion() { + return BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION; + } + + public int getMaxShortBarrierRetriesForMultiRegion() { + return MAX_SHORT_BARRIER_RETRIES_FOR_MULTI_REGION; + } + + public int getShortBarrierRetryIntervalInMsForMultiRegion() { + return SHORT_BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION; + } + + public int getDirectHttpsMaxConnectionLimit() { + return getJVMConfigAsInt(MAX_DIRECT_HTTPS_POOL_SIZE, DEFAULT_DIRECT_HTTPS_POOL_SIZE); + } + + public int getMaxHttpHeaderSize() { + return getJVMConfigAsInt(MAX_HTTP_HEADER_SIZE_IN_BYTES, DEFAULT_MAX_HTTP_REQUEST_HEADER_SIZE); + } + + public int getMaxHttpInitialLineLength() { + return getJVMConfigAsInt(MAX_HTTP_INITIAL_LINE_LENGTH_IN_BYTES, DEFAULT_MAX_HTTP_INITIAL_LINE_LENGTH); + } + + public int getMaxHttpChunkSize() { + return getJVMConfigAsInt(MAX_HTTP_CHUNK_SIZE_IN_BYTES, DEFAULT_MAX_HTTP_CHUNK_SIZE_IN_BYTES); + } + + public int getMaxHttpBodyLength() { + return getJVMConfigAsInt(MAX_HTTP_BODY_LENGTH_IN_BYTES, DEFAULT_MAX_HTTP_BODY_LENGTH_IN_BYTES); + } + + public int getUnavailableLocationsExpirationTimeInSeconds() { + return getJVMConfigAsInt(UNAVAILABLE_LOCATIONS_EXPIRATION_TIME_IN_SECONDS, DEFAULT_UNAVAILABLE_LOCATIONS_EXPIRATION_TIME_IN_SECONDS); + } + + public String getReactorNettyConnectionPoolName() { + return REACTOR_NETTY_CONNECTION_POOL_NAME; + } + + private static String getJVMConfigAsString(String propName, String defaultValue) { + String propValue = System.getProperty(propName); + return StringUtils.defaultString(propValue, defaultValue); + } + + private static int getJVMConfigAsInt(String propName, int defaultValue) { + String propValue = System.getProperty(propName); + return getIntValue(propValue, defaultValue); + } + + private static int getIntValue(String val, int defaultValue) { + if (StringUtils.isEmpty(val)) { + return defaultValue; + } else { + return Integer.valueOf(val); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Conflict.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Conflict.java new file mode 100644 index 0000000000000..12133673af9c3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Conflict.java @@ -0,0 +1,99 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; + +import java.lang.reflect.InvocationTargetException; + +/** + * Represents a conflict in the version of a particular resource in the Azure Cosmos DB database service. + *

    + * During rare failure scenarios, conflicts are generated for the documents in transit. Clients can inspect the + * respective conflict instances for resources and operations in conflict. + */ +public final class Conflict extends Resource { + /** + * Initialize a conflict object. + */ + public Conflict() { + super(); + } + + /** + * Initialize a conflict object from json string. + * + * @param jsonString the json string that represents the conflict. + */ + public Conflict(String jsonString) { + super(jsonString); + } + + /** + * Gets the operation kind. + * + * @return the operation kind. + */ + public String getOperationKind() { + return super.getString(Constants.Properties.OPERATION_TYPE); + } + + /** + * Gets the type of the conflicting resource. + * + * @return the resource type. + */ + public String getResouceType() { + return super.getString(Constants.Properties.RESOURCE_TYPE); + } + + /** + * Gets the resource ID for the conflict in the Azure Cosmos DB service. + * @return resource Id for the conflict. + */ + public String getSourceResourceId() { + return super.getString(Constants.Properties.SOURCE_RESOURCE_ID); + } + + /** + * Gets the conflicting resource in the Azure Cosmos DB service. + * @param the type of the object. + * @param klass The returned type of conflicting resource. + * @return The conflicting resource. + */ + public T getResource(Class klass) { + String resourceAsString = super.getString(Constants.Properties.CONTENT); + + if (!Strings.isNullOrEmpty(resourceAsString)) { + try { + return klass.getConstructor(String.class).newInstance(resourceAsString); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + } else { + return null; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Constants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Constants.java new file mode 100644 index 0000000000000..adc9f98681a44 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Constants.java @@ -0,0 +1,224 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Used internally. Constants in the Azure Cosmos DB database service Java SDK. + */ +public final class Constants { + + public static final class Quota { + // Quota Strings + public static final String DATABASE = "databases"; + public static final String COLLECTION = "collections"; + public static final String USER = "users"; + public static final String PERMISSION = "permissions"; + public static final String COLLECTION_SIZE = "collectionSize"; + public static final String DOCUMENTS_SIZE = "documentsSize"; + public static final String STORED_PROCEDURE = "storedProcedures"; + public static final String TRIGGER = "triggers"; + public static final String USER_DEFINED_FUNCTION = "functions"; + public static final String DELIMITER_CHARS = "=|;"; + public static final String DOCUMENTS_COUNT = "documentsCount"; + } + + public static final class Properties { + public static final String ID = "id"; + public static final String R_ID = "_rid"; + public static final String SELF_LINK = "_self"; + public static final String LAST_MODIFIED = "_ts"; + public static final String COUNT = "_count"; + public static final String E_TAG = "_etag"; + public static final String AGGREGATE = "_aggregate"; + + public static final String CONSISTENCY_POLICY = "consistencyPolicy"; + public static final String DEFAULT_CONSISTENCY_LEVEL = "defaultConsistencyLevel"; + public static final String MAX_STALENESS_PREFIX = "maxStalenessPrefix"; + public static final String MAX_STALENESS_INTERVAL_IN_SECONDS = "maxIntervalInSeconds"; + public static final String PARENTS = "parents"; + + public static final String DATABASES_LINK = "_dbs"; + public static final String COLLECTIONS_LINK = "_colls"; + public static final String USERS_LINK = "_users"; + public static final String PERMISSIONS_LINK = "_permissions"; + public static final String ATTACHMENTS_LINK = "_attachments"; + public static final String STORED_PROCEDURES_LINK = "_sprocs"; + public static final String TRIGGERS_LINK = "_triggers"; + public static final String USER_DEFINED_FUNCTIONS_LINK = "_udfs"; + public static final String CONFLICTS_LINK = "_conflicts"; + public static final String DOCUMENTS_LINK = "_docs"; + public static final String RESOURCE_LINK = "resource"; + public static final String MEDIA_LINK = "media"; + + public static final String PERMISSION_MODE = "permissionMode"; + public static final String RESOURCE_KEY = "key"; + public static final String TOKEN = "_token"; + public static final String SQL_API_TYPE = "0x10"; + + // Scripting + public static final String BODY = "body"; + public static final String TRIGGER_TYPE = "triggerType"; + public static final String TRIGGER_OPERATION = "triggerOperation"; + + public static final String MAX_SIZE = "maxSize"; + public static final String CURRENT_USAGE = "currentUsage"; + + public static final String CONTENT = "content"; + + public static final String CONTENT_TYPE = "contentType"; + + // ErrorResource. + public static final String CODE = "code"; + public static final String MESSAGE = "message"; + public static final String ERROR_DETAILS = "errorDetails"; + public static final String ADDITIONAL_ERROR_INFO = "additionalErrorInfo"; + + // PartitionInfo. + public static final String RESOURCE_TYPE = "resourceType"; + public static final String SERVICE_INDEX = "serviceIndex"; + public static final String PARTITION_INDEX = "partitionIndex"; + + public static final String ADDRESS_LINK = "addresses"; + public static final String USER_REPLICATION_POLICY = "userReplicationPolicy"; + public static final String USER_CONSISTENCY_POLICY = "userConsistencyPolicy"; + public static final String SYSTEM_REPLICATION_POLICY = "systemReplicationPolicy"; + public static final String READ_POLICY = "readPolicy"; + public static final String QUERY_ENGINE_CONFIGURATION = "queryEngineConfiguration"; + + //ReplicationPolicy + public static final String REPLICATION_POLICY = "replicationPolicy"; + public static final String ASYNC_REPLICATION = "asyncReplication"; + public static final String MAX_REPLICA_SET_SIZE = "maxReplicasetSize"; + public static final String MIN_REPLICA_SET_SIZE = "minReplicaSetSize"; + + //Indexing Policy. + public static final String INDEXING_POLICY = "indexingPolicy"; + public static final String AUTOMATIC = "automatic"; + public static final String STRING_PRECISION = "StringPrecision"; + public static final String NUMERIC_PRECISION = "NumericPrecision"; + public static final String MAX_PATH_DEPTH = "maxPathDepth"; + public static final String INDEXING_MODE = "indexingMode"; + public static final String INDEX_TYPE = "IndexType"; + public static final String INDEX_KIND = "kind"; + public static final String DATA_TYPE = "dataType"; + public static final String PRECISION = "precision"; + + public static final String PATHS = "paths"; + public static final String PATH = "path"; + public static final String INCLUDED_PATHS = "includedPaths"; + public static final String EXCLUDED_PATHS = "excludedPaths"; + public static final String INDEXES = "indexes"; + public static final String COMPOSITE_INDEXES = "compositeIndexes"; + public static final String ORDER = "order"; + public static final String SPATIAL_INDEXES = "spatialIndexes"; + public static final String TYPES = "types"; + + // Unique index. + public static final String UNIQUE_KEY_POLICY = "uniqueKeyPolicy"; + public static final String UNIQUE_KEYS = "uniqueKeys"; + + // Conflict. + public static final String CONFLICT = "conflict"; + public static final String OPERATION_TYPE = "operationType"; + public static final String SOURCE_RESOURCE_ID = "resourceId"; + + // Offer resource + public static final String OFFER_TYPE = "offerType"; + public static final String OFFER_VERSION = "offerVersion"; + public static final String OFFER_CONTENT = "content"; + public static final String OFFER_THROUGHPUT = "offerThroughput"; + public static final String OFFER_VERSION_V1 = "V1"; + public static final String OFFER_VERSION_V2 = "V2"; + public static final String OFFER_RESOURCE_ID = "offerResourceId"; + + // PartitionKey + public static final String PARTITION_KEY = "partitionKey"; + public static final String PARTITION_KEY_PATHS = "paths"; + public static final String PARTITION_KIND = "kind"; + public static final String PARTITION_KEY_DEFINITION_VERSION = "version"; + public static final String SYSTEM_KEY = "systemKey"; + + public static final String RESOURCE_PARTITION_KEY = "resourcePartitionKey"; + public static final String PARTITION_KEY_RANGE_ID = "partitionKeyRangeId"; + public static final String MIN_INCLUSIVE_EFFECTIVE_PARTITION_KEY = "minInclusiveEffectivePartitionKey"; + public static final String MAX_EXCLUSIVE_EFFECTIVE_PARTITION_KEY = "maxExclusiveEffectivePartitionKey"; + + // AddressResource + public static final String IS_PRIMARY = "isPrimary"; + public static final String PROTOCOL = "protocol"; + public static final String LOGICAL_URI = "logicalUri"; + public static final String PHYISCAL_URI = "physcialUri"; + + // Time-to-Live + public static final String TTL = "ttl"; + public static final String DEFAULT_TTL = "defaultTtl"; + + // Global DB account properties + public static final String Name = "name"; + public static final String WRITABLE_LOCATIONS = "writableLocations"; + public static final String READABLE_LOCATIONS = "readableLocations"; + public static final String DATABASE_ACCOUNT_ENDPOINT = "databaseAccountEndpoint"; + + //Authorization + public static final String MASTER_TOKEN = "master"; + public static final String RESOURCE_TOKEN = "resource"; + public static final String TOKEN_VERSION = "1.0"; + public static final String AUTH_SCHEMA_TYPE = "type"; + public static final String AUTH_VERSION = "ver"; + public static final String AUTH_SIGNATURE = "sig"; + public static final String READ_PERMISSION_MODE = "read"; + public static final String ALL_PERMISSION_MODE = "all"; + public static final String PATH_SEPARATOR = "/"; + + public static final int DEFAULT_MAX_PAGE_SIZE = 100; + public static final String ENABLE_MULTIPLE_WRITE_LOCATIONS = "enableMultipleWriteLocations"; + + // Conflict resolution policy + public static final String CONFLICT_RESOLUTION_POLICY = "conflictResolutionPolicy"; + public static final String MODE = "mode"; + public static final String CONFLICT_RESOLUTION_PATH = "conflictResolutionPath"; + public static final String CONFLICT_RESOLUTION_PROCEDURE = "conflictResolutionProcedure"; + + //Handler names for RXNetty httpClient + public static final String SSL_HANDLER_NAME = "ssl-handler"; + public static final String SSL_COMPLETION_HANDLER_NAME = "ssl-completion-handler"; + public static final String HTTP_PROXY_HANDLER_NAME = "http-proxy-handler"; + public static final String LOGGING_HANDLER_NAME = "logging-handler"; + } + + public static final class UrlEncodingInfo { + public static final String PLUS_SYMBOL_ESCAPED = "\\+"; + public static final String PLUS_SYMBOL_URI_ENCODING = "%2b"; + public static final String SINGLE_SPACE_URI_ENCODING = "%20"; + public static final String UTF_8 = "UTF-8"; + } + + public static final class PartitionedQueryExecutionInfo { + public static final int VERSION_1 = 1; + } + + public static final class QueryExecutionContext { + public static final String INCREMENTAL_FEED_HEADER_VALUE = "Incremental feed"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ContentSerializationFormat.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ContentSerializationFormat.java new file mode 100644 index 0000000000000..12edb9f2d6df8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ContentSerializationFormat.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +public enum ContentSerializationFormat { + /** + * Standard JSON RFC UTF-8 text + */ + JsonText, + + /** + * CUSTOM binary for Cosmos DB that encodes a superset of JSON values. + */ + CosmosBinary, +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Database.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Database.java new file mode 100644 index 0000000000000..af8e1df73cb0e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Database.java @@ -0,0 +1,86 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a Database in the Azure Cosmos DB database service. A database manages users, permissions and a set of collections + *

    + * Each Azure Cosmos DB Service is able to support multiple independent named databases, with the database being the + * logical container for data. Each Database consists of one or more collections, each of which in turn contain one or + * more documents. Since databases are an an administrative resource and the Service Master Key will be required in + * order to access and successfully complete any action using the User APIs. + */ +public final class Database extends Resource { + + /** + * Initialize a database object. + */ + public Database() { + super(); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of Database + */ + public Database id(String id){ + super.id(id); + return this; + } + + /** + * Initialize a database object from json string. + * + * @param jsonString the json string. + */ + public Database(String jsonString) { + super(jsonString); + } + + /** + * Gets the self-link for collections in the database + * + * @return the collections link. + */ + public String getCollectionsLink() { + return String.format("%s/%s", + StringUtils.stripEnd(super.selfLink(), "/"), + super.getString(Constants.Properties.COLLECTIONS_LINK)); + } + + /** + * Gets the self-link for users in the database. + * + * @return the users link. + */ + public String getUsersLink() { + return String.format("%s/%s", + StringUtils.stripEnd(super.selfLink(), "/"), + super.getString(Constants.Properties.USERS_LINK)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccount.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccount.java new file mode 100644 index 0000000000000..8f2fd00f6e016 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccount.java @@ -0,0 +1,291 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConsistencyPolicy; +import com.azure.data.cosmos.Resource; +import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static com.azure.data.cosmos.BridgeInternal.setProperty; +import static com.azure.data.cosmos.BridgeInternal.setResourceSelfLink; +import static com.azure.data.cosmos.BridgeInternal.populatePropertyBagJsonSerializable; + +/** + * Represents a database account in the Azure Cosmos DB database service. + */ +public class DatabaseAccount extends Resource { + private ConsistencyPolicy consistencyPolicy; + + private long maxMediaStorageUsageInMB; + private long mediaStorageUsageInMB; + private ReplicationPolicy replicationPolicy; + private ReplicationPolicy systemReplicationPolicy; + private Map queryEngineConfiguration; + + /** + * Constructor. + */ + public DatabaseAccount() { + setResourceSelfLink(this, ""); + } + + /** + * Initialize a database account object from json string. + * + * @param jsonString the json string that represents the database account. + */ + public DatabaseAccount(String jsonString) { + super(jsonString); + } + + /** + * Get the databases link of the databaseAccount. + * + * @return the databases link. + */ + public String getDatabasesLink() { + return super.getString(Constants.Properties.DATABASES_LINK); + } + + /** + * Set the databases of the databaseAccount. + * + * @param databasesLink the databases link. + */ + public void setDatabasesLink(String databasesLink) { + setProperty(this, Constants.Properties.DATABASES_LINK, databasesLink); + } + + /** + * Get the medialink of the databaseAccount. + * + * @return the media link. + */ + public String getMediaLink() { + return super.getString(Constants.Properties.MEDIA_LINK); + } + + /** + * Set the medialink of the databaseAccount. + * + * @param medialink the media link. + */ + public void setMediaLink(String medialink) { + setProperty(this, Constants.Properties.MEDIA_LINK, medialink); + } + + /** + * Get the addresseslink of the databaseAccount. + * + * @return the addresses link. + */ + public String getAddressesLink() { + return super.getString(Constants.Properties.ADDRESS_LINK); + } + + /** + * Set the addresseslink of the databaseAccount. + * + * @param addresseslink the addresses link. + */ + public void setAddressesLink(String addresseslink) { + setProperty(this, Constants.Properties.ADDRESS_LINK, addresseslink); + } + + /** + * Attachment content (media) storage quota in MBs Retrieved from gateway. + * + * @return the max media storage usage in MB. + */ + public long getMaxMediaStorageUsageInMB() { + return this.maxMediaStorageUsageInMB; + } + + public void setMaxMediaStorageUsageInMB(long value) { + this.maxMediaStorageUsageInMB = value; + } + + /** + * Current attachment content (media) usage in MBs. + *

    + * Retrieved from gateway. Value is returned from cached information updated + * periodically and is not guaranteed to be real time. + * + * @return the media storage usage in MB. + */ + public long getMediaStorageUsageInMB() { + return this.mediaStorageUsageInMB; + } + + public void setMediaStorageUsageInMB(long value) { + this.mediaStorageUsageInMB = value; + } + + /** + * Gets the ConsistencyPolicy properties. + * + * @return the consistency policy. + */ + public ConsistencyPolicy getConsistencyPolicy() { + if (this.consistencyPolicy == null) { + this.consistencyPolicy = super.getObject(Constants.Properties.USER_CONSISTENCY_POLICY, + ConsistencyPolicy.class); + + if (this.consistencyPolicy == null) { + this.consistencyPolicy = new ConsistencyPolicy(); + } + } + return this.consistencyPolicy; + } + + /** + * Gets the ReplicationPolicy properties. + * + * @return the replication policy. + */ + public ReplicationPolicy getReplicationPolicy() { + if (this.replicationPolicy == null) { + this.replicationPolicy = super.getObject(Constants.Properties.USER_REPLICATION_POLICY, + ReplicationPolicy.class); + + if (this.replicationPolicy == null) { + this.replicationPolicy = new ReplicationPolicy(); + } + } + + return this.replicationPolicy; + } + + /** + * Gets the SystemReplicationPolicy properties. + * + * @return the system replication policy. + */ + public ReplicationPolicy getSystemReplicationPolicy() { + if (this.systemReplicationPolicy == null) { + this.systemReplicationPolicy = super.getObject(Constants.Properties.SYSTEM_REPLICATION_POLICY, + ReplicationPolicy.class); + + if (this.systemReplicationPolicy == null) { + this.systemReplicationPolicy = new ReplicationPolicy(); + } + } + + return this.systemReplicationPolicy; + } + + /** + * Gets the QueryEngineConfiuration properties. + * + * @return the query engine configuration. + */ + public Map getQueryEngineConfiuration() { + if (this.queryEngineConfiguration == null) { + String queryEngineConfigurationJsonString = super.getObject(Constants.Properties.QUERY_ENGINE_CONFIGURATION, + String.class); + if (StringUtils.isNotEmpty(queryEngineConfigurationJsonString)) { + TypeReference> typeRef = new TypeReference>() { + }; + try { + this.queryEngineConfiguration = Utils.getSimpleObjectMapper() + .readValue(queryEngineConfigurationJsonString, typeRef); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + if (this.queryEngineConfiguration == null) { + this.queryEngineConfiguration = new HashMap<>(); + } + } + } + + return this.queryEngineConfiguration; + } + + /** + * Gets the list of writable locations for this database account. + * + * @return the list of writable locations. + */ + public Iterable getWritableLocations() { + return super.getCollection(Constants.Properties.WRITABLE_LOCATIONS, DatabaseAccountLocation.class); + } + + /** + * Sets the list of writable locations for this database account. + *

    + * The list of writable locations are returned by the service. + * + * @param locations the list of writable locations. + */ + public void setWritableLocations(Iterable locations) { + setProperty(this, Constants.Properties.WRITABLE_LOCATIONS, locations); + } + + /** + * Gets the list of readable locations for this database account. + * + * @return the list of readable locations. + */ + public Iterable getReadableLocations() { + return super.getCollection(Constants.Properties.READABLE_LOCATIONS, DatabaseAccountLocation.class); + } + + /** + * Sets the list of readable locations for this database account. + *

    + * The list of readable locations are returned by the service. + * + * @param locations the list of readable locations. + */ + public void setReadableLocations(Iterable locations) { + setProperty(this, Constants.Properties.READABLE_LOCATIONS, locations); + } + + public boolean isEnableMultipleWriteLocations() { + return ObjectUtils.defaultIfNull(super.getBoolean(Constants.Properties.ENABLE_MULTIPLE_WRITE_LOCATIONS), false); + } + + public void setEnableMultipleWriteLocations(boolean value) { + setProperty(this, Constants.Properties.ENABLE_MULTIPLE_WRITE_LOCATIONS, value); + } + + public void populatePropertyBag() { + if (this.consistencyPolicy != null) { + populatePropertyBagJsonSerializable(this.consistencyPolicy); + setProperty(this, Constants.Properties.USER_CONSISTENCY_POLICY, this.consistencyPolicy); + } + } + + @Override + public String toJson() { + this.populatePropertyBag(); + return super.toJson(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountConfigurationProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountConfigurationProvider.java new file mode 100644 index 0000000000000..a82915676cb05 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountConfigurationProvider.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConsistencyLevel; + +/** + * Defines an interface to work with database account configuration in the Azure Cosmos DB database service. + */ +public interface DatabaseAccountConfigurationProvider { + ConsistencyLevel getStoreConsistencyPolicy(); + + int getMaxReplicaSetSize(); + + String getQueryEngineConfiguration(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountLocation.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountLocation.java new file mode 100644 index 0000000000000..160dd825ee868 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountLocation.java @@ -0,0 +1,88 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.JsonSerializable; + +import static com.azure.data.cosmos.BridgeInternal.setProperty; + +/** + * Represents the location of a database account in the Azure Cosmos DB database service. + */ +public class DatabaseAccountLocation extends JsonSerializable { + + /** + * DEFAULT Constructor. Creates a new instance of the + * DatabaseAccountLocation object. + */ + public DatabaseAccountLocation() { + super(); + } + + /** + * Creates a new instance of the DatabaseAccountLocation object from a JSON + * string. + * + * @param jsonString the JSON string that represents the DatabaseAccountLocation object. + */ + public DatabaseAccountLocation(String jsonString) { + super(jsonString); + } + + /** + * Gets The name of the database account location. + * + * @return the name of the database account location. + */ + public String getName() { + return super.getString(Constants.Properties.Name); + } + + /** + * Sets the name of the database account location. + * + * @param name the name of the database account location. + */ + public void setName(String name) { + setProperty(this, Constants.Properties.Name, name); + } + + /** + * Gets The endpoint (the URI) of the database account location. + * + * @return the endpoint of the database account location. + */ + public String getEndpoint() { + return super.getString(Constants.Properties.DATABASE_ACCOUNT_ENDPOINT); + } + + /** + * Sets the endpoint (the URI) of the database account location. + * + * @param endpoint the endpoint of the database account location. + */ + public void setEndpoint(String endpoint) { + setProperty(this, Constants.Properties.DATABASE_ACCOUNT_ENDPOINT, endpoint); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountManagerInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountManagerInternal.java new file mode 100644 index 0000000000000..e423da21f639a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseAccountManagerInternal.java @@ -0,0 +1,54 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConnectionPolicy; +import reactor.core.publisher.Flux; + +import java.net.URI; + +public interface DatabaseAccountManagerInternal { + + /** + * Gets database account information. + * + * @param endpoint the endpoint from which gets the database account + * @return the database account. + */ + Flux getDatabaseAccountFromEndpoint(URI endpoint); + + /** + * Gets the connection policy + * + * @return connection policy + */ + ConnectionPolicy getConnectionPolicy(); + + /** + * Gets the service endpoint + * + * @return service endpoint + */ + URI getServiceEndpoint(); + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseForTest.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseForTest.java new file mode 100644 index 0000000000000..3d2ca095c6f3b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DatabaseForTest.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +public class DatabaseForTest { + private static Logger logger = LoggerFactory.getLogger(DatabaseForTest.class); + public static final String SHARED_DB_ID_PREFIX = "RxJava.SDKTest.SharedDatabase"; + private static final Duration CLEANUP_THRESHOLD_DURATION = Duration.ofHours(2); + private static final String DELIMITER = "_"; + private static DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); + + public LocalDateTime createdTime; + public Database createdDatabase; + + private DatabaseForTest(Database db, LocalDateTime createdTime) { + this.createdDatabase = db; + this.createdTime = createdTime; + } + + private boolean isStale() { + return isOlderThan(CLEANUP_THRESHOLD_DURATION); + } + + private boolean isOlderThan(Duration dur) { + return createdTime.isBefore(LocalDateTime.now().minus(dur)); + } + + public static String generateId() { + return SHARED_DB_ID_PREFIX + DELIMITER + TIME_FORMATTER.format(LocalDateTime.now()) + DELIMITER + RandomStringUtils.randomAlphabetic(3); + } + + private static DatabaseForTest from(Database db) { + if (db == null || db.id() == null || db.selfLink() == null) { + return null; + } + + String id = db.id(); + if (id == null) { + return null; + } + + String[] parts = StringUtils.split(id, DELIMITER); + if (parts.length != 3) { + return null; + } + if (!StringUtils.equals(parts[0], SHARED_DB_ID_PREFIX)) { + return null; + } + + try { + LocalDateTime parsedTime = LocalDateTime.parse(parts[1], TIME_FORMATTER); + return new DatabaseForTest(db, parsedTime); + } catch (Exception e) { + return null; + } + } + + public static DatabaseForTest create(DatabaseManager client) { + Database dbDef = new Database(); + dbDef.id(generateId()); + + Database db = client.createDatabase(dbDef).single().block().getResource(); + DatabaseForTest dbForTest = DatabaseForTest.from(db); + assert(dbForTest != null); + return dbForTest; + } + + public static void cleanupStaleTestDatabases(DatabaseManager client) { + logger.info("Cleaning stale test databases ..."); + List dbs = client.queryDatabases( + new SqlQuerySpec("SELECT * FROM c WHERE STARTSWITH(c.id, @PREFIX)", + new SqlParameterList(new SqlParameter("@PREFIX", DatabaseForTest.SHARED_DB_ID_PREFIX)))) + .flatMap(page -> Flux.fromIterable(page.results())).collectList().block(); + + for (Database db : dbs) { + assert(db.id().startsWith(DatabaseForTest.SHARED_DB_ID_PREFIX)); + + DatabaseForTest dbForTest = DatabaseForTest.from(db); + + if (db != null && dbForTest.isStale()) { + logger.info("Deleting database {}", db.id()); + client.deleteDatabase(db.id()).single().block(); + } + } + } + + public interface DatabaseManager { + Flux> queryDatabases(SqlQuerySpec query); + Flux> createDatabase(Database databaseDefinition); + Flux> deleteDatabase(String id); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Document.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Document.java new file mode 100644 index 0000000000000..9e4f5e2dfb9ca --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Document.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; + +import static com.azure.data.cosmos.BridgeInternal.remove; +import static com.azure.data.cosmos.BridgeInternal.setProperty; +import static com.azure.data.cosmos.BridgeInternal.setMapper; + +/** + * Represents a document in the Azure Cosmos DB database service. + *

    + * A document is a structured JSON document. There is no set schema for the JSON documents, and a document may contain + * any number of custom properties as well as an optional list of attachments. Document is an application resource and + * can be authorized using the master key or resource keys. + */ +public class Document extends Resource { + + /** + * Initialize a document object. + */ + public Document() { + super(); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of the Document + */ + public Document id(String id){ + super.id(id); + return this; + } + + /** + * Initialize a document object from json string. + * + * @param jsonString the json string that represents the document object. + * @param objectMapper the custom object mapper + */ + Document(String jsonString, ObjectMapper objectMapper) { + // TODO: Made package private due to #153. #171 adding custom serialization options back. + super(jsonString); + setMapper(this, objectMapper); + } + + /** + * Initialize a document object from json string. + * + * @param jsonString the json string that represents the document object. + */ + public Document(String jsonString) { + super(jsonString); + } + + public static Document FromObject(Object document, ObjectMapper objectMapper) { + Document typedDocument; + if (document instanceof Document) { + typedDocument = (Document) document; + } else { + try { + return new Document(objectMapper.writeValueAsString(document)); + } catch (IOException e) { + throw new IllegalArgumentException("Can't serialize the object into the json string", e); + } + } + return typedDocument; + } + + /** + * Gets the document's time-to-live value. + * + * @return the document's time-to-live value in seconds. + */ + public Integer getTimeToLive() { + if (super.has(Constants.Properties.TTL)) { + return super.getInt(Constants.Properties.TTL); + } + + return null; + } + + /** + * Sets the document's time-to-live value. + *

    + * A document's time-to-live value is an optional property. If set, the document expires after the specified number + * of seconds since its last write time. The value of this property should be one of the following: + *

    + * null - indicates the time-to-live value for this document inherits from the parent collection's default time-to-live value. + *

    + * nonzero positive integer - indicates the number of seconds before the document expires. It overrides the default time-to-live + * value specified on the parent collection, unless the parent collection's default time-to-live is null. + *

    + * -1 - indicates the document never expires. It overrides the default time-to-live + * value specified on the parent collection, unless the parent collection's default time-to-live is null. + * + * @param timeToLive the document's time-to-live value in seconds. + */ + public void setTimeToLive(Integer timeToLive) { + // a "null" value is represented as a missing element on the wire. + // setting timeToLive to null should remove the property from the property bag. + if (timeToLive != null) { + setProperty(this, Constants.Properties.TTL, timeToLive); + } else if (super.has(Constants.Properties.TTL)) { + remove(this, Constants.Properties.TTL); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentCollection.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentCollection.java new file mode 100644 index 0000000000000..13e552434f094 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentCollection.java @@ -0,0 +1,320 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConflictResolutionPolicy; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.UniqueKeyPolicy; +import org.apache.commons.lang3.StringUtils; + +import static com.azure.data.cosmos.BridgeInternal.populatePropertyBagJsonSerializable; +import static com.azure.data.cosmos.BridgeInternal.setProperty; +import static com.azure.data.cosmos.BridgeInternal.remove; + +/** + * Represents a document collection in the Azure Cosmos DB database service. A collection is a named logical container + * for documents. + *

    + * A database may contain zero or more named collections and each collection consists of zero or more JSON documents. + * Being schema-free, the documents in a collection do not need to share the same structure or fields. Since collections + * are application resources, they can be authorized using either the master key or resource keys. + */ +public final class DocumentCollection extends Resource { + private IndexingPolicy indexingPolicy; + private UniqueKeyPolicy uniqueKeyPolicy; + private PartitionKeyDefinition partitionKeyDefinition; + + /** + * Initialize a document collection object. + */ + public DocumentCollection() { + super(); + } + + /** + * Sets the id and returns the document collection + * @param id the name of the resource. + * @return + */ + public DocumentCollection id(String id){ + super.id(id); + return this; + } + + /** + * Initialize a document collection object from json string. + * + * @param jsonString the json string that represents the document collection. + */ + public DocumentCollection(String jsonString) { + super(jsonString); + } + + /** + * Gets the indexing policy. + * + * @return the indexing policy. + */ + public IndexingPolicy getIndexingPolicy() { + if (this.indexingPolicy == null) { + if (super.has(Constants.Properties.INDEXING_POLICY)) { + this.indexingPolicy = super.getObject(Constants.Properties.INDEXING_POLICY, IndexingPolicy.class); + } else { + this.indexingPolicy = new IndexingPolicy(); + } + } + + return this.indexingPolicy; + } + + /** + * Sets the indexing policy. + * + * @param indexingPolicy the indexing policy. + */ + public void setIndexingPolicy(IndexingPolicy indexingPolicy) { + if (indexingPolicy == null) { + throw new IllegalArgumentException("IndexingPolicy cannot be null."); + } + + this.indexingPolicy = indexingPolicy; + } + + /** + * Gets the collection's partition key definition. + * + * @return the partition key definition. + */ + public PartitionKeyDefinition getPartitionKey() { + if (this.partitionKeyDefinition == null) { + + if (super.has(Constants.Properties.PARTITION_KEY)) { + this.partitionKeyDefinition = super.getObject(Constants.Properties.PARTITION_KEY, PartitionKeyDefinition.class); + } else { + this.partitionKeyDefinition = new PartitionKeyDefinition(); + } + } + + return this.partitionKeyDefinition; + } + + /** + * Sets the collection's partition key definition. + * + * @param partitionKey the partition key definition. + */ + public void setPartitionKey(PartitionKeyDefinition partitionKey) { + if (partitionKey == null) { + throw new IllegalArgumentException("partitionKeyDefinition cannot be null."); + } + + this.partitionKeyDefinition = partitionKey; + } + + /** + * Gets the collection's default time-to-live value. + * + * @return the default time-to-live value in seconds. + */ + public Integer getDefaultTimeToLive() { + if (super.has(Constants.Properties.DEFAULT_TTL)) { + return super.getInt(Constants.Properties.DEFAULT_TTL); + } + + return null; + } + + /** + * Sets the collection's default time-to-live value. + *

    + * The default time-to-live value on a collection is an optional property. If set, the documents within the collection + * expires after the specified number of seconds since their last write time. The value of this property should be one of the following: + *

    + * null - indicates evaluation of time-to-live is disabled and documents within the collection will never expire, regardless whether + * individual documents have their time-to-live set. + *

    + * nonzero positive integer - indicates the default time-to-live value for all documents within the collection. This value can be overridden + * by individual documents' time-to-live value. + *

    + * -1 - indicates by default all documents within the collection never expire. This value can be overridden by individual documents' + * time-to-live value. + * + * @param timeToLive the default time-to-live value in seconds. + */ + public void setDefaultTimeToLive(Integer timeToLive) { + // a "null" value is represented as a missing element on the wire. + // setting timeToLive to null should remove the property from the property bag. + if (timeToLive != null) { + setProperty(this, Constants.Properties.DEFAULT_TTL, timeToLive); + } else if (super.has(Constants.Properties.DEFAULT_TTL)) { + remove(this, Constants.Properties.DEFAULT_TTL); + } + } + + /** + * Sets the Uni that guarantees uniqueness of documents in collection in the Azure Cosmos DB service. + * @return UniqueKeyPolicy + */ + public UniqueKeyPolicy getUniqueKeyPolicy() { + + // Thread safe lazy initialization for case when collection is cached (and is basically readonly). + if (this.uniqueKeyPolicy == null) { + this.uniqueKeyPolicy = super.getObject(Constants.Properties.UNIQUE_KEY_POLICY, UniqueKeyPolicy.class); + + if (this.uniqueKeyPolicy == null) { + this.uniqueKeyPolicy = new UniqueKeyPolicy(); + } + } + + return this.uniqueKeyPolicy; + } + + public void setUniqueKeyPolicy(UniqueKeyPolicy uniqueKeyPolicy) { + if (uniqueKeyPolicy == null) { + throw new IllegalArgumentException("uniqueKeyPolicy cannot be null."); + } + + this.uniqueKeyPolicy = uniqueKeyPolicy; + setProperty(this, Constants.Properties.UNIQUE_KEY_POLICY, uniqueKeyPolicy); + } + + /** + * Gets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @return ConflictResolutionPolicy + */ + public ConflictResolutionPolicy getConflictResolutionPolicy() { + return super.getObject(Constants.Properties.CONFLICT_RESOLUTION_POLICY, ConflictResolutionPolicy.class); + } + + /** + * Sets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @param value ConflictResolutionPolicy to be used. + */ + public void setConflictResolutionPolicy(ConflictResolutionPolicy value) { + if (value == null) { + throw new IllegalArgumentException("CONFLICT_RESOLUTION_POLICY cannot be null."); + } + + setProperty(this, Constants.Properties.CONFLICT_RESOLUTION_POLICY, value); + } + + + /** + * Gets the self-link for documents in a collection. + * + * @return the document link. + */ + public String getDocumentsLink() { + return String.format("%s/%s", + StringUtils.stripEnd(super.selfLink(), "/"), + super.getString(Constants.Properties.DOCUMENTS_LINK)); + } + + /** + * Gets the self-link for stored procedures in a collection. + * + * @return the stored procedures link. + */ + public String getStoredProceduresLink() { + return String.format("%s/%s", + StringUtils.stripEnd(super.selfLink(), "/"), + super.getString(Constants.Properties.STORED_PROCEDURES_LINK)); + } + + /** + * Gets the self-link for triggers in a collection. + * + * @return the trigger link. + */ + public String getTriggersLink() { + return StringUtils.removeEnd(this.selfLink(), "/") + + "/" + super.getString(Constants.Properties.TRIGGERS_LINK); + } + + /** + * Gets the self-link for user defined functions in a collection. + * + * @return the user defined functions link. + */ + public String getUserDefinedFunctionsLink() { + return StringUtils.removeEnd(this.selfLink(), "/") + + "/" + super.getString(Constants.Properties.USER_DEFINED_FUNCTIONS_LINK); + } + + /** + * Gets the self-link for conflicts in a collection. + * + * @return the conflicts link. + */ + public String getConflictsLink() { + return StringUtils.removeEnd(this.selfLink(), "/") + + "/" + super.getString(Constants.Properties.CONFLICTS_LINK); + } + + void populatePropertyBag() { + if (this.indexingPolicy == null) { + this.getIndexingPolicy(); + } + if (this.uniqueKeyPolicy == null) { + this.getUniqueKeyPolicy(); + } + + if (this.partitionKeyDefinition != null) { + populatePropertyBagJsonSerializable(this.partitionKeyDefinition); + setProperty(this, Constants.Properties.PARTITION_KEY, this.partitionKeyDefinition); + } + populatePropertyBagJsonSerializable(this.indexingPolicy); + populatePropertyBagJsonSerializable(this.uniqueKeyPolicy); + + setProperty(this, Constants.Properties.INDEXING_POLICY, this.indexingPolicy); + setProperty(this, Constants.Properties.UNIQUE_KEY_POLICY, this.uniqueKeyPolicy); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !DocumentCollection.class.isAssignableFrom(obj.getClass())) { + return false; + } + + DocumentCollection typedObj = (DocumentCollection) obj; + return typedObj.resourceId().equals(this.resourceId()); + } + + @Override + public int hashCode() { + return this.resourceId().hashCode(); + } + + @Override + public String toJson() { + this.populatePropertyBag(); + return super.toJson(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentServiceRequestContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentServiceRequestContext.java new file mode 100644 index 0000000000000..9cb502aa9deae --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/DocumentServiceRequestContext.java @@ -0,0 +1,120 @@ +/* + * + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.directconnectivity.StoreResult; +import com.azure.data.cosmos.internal.directconnectivity.TimeoutHelper; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; + +import java.net.URL; +import java.util.List; + +public class DocumentServiceRequestContext implements Cloneable{ + public volatile boolean forceAddressRefresh; + public volatile boolean forceRefreshAddressCache; + public volatile RequestChargeTracker requestChargeTracker; + public volatile TimeoutHelper timeoutHelper; + public volatile String resolvedCollectionRid; + public volatile ISessionToken sessionToken; + public volatile long quorumSelectedLSN; + public volatile long globalCommittedSelectedLSN; + public volatile StoreResponse globalStrongWriteResponse; + public volatile ConsistencyLevel originalRequestConsistencyLevel; + public volatile PartitionKeyRange resolvedPartitionKeyRange; + public volatile Integer regionIndex; + public volatile Boolean usePreferredLocations; + public volatile Integer locationIndexToRoute; + public volatile URL locationEndpointToRoute; + public volatile boolean performedBackgroundAddressRefresh; + public volatile boolean performLocalRefreshOnGoneException; + public volatile List storeResponses; + public volatile StoreResult quorumSelectedStoreResponse; + public volatile PartitionKeyInternal effectivePartitionKey; + public volatile CosmosResponseDiagnostics cosmosResponseDiagnostics; + + /** + * Sets routing directive for GlobalEndpointManager to resolve the request + * to endpoint based on location index. + * + * @param locationIndex Index of the location to which the request should be routed. + * @param usePreferredLocations Use preferred locations to route request. + */ + public void RouteToLocation(int locationIndex, boolean usePreferredLocations) { + this.locationIndexToRoute = locationIndex; + this.usePreferredLocations = usePreferredLocations; + this.locationEndpointToRoute = null; + } + + /** + * Sets location-based routing directive for GlobalEndpointManager to resolve + * the request to given locationEndpoint. + * + * @param locationEndpoint Location endpoint to which the request should be routed. + */ + public void RouteToLocation(URL locationEndpoint) { + this.locationEndpointToRoute = locationEndpoint; + this.locationIndexToRoute = null; + this.usePreferredLocations = null; + } + + /** + * Clears location-based routing directive + */ + public void ClearRouteToLocation() { + this.locationIndexToRoute = null; + this.locationEndpointToRoute = null; + this.usePreferredLocations = null; + } + + @Override + public DocumentServiceRequestContext clone() { + DocumentServiceRequestContext context = new DocumentServiceRequestContext(); + context.forceAddressRefresh = this.forceAddressRefresh; + context.forceRefreshAddressCache = this.forceRefreshAddressCache; + context.requestChargeTracker = this.requestChargeTracker; + context.timeoutHelper = this.timeoutHelper; + context.resolvedCollectionRid = this.resolvedCollectionRid; + context.sessionToken = this.sessionToken; + context.quorumSelectedLSN = this.quorumSelectedLSN; + context.globalCommittedSelectedLSN = this.globalCommittedSelectedLSN; + context.globalStrongWriteResponse = this.globalStrongWriteResponse; + context.originalRequestConsistencyLevel = this.originalRequestConsistencyLevel; + context.resolvedPartitionKeyRange = this.resolvedPartitionKeyRange; + context.regionIndex = this.regionIndex; + context.usePreferredLocations = this.usePreferredLocations; + context.locationIndexToRoute = this.locationIndexToRoute; + context.locationEndpointToRoute = this.locationEndpointToRoute; + context.performLocalRefreshOnGoneException = this.performLocalRefreshOnGoneException; + context.effectivePartitionKey = this.effectivePartitionKey; + context.performedBackgroundAddressRefresh = this.performedBackgroundAddressRefresh; + context.cosmosResponseDiagnostics = this.cosmosResponseDiagnostics; + + return context; + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/EnumerationDirection.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/EnumerationDirection.java new file mode 100644 index 0000000000000..4515312aadb21 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/EnumerationDirection.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +public enum EnumerationDirection { + /** + * Use forward direction + */ + Forward, + + /** + * Use reverse direction + */ + Reverse +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Exceptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Exceptions.java new file mode 100644 index 0000000000000..c45993030547e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Exceptions.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class Exceptions { + + public static boolean isStatusCode(CosmosClientException e, int status) { + return status == e.statusCode(); + } + + public static boolean isSubStatusCode(CosmosClientException e, int subStatus) { + return subStatus == e.subStatusCode(); + } + + public static boolean isPartitionSplit(CosmosClientException e) { + return isStatusCode(e, HttpConstants.StatusCodes.GONE) + && isSubStatusCode(e, HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE); + } + + public static boolean isNameCacheStale(CosmosClientException e) { + return isStatusCode(e, HttpConstants.StatusCodes.GONE) + && isSubStatusCode(e, HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/FanoutOperationState.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/FanoutOperationState.java new file mode 100644 index 0000000000000..862ed362c944c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/FanoutOperationState.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +public enum FanoutOperationState { + /** + * Fanout operation started + */ + Started, + + /** + * Fanout operation completed + */ + Completed +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/GlobalEndpointManager.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/GlobalEndpointManager.java new file mode 100644 index 0000000000000..90d5957302a0c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/GlobalEndpointManager.java @@ -0,0 +1,260 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.routing.LocationCache; +import com.azure.data.cosmos.internal.routing.LocationHelper; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.net.URISyntaxException; +import java.net.URL; +import java.time.Duration; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +/** + * Endpoint region cache manager implementation. Supports cross region address routing based on + * availability and preference list. + */ +public class GlobalEndpointManager implements AutoCloseable { + private static final Logger logger = LoggerFactory.getLogger(GlobalEndpointManager.class); + + private final int backgroundRefreshLocationTimeIntervalInMS; + private final LocationCache locationCache; + private final URL defaultEndpoint; + private final ConnectionPolicy connectionPolicy; + private final DatabaseAccountManagerInternal owner; + private final AtomicBoolean isRefreshing; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + private final Scheduler scheduler = Schedulers.fromExecutor(executor); + private volatile boolean isClosed; + + public GlobalEndpointManager(DatabaseAccountManagerInternal owner, ConnectionPolicy connectionPolicy, Configs configs) { + this.backgroundRefreshLocationTimeIntervalInMS = configs.getUnavailableLocationsExpirationTimeInSeconds() * 1000; + try { + this.locationCache = new LocationCache( + new ArrayList<>(connectionPolicy.preferredLocations() != null ? + connectionPolicy.preferredLocations(): + Collections.emptyList() + ), + owner.getServiceEndpoint().toURL(), + connectionPolicy.enableEndpointDiscovery(), + BridgeInternal.getUseMultipleWriteLocations(connectionPolicy), + configs); + + this.owner = owner; + this.defaultEndpoint = owner.getServiceEndpoint().toURL(); + this.connectionPolicy = connectionPolicy; + + this.isRefreshing = new AtomicBoolean(false); + this.isClosed = false; + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + public void init() { + // TODO: add support for openAsync + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/332589 + startRefreshLocationTimerAsync(true).block(); + } + + public UnmodifiableList getReadEndpoints() { + // readonly + return this.locationCache.getReadEndpoints(); + } + + public UnmodifiableList getWriteEndpoints() { + //readonly + return this.locationCache.getWriteEndpoints(); + } + + public static Mono getDatabaseAccountFromAnyLocationsAsync( + URL defaultEndpoint, List locations, Function> getDatabaseAccountFn) { + + return getDatabaseAccountFn.apply(defaultEndpoint).onErrorResume( + e -> { + logger.error("Fail to reach global gateway [{}], [{}]", defaultEndpoint, e.getMessage()); + if (locations.isEmpty()) { + return Mono.error(e); + } + + Flux> obs = Flux.range(0, locations.size()) + .map(index -> getDatabaseAccountFn.apply(LocationHelper.getLocationEndpoint(defaultEndpoint, locations.get(index))).flux()); + + // iterate and get the database account from the first non failure, otherwise get the last error. + Mono res = Flux.concatDelayError(obs).take(1).single(); + return res.doOnError( + innerE -> logger.error("Fail to reach location any of locations {} {}", String.join(",", locations), innerE.getMessage())); + }); + } + + public URL resolveServiceEndpoint(RxDocumentServiceRequest request) { + return this.locationCache.resolveServiceEndpoint(request); + } + + public void markEndpointUnavailableForRead(URL endpoint) { + logger.debug("Marking endpoint {} unavailable for read",endpoint); + this.locationCache.markEndpointUnavailableForRead(endpoint);; + } + + public void markEndpointUnavailableForWrite(URL endpoint) { + logger.debug("Marking endpoint {} unavailable for Write",endpoint); + this.locationCache.markEndpointUnavailableForWrite(endpoint); + } + + public boolean CanUseMultipleWriteLocations(RxDocumentServiceRequest request) { + return this.locationCache.canUseMultipleWriteLocations(request); + } + + public void close() { + this.isClosed = true; + this.executor.shutdown(); + logger.debug("GlobalEndpointManager closed."); + } + + public Mono refreshLocationAsync(DatabaseAccount databaseAccount) { + return Mono.defer(() -> { + logger.debug("refreshLocationAsync() invoked"); + if (!isRefreshing.compareAndSet(false, true)) { + logger.debug("in the middle of another refresh. Not invoking a new refresh."); + return Mono.empty(); + } + + logger.debug("will refresh"); + return this.refreshLocationPrivateAsync(databaseAccount).doOnError(e -> this.isRefreshing.set(false)); + }); + } + + private Mono refreshLocationPrivateAsync(DatabaseAccount databaseAccount) { + return Mono.defer(() -> { + logger.debug("refreshLocationPrivateAsync() refreshing locations"); + + if (databaseAccount != null) { + this.locationCache.onDatabaseAccountRead(databaseAccount); + } + + Utils.ValueHolder canRefreshInBackground = new Utils.ValueHolder<>(); + if (this.locationCache.shouldRefreshEndpoints(canRefreshInBackground)) { + logger.debug("shouldRefreshEndpoints: true"); + + if (databaseAccount == null && !canRefreshInBackground.v) { + logger.debug("shouldRefreshEndpoints: can't be done in background"); + + Mono databaseAccountObs = getDatabaseAccountFromAnyLocationsAsync( + this.defaultEndpoint, + new ArrayList<>(this.connectionPolicy.preferredLocations()), + this::getDatabaseAccountAsync); + + return databaseAccountObs.map(dbAccount -> { + this.locationCache.onDatabaseAccountRead(dbAccount); + return dbAccount; + }).flatMap(dbAccount -> { + // trigger a startRefreshLocationTimerAsync don't wait on it. + this.startRefreshLocationTimerAsync(); + return Mono.empty(); + }); + } + + // trigger a startRefreshLocationTimerAsync don't wait on it. + this.startRefreshLocationTimerAsync(); + + return Mono.empty(); + } else { + logger.debug("shouldRefreshEndpoints: false, nothing to do."); + this.isRefreshing.set(false); + return Mono.empty(); + } + }); + } + + private void startRefreshLocationTimerAsync() { + startRefreshLocationTimerAsync(false).subscribe(); + } + + private Mono startRefreshLocationTimerAsync(boolean initialization) { + + if (this.isClosed) { + logger.debug("startRefreshLocationTimerAsync: nothing to do, it is closed"); + // if client is already closed, nothing to be done, just return. + return Mono.empty(); + } + + logger.debug("registering a refresh in [{}] ms", this.backgroundRefreshLocationTimeIntervalInMS); + LocalDateTime now = LocalDateTime.now(); + + int delayInMillis = initialization ? 0: this.backgroundRefreshLocationTimeIntervalInMS; + + return Mono.delay(Duration.ofMillis(delayInMillis)) + .flatMap( + t -> { + if (this.isClosed) { + logger.warn("client already closed"); + // if client is already closed, nothing to be done, just return. + return Mono.empty(); + } + + logger.debug("startRefreshLocationTimerAsync() - Invoking refresh, I was registered on [{}]", now); + Mono databaseAccountObs = GlobalEndpointManager.getDatabaseAccountFromAnyLocationsAsync(this.defaultEndpoint, new ArrayList<>(this.connectionPolicy.preferredLocations()), + this::getDatabaseAccountAsync); + + return databaseAccountObs.flatMap(dbAccount -> { + logger.debug("db account retrieved"); + return this.refreshLocationPrivateAsync(dbAccount); + }); + }).onErrorResume(ex -> { + logger.error("startRefreshLocationTimerAsync() - Unable to refresh database account from any location. Exception: {}", ex.toString(), ex); + + this.startRefreshLocationTimerAsync(); + return Mono.empty(); + }).subscribeOn(scheduler); + } + + private Mono getDatabaseAccountAsync(URL serviceEndpoint) { + try { + return this.owner.getDatabaseAccountFromEndpoint(serviceEndpoint.toURI()) + .doOnNext(i -> logger.debug("account retrieved: {}", i)).single(); + } catch (URISyntaxException e) { + return Mono.error(e); + } + } + + public boolean isClosed() { + return this.isClosed; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/HttpConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/HttpConstants.java new file mode 100644 index 0000000000000..d1a31ecd600af --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/HttpConstants.java @@ -0,0 +1,326 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Used internally. HTTP constants in the Azure Cosmos DB database service Java + * SDK. + */ +public class HttpConstants { + public static class HttpMethods { + public static final String GET = "GET"; + public static final String POST = "POST"; + public static final String PUT = "PUT"; + public static final String DELETE = "DELETE"; + public static final String HEAD = "HEAD"; + public static final String OPTIONS = "OPTIONS"; + public static final String PATCH = "PATCH"; + } + + public static class QueryStrings { + public static final String URL = "$resolveFor"; + public static final String FILTER = "$filter"; + public static final String PARTITION_KEY_RANGE_IDS = "$partitionKeyRangeIds"; + } + + public static class HttpHeaders { + public static final String AUTHORIZATION = "authorization"; + public static final String E_TAG = "etag"; + public static final String METHOD_OVERRIDE = "X-HTTP-Method"; + public static final String SLUG = "Slug"; + public static final String CONTENT_TYPE = "Content-Type"; + public static final String LAST_MODIFIED = "Last-Modified"; + public static final String CONTENT_ENCODING = "Content-Encoding"; + public static final String CHARACTER_SET = "CharacterSet"; + public static final String USER_AGENT = "User-Agent"; + public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + public static final String IF_MATCH = "If-Match"; + public static final String IF_NONE_MATCH = "If-NONE-Match"; + public static final String CONTENT_LENGTH = "Content-Length"; + public static final String ACCEPT_ENCODING = "Accept-Encoding"; + public static final String KEEP_ALIVE = "Keep-Alive"; + public static final String CONNECTION = "Connection"; + public static final String CACHE_CONTROL = "Cache-Control"; + public static final String TRANSFER_ENCODING = "Transfer-Encoding"; + public static final String CONTENT_LANGUAGE = "Content-Language"; + public static final String CONTENT_LOCATION = "Content-Location"; + public static final String CONTENT_MD5 = "Content-Md5"; + public static final String CONTENT_RANGE = "Content-RANGE"; + public static final String ACCEPT = "Accept"; + public static final String ACCEPT_CHARSET = "Accept-Charset"; + public static final String ACCEPT_LANGUAGE = "Accept-Language"; + public static final String IF_RANGE = "If-RANGE"; + public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; + public static final String MAX_FORWARDS = "Max-Forwards"; + public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; + public static final String ACCEPT_RANGES = "Accept-Ranges"; + public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; + public static final String RETRY_AFTER = "Retry-After"; + public static final String SET_COOKIE = "Set-Cookie"; + public static final String WWW_AUTHENTICATE = "Www-Authenticate"; + public static final String ORIGIN = "Origin"; + public static final String HOST = "Host"; + public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin"; + public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers"; + public static final String KEY_VALUE_ENCODING_FORMAT = "application/x-www-form-urlencoded"; + public static final String WRAP_ASSERTION_FORMAT = "wrap_assertion_format"; + public static final String WRAP_ASSERTION = "wrap_assertion"; + public static final String WRAP_SCOPE = "wrap_scope"; + public static final String SIMPLE_TOKEN = "SWT"; + public static final String HTTP_DATE = "date"; + public static final String PREFER = "Prefer"; + public static final String LOCATION = "Location"; + public static final String REFERER = "referer"; + + // Query + public static final String QUERY = "x-ms-documentdb-query"; + public static final String IS_QUERY = "x-ms-documentdb-isquery"; + public static final String ENABLE_CROSS_PARTITION_QUERY = "x-ms-documentdb-query-enablecrosspartition"; + public static final String PARALLELIZE_CROSS_PARTITION_QUERY = "x-ms-documentdb-query-parallelizecrosspartitionquery"; + + // Our custom DocDB headers + public static final String CONTINUATION = "x-ms-continuation"; + public static final String PAGE_SIZE = "x-ms-max-item-count"; + public static final String RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB = "x-ms-documentdb-responsecontinuationtokenlimitinkb"; + + // Request sender generated. Simply echoed by backend. + public static final String ACTIVITY_ID = "x-ms-activity-id"; + public static final String PRE_TRIGGER_INCLUDE = "x-ms-documentdb-pre-trigger-include"; + public static final String PRE_TRIGGER_EXCLUDE = "x-ms-documentdb-pre-trigger-exclude"; + public static final String POST_TRIGGER_INCLUDE = "x-ms-documentdb-post-trigger-include"; + public static final String POST_TRIGGER_EXCLUDE = "x-ms-documentdb-post-trigger-exclude"; + public static final String INDEXING_DIRECTIVE = "x-ms-indexing-directive"; + public static final String SESSION_TOKEN = "x-ms-session-token"; + public static final String CONSISTENCY_LEVEL = "x-ms-consistency-level"; + public static final String X_DATE = "x-ms-date"; + public static final String COLLECTION_PARTITION_INFO = "x-ms-collection-partition-info"; + public static final String COLLECTION_SERVICE_INFO = "x-ms-collection-service-info"; + public static final String RETRY_AFTER_IN_MILLISECONDS = "x-ms-retry-after-ms"; + public static final String IS_FEED_UNFILTERED = "x-ms-is-feed-unfiltered"; + public static final String RESOURCE_TOKEN_EXPIRY = "x-ms-documentdb-expiry-seconds"; + public static final String ENABLE_SCAN_IN_QUERY = "x-ms-documentdb-query-enable-scan"; + public static final String EMIT_VERBOSE_TRACES_IN_QUERY = "x-ms-documentdb-query-emit-traces"; + + // target lsn for head requests + public static final String TARGET_LSN = "x-ms-target-lsn"; + public static final String TARGET_GLOBAL_COMMITTED_LSN = "x-ms-target-global-committed-lsn"; + + // Request validation + public static final String REQUEST_VALIDATION_FAILURE = "x-ms-request-validation-failure"; + + public static final String WRITE_REQUEST_TRIGGER_ADDRESS_REFRESH = "x-ms-write-request-trigger-refresh"; + + // Quota Info + public static final String MAX_RESOURCE_QUOTA = "x-ms-resource-quota"; + public static final String CURRENT_RESOURCE_QUOTA_USAGE = "x-ms-resource-usage"; + public static final String MAX_MEDIA_STORAGE_USAGE_IN_MB = "x-ms-max-media-storage-usage-mb"; + + // Usage Info + public static final String REQUEST_CHARGE = "x-ms-request-charge"; + public static final String CURRENT_MEDIA_STORAGE_USAGE_IN_MB = "x-ms-media-storage-usage-mb"; + public static final String DATABASE_ACCOUNT_CONSUMED_DOCUMENT_STORAGE_IN_MB = "x-ms-databaseaccount-consumed-mb"; + public static final String DATABASE_ACCOUNT_RESERVED_DOCUMENT_STORAGE_IN_MB = "x-ms-databaseaccount-reserved-mb"; + public static final String DATABASE_ACCOUNT_PROVISIONED_DOCUMENT_STORAGE_IN_MB = "x-ms-databaseaccount-provisioned-mb"; + + // Address related headers. + public static final String FORCE_REFRESH = "x-ms-force-refresh"; + public static final String ITEM_COUNT = "x-ms-item-count"; + public static final String NEW_RESOURCE_ID = "x-ms-new-resource-id"; + public static final String USE_MASTER_COLLECTION_RESOLVER = "x-ms-use-master-collection-resolver"; + + // Admin Headers + public static final String FULL_UPGRADE = "x-ms-force-full-upgrade"; + public static final String ONLY_UPGRADE_SYSTEM_APPLICATIONS = "x-ms-only-upgrade-system-applications"; + public static final String ONLY_UPGRADE_NON_SYSTEM_APPLICATIONS = "x-ms-only-upgrade-non-system-applications"; + public static final String UPGRADE_FABRIC_RING_CODE_AND_CONFIG = "x-ms-upgrade-fabric-code-config"; + public static final String IGNORE_IN_PROGRESS_UPGRADE = "x-ms-ignore-inprogress-upgrade"; + public static final String UPGRADE_VERIFICATION_KIND = "x-ms-upgrade-verification-kind"; + public static final String IS_CANARY = "x-ms-iscanary"; + public static final String FORCE_DELETE = "x-ms-force-delete"; + + // Version headers and values + public static final String VERSION = "x-ms-version"; + public static final String SCHEMA_VERSION = "x-ms-schemaversion"; + public static final String SERVER_VERSION = "x-ms-serviceversion"; + public static final String GATEWAY_VERSION = "x-ms-gatewayversion"; + + // RDFE Resource Provider headers + public static final String OCP_RESOURCE_PROVIDER_REGISTERED_URI = "ocp-resourceprovider-registered-uri"; + + // For Document service management operations only. This is in + // essence a 'handle' to (long running) operations. + public static final String REQUEST_ID = "x-ms-request-id"; + + // Object returning this determines what constitutes state and what + // last state change means. For replica, it is the last role change. + public static final String LAST_STATE_CHANGE_UTC = "x-ms-last-state-change-utc"; + + // CSM specific headers + // Client-request-id: Optional caller-specified request ID, in the form + // of a GUID + public static final String CLIENT_REQUEST_ID = "x-ms-client-request-id"; + + // Offer header + public static final String OFFER_TYPE = "x-ms-offer-type"; + public static final String OFFER_THROUGHPUT = "x-ms-offer-throughput"; + public static final String OFFER_IS_RU_PER_MINUTE_THROUGHPUT_ENABLED = "x-ms-offer-is-ru-per-minute-throughput-enabled"; + + // Upsert header + public static final String IS_UPSERT = "x-ms-documentdb-is-upsert"; + + // Index progress headers + public static final String INDEX_TRANSFORMATION_PROGRESS = "x-ms-documentdb-collection-index-transformation-progress"; + public static final String LAZY_INDEXING_PROGRESS = "x-ms-documentdb-collection-lazy-indexing-progress"; + + // Owner name + public static final String OWNER_FULL_NAME = "x-ms-alt-content-path"; + + // Owner ID used for name based request in session token. + public static final String OWNER_ID = "x-ms-content-path"; + + // Partition headers + public static final String PARTITION_KEY = "x-ms-documentdb-partitionkey"; + public static final String PARTITION_KEY_RANGE_ID = "x-ms-documentdb-partitionkeyrangeid"; + + // Error response sub status code + public static final String SUB_STATUS = "x-ms-substatus"; + + public static final String LSN = "lsn"; + + // CUSTOM DocDB JavaScript logging headers + public static final String SCRIPT_ENABLE_LOGGING = "x-ms-documentdb-script-enable-logging"; + public static final String SCRIPT_LOG_RESULTS = "x-ms-documentdb-script-log-results"; + + // Collection quota + public static final String POPULATE_QUOTA_INFO = "x-ms-documentdb-populatequotainfo"; + + // ChangeFeed + public static final String A_IM = "A-IM"; + public static final String ALLOW_TENTATIVE_WRITES = "x-ms-cosmos-allow-tentative-writes"; + + // These properties were added to support RNTBD and they've been added here to + // reduce merge conflicts + + public static final String CAN_CHARGE = "x-ms-cancharge"; + public static final String CAN_OFFER_REPLACE_COMPLETE = "x-ms-can-offer-replace-complete"; + public static final String CAN_THROTTLE = "x-ms-canthrottle"; + public static final String CLIENT_RETRY_ATTEMPT_COUNT = "x-ms-client-retry-attempt-count"; + public static final String COLLECTION_INDEX_TRANSFORMATION_PROGRESS = "x-ms-documentdb-collection-index-transformation-progress"; + public static final String COLLECTION_LAZY_INDEXING_PROGRESS = "x-ms-documentdb-collection-lazy-indexing-progress"; + public static final String COLLECTION_REMOTE_STORAGE_SECURITY_IDENTIFIER = "x-ms-collection-security-identifier"; + public static final String CONTENT_SERIALIZATION_FORMAT = "x-ms-documentdb-content-serialization-format"; + public static final String DISABLE_RNTBD_CHANNEL = "x-ms-disable-rntbd-channel"; + public static final String DISABLE_RU_PER_MINUTE_USAGE = "x-ms-documentdb-disable-ru-per-minute-usage"; + public static final String ENABLE_LOGGING = "x-ms-documentdb-script-enable-logging"; + public static final String ENABLE_LOW_PRECISION_ORDER_BY = "x-ms-documentdb-query-enable-low-precision-order-by"; + public static final String END_EPK = "x-ms-end-epk"; + public static final String END_ID = "x-ms-end-id"; + public static final String ENUMERATION_DIRECTION = "x-ms-enumeration-direction"; + public static final String FILTER_BY_SCHEMA_RESOURCE_ID = "x-ms-documentdb-filterby-schema-rid"; + public static final String FORCE_QUERY_SCAN = "x-ms-documentdb-force-query-scan"; + public static final String GATEWAY_SIGNATURE = "x-ms-gateway-signature"; + public static final String IS_AUTO_SCALE_REQUEST = "x-ms-is-auto-scale"; + public static final String IS_READ_ONLY_SCRIPT = "x-ms-is-readonly-script"; + public static final String LOG_RESULTS = "x-ms-documentdb-script-log-results"; + public static final String MIGRATE_COLLECTION_DIRECTIVE = "x-ms-migratecollection-directive"; + public static final String POPULATE_COLLECTION_THROUGHPUT_INFO = "x-ms-documentdb-populatecollectionthroughputinfo"; + public static final String POPULATE_PARTITION_STATISTICS = "x-ms-documentdb-populatepartitionstatistics"; + public static final String POPULATE_QUERY_METRICS = "x-ms-documentdb-populatequerymetrics"; + public static final String PROFILE_REQUEST = "x-ms-profile-request"; + public static final String READ_FEED_KEY_TYPE = "x-ms-read-key-type"; + public static final String REMAINING_TIME_IN_MS_ON_CLIENT_REQUEST = "x-ms-remaining-time-in-ms-on-client"; + public static final String RESTORE_METADATA_FILTER = "x-ms-restore-metadata-filter"; + public static final String SHARED_OFFER_THROUGHPUT = "x-ms-cosmos-shared-offer-throughput"; + public static final String START_EPK = "x-ms-start-epk"; + public static final String START_ID = "x-ms-start-id"; + public static final String SUPPORT_SPATIAL_LEGACY_COORDINATES = "x-ms-documentdb-supportspatiallegacycoordinates"; + public static final String TRANSPORT_REQUEST_ID = "x-ms-transport-request-id"; + public static final String USE_POLYGONS_SMALLER_THAN_AHEMISPHERE = "x-ms-documentdb-usepolygonssmallerthanahemisphere"; + public static final String API_TYPE = "x-ms-cosmos-apitype"; + public static final String QUERY_METRICS = "x-ms-documentdb-query-metrics"; + + } + + public static class A_IMHeaderValues { + public static final String INCREMENTAL_FEED = "Incremental Feed"; + } + + public static class Versions { + public static final String CURRENT_VERSION = "2018-12-31"; + + // TODO: FIXME we can use maven plugin for generating a version file + // @see + // https://stackoverflow.com/questions/2469922/generate-a-version-java-file-in-maven + public static final String SDK_VERSION = "3.0.0"; + public static final String SDK_NAME = "cosmosdb-java-sdk"; + } + + public static class StatusCodes { + public static final int NOT_MODIFIED = 304; + // Client error + public static final int MINIMUM_STATUSCODE_AS_ERROR_GATEWAY = 400; + public static final int BADREQUEST = 400; + public static final int UNAUTHORIZED = 401; + public static final int FORBIDDEN = 403; + public static final int NOTFOUND = 404; + public static final int METHOD_NOT_ALLOWED = 405; + public static final int REQUEST_TIMEOUT = 408; + public static final int CONFLICT = 409; + public static final int GONE = 410; + public static final int PRECONDITION_FAILED = 412; + public static final int REQUEST_ENTITY_TOO_LARGE = 413; + public static final int LOCKED = 423; + public static final int TOO_MANY_REQUESTS = 429; + public static final int RETRY_WITH = 449; + + public static final int SERVICE_UNAVAILABLE = 503; + public static final int INTERNAL_SERVER_ERROR = 500; + } + + public static class SubStatusCodes { + // Unknown SubStatus Code + public static final int UNKNOWN = 0; + + // 400: Bad Request substatus + public static final int PARTITION_KEY_MISMATCH = 1001; + public static final int CROSS_PARTITION_QUERY_NOT_SERVABLE = 1004; + + // 410: StatusCodeType_Gone: substatus + public static final int NAME_CACHE_IS_STALE = 1000; + public static final int PARTITION_KEY_RANGE_GONE = 1002; + public static final int COMPLETING_SPLIT = 1007; + public static final int COMPLETING_PARTITION_MIGRATION = 1008; + + // 403: Forbidden substatus + public static final int FORBIDDEN_WRITEFORBIDDEN = 3; + public static final int DATABASE_ACCOUNT_NOTFOUND = 1008; + + // 404: LSN in session token is higher + public static final int READ_SESSION_NOT_AVAILABLE = 1002; + } + + public static class HeaderValues { + public static final String NoCache = "no-cache"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IAuthorizationTokenProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IAuthorizationTokenProvider.java new file mode 100644 index 0000000000000..f7de0a86be903 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IAuthorizationTokenProvider.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import java.util.Map; + +public interface IAuthorizationTokenProvider { + String getUserAuthorizationToken(String resourceAddress, + ResourceType resourceType, + String get, + Map headers, + AuthorizationTokenType primarymasterkey, + Map properties); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ICollectionRoutingMapCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ICollectionRoutingMapCache.java new file mode 100644 index 0000000000000..1ac11e218facb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ICollectionRoutingMapCache.java @@ -0,0 +1,48 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import reactor.core.publisher.Mono; + +import java.util.Map; + +// TODO: add documentation +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + **/ +public interface ICollectionRoutingMapCache { + default Mono tryLookupAsync( + String collectionRid, + CollectionRoutingMap previousValue, + Map properties) { + return tryLookupAsync(collectionRid, previousValue, false, properties); + } + + Mono tryLookupAsync( + String collectionRid, + CollectionRoutingMap previousValue, + boolean forceRefreshCollectionRoutingMap, + Map properties); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IDocumentClientRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IDocumentClientRetryPolicy.java new file mode 100644 index 0000000000000..b1ce820c586d8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IDocumentClientRetryPolicy.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import reactor.core.publisher.Mono; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IDocumentClientRetryPolicy extends IRetryPolicy { + + // TODO: this is just a place holder for now. As .Net has this method. + // I have to spend more time figure out what's the right pattern for this (if method needed) + + ///

    + /// Method that is called before a request is sent to allow the retry policy implementation + /// to modify the state of the request. + /// + /// The request being sent to the service. + /// + /// Currently only read operations will invoke this method. There is no scenario for write + /// operations to modify requests before retrying. + /// + + // TODO: I need to investigate what's the right contract here and/or if/how this is useful + void onBeforeSendRequest(RxDocumentServiceRequest request); + + + class NoRetry implements IDocumentClientRetryPolicy { + + private static NoRetry instance = new NoRetry(); + + private NoRetry() {} + + public static NoRetry getInstance() { + return instance; + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + // no op + } + + @Override + public Mono shouldRetry(Exception e) { + return Mono.just(ShouldRetryResult.error(e)); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicy.java new file mode 100644 index 0000000000000..84e753bf33d03 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicy.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import reactor.core.publisher.Mono; + +import java.time.Duration; + +// TODO update documentation +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IRetryPolicy { + // this capture all the retry logic + // TODO: design decision should this return a single or an observable? + + /// + /// Method that is called to determine from the policy that needs to retry on the exception + /// + /// Exception during the callback method invocation + /// + /// If the retry needs to be attempted or not + Mono shouldRetry(Exception e); + + + class ShouldRetryResult { + /// + /// How long to wait before next retry. 0 indicates retry immediately. + /// + public final Duration backOffTime; + public final Exception exception; + public boolean shouldRetry; + public final Quadruple policyArg; + + private ShouldRetryResult(Duration dur, Exception e, boolean shouldRetry, + Quadruple policyArg) { + this.backOffTime = dur; + this.exception = e; + this.shouldRetry = shouldRetry; + this.policyArg = policyArg; + } + + public static ShouldRetryResult retryAfter(Duration dur) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, null); + } + + public static ShouldRetryResult retryAfter(Duration dur, + Quadruple policyArg) { + Utils.checkNotNullOrThrow(dur, "duration", "cannot be null"); + return new ShouldRetryResult(dur, null, true, policyArg); + } + + public static ShouldRetryResult error(Exception e) { + Utils.checkNotNullOrThrow(e, "exception", "cannot be null"); + return new ShouldRetryResult(null, e, false, null); + } + + public static ShouldRetryResult noRetry() { + return new ShouldRetryResult(null, null, false, null); + } + + public void throwIfDoneTrying(Exception capturedException) throws Exception { + if (this.shouldRetry) { + return; + } + + if (this.exception == null) { + throw capturedException; + } else { + throw this.exception; + } + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicyFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicyFactory.java new file mode 100644 index 0000000000000..a13ba894372de --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRetryPolicyFactory.java @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IRetryPolicyFactory { + IDocumentClientRetryPolicy getRequestPolicy(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRoutingMapProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRoutingMapProvider.java new file mode 100644 index 0000000000000..6e940ba093cd6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/IRoutingMapProvider.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.routing.Range; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +//TODO: update documentation +//TODO: add two overload methods for forceRefresh = false +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + **/ +public interface IRoutingMapProvider { + /// + /// Returns list of effective partition key ranges for a collection. + /// + /// Collection for which to retrieve routing map. + /// This method will return all ranges which overlap this range. + /// Whether forcefully refreshing the routing map is necessary + /// List of effective partition key ranges for a collection or null if collection doesn't exist. + Mono> tryGetOverlappingRangesAsync(String collectionResourceId, Range range, + boolean forceRefresh /* = false */, Map properties); + + Mono tryGetPartitionKeyRangeByIdAsync(String collectionResourceId, String partitionKeyRangeId, + boolean forceRefresh /* = false */, Map properties); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionContainer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionContainer.java new file mode 100644 index 0000000000000..ed47596aff626 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionContainer.java @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.ISessionToken; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; + +import java.util.Map; + +public interface ISessionContainer { + /** + * Returns a serialized map of partitionKeyRangeId to session token. If a entity is name based then the method extracts name from + * ResourceAddress and use it to identify collection otherwise it uses ResourceId. Returns empty string if collection is unknown + * @param entity {@link RxDocumentServiceRequest entity} + * @return serialzed map of partitionKeyRangeId to session token or empty string is collection is unknown + */ + String resolveGlobalSessionToken(RxDocumentServiceRequest entity); + + /** + * Returns a session token identified by partitionKeyRangeId(*) from a collection identified either by ResourceAddress + * (in case of name based entity) or either by ResourceId. + * + * If partitionKeyRangeId is not in the collection's partitionKeyRangeId token map then method + * iterates through request.RequestContext.ResolvedPartitionKeyRange.Parents starting from tail and + * returns a corresponding token if there is a match. + * @param entity {@link RxDocumentServiceRequest} + * @param partitionKeyRangeId partitionKeyRangeId + * @return Returns a session token identified by partitionKeyRangeId(*) from a collection identified either by ResourceAddress + * (in case of name based entity) or either by ResourceId. + */ + ISessionToken resolvePartitionLocalSessionToken(RxDocumentServiceRequest entity, String partitionKeyRangeId); + + /** + * Atomically: removes partitionKeyRangeId token map associated with resourceId, + * maps resourceId to collectionFullName and removes its map as well + * @param resourceId resourceId + */ + void clearTokenByResourceId(String resourceId); + + /** + * Atomically: removes partitionKeyRangeId token map associated with collectionFullName, maps collectionFullName to resourceId and + * removes its map as well. + * @param collectionFullName collectionFullName + */ + void clearTokenByCollectionFullName(String collectionFullName); + + /** + * Infers collectionFullName using responseHeaders[HttpConstants.HttpHeaders.OwnerFullName] or request.ResourceAddress, + * infers resourceId using responseHeaders[HttpConstants.HttpHeaders.OwnerId] or request.ResourceId, + * and adds responseHeaders[HttpConstants.HttpHeaders.SessionToken] session token to the (collectionFullName, resourceId)'s + * partitionKeyRangeId token map. + * + * NB: Silently does nothing for master queries, or when it's impossible to infer collectionRid and collectionFullName + * from the request, or then SessionToken is missing in responseHeader. + * + * @param request {@link RxDocumentServiceRequest} + * @param responseHeaders responseHeaders + */ + void setSessionToken(RxDocumentServiceRequest request, Map responseHeaders); + + /** + * Adds responseHeaders[HttpConstants.HttpHeaders.SessionToken] session token to the (collectionFullName, collectionRid)'s partitionKeyRangeId token map. + * @param collectionRid collectionRid + * @param collectionFullName collectionFullName + * @param responseHeaders responseHeaders + */ + void setSessionToken(String collectionRid, String collectionFullName, Map responseHeaders); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionToken.java new file mode 100644 index 0000000000000..49c6b383e98da --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ISessionToken.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; + +/** + * Models session token. + * + * We make assumption that instances of this interface are immutable (read only after they are constructed), so if you want to change + * this behaviour please review all of its uses and make sure that mutability doesn't break anything. + */ +public interface ISessionToken { + + String PARTITION_KEY_RANGE_SESSION_SEPARATOR = ":"; + + /** + * Returns true if this instance of session token is valid with respect to other session token. + * This is used to decide if the client can accept server's response (based on comparison between client's + * and server's session token) + * + * @param other SESSION token to validate + * @return true if this instance of session token is valid with respect to other session token; + * false otherwise + */ + boolean isValid(ISessionToken other) throws CosmosClientException; + + /** + * Returns a new instance of session token obtained by merging this session token with + * the given session token other. + * + * Merge is commutative operation, so a.Merge(b).Equals(b.Merge(a)) + * + * @param other Other session token to merge + * @return Instance of merged session token + */ + ISessionToken merge(ISessionToken other) throws CosmosClientException; + + long getLSN(); + + String convertToString(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Integers.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Integers.java new file mode 100644 index 0000000000000..2369c1c815118 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Integers.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +public class Integers { + public static int tryParse(String value, int defaultValue) { + if (Strings.isNullOrEmpty(value)) { + return defaultValue; + } + + try { + return Integer.valueOf(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } + + public static Integer tryParse(String value) { + if (Strings.isNullOrEmpty(value)) { + return null; + } + + try { + return Integer.valueOf(value); + } catch (NumberFormatException e) { + return null; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InternalConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InternalConstants.java new file mode 100644 index 0000000000000..5f56ba4fbed15 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InternalConstants.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +class InternalConstants { + + static class ResourceKeys { + static final String ATTACHMENTS = "Attachments"; + static final String CONFLICTS = "Conflicts"; + static final String DATABASES = "Databases"; + static final String DOCUMENTS = "Documents"; + static final String DOCUMENT_COLLECTIONS = "DocumentCollections"; + static final String OFFERS = "Offers"; + static final String PERMISSIONS = "Permissions"; + static final String PARTITION_KEY_RANGES = "PartitionKeyRanges"; + static final String TRIGGERS = "Triggers"; + static final String STOREDPROCEDURES = "StoredProcedures"; + static final String USERS = "Users"; + static final String USER_DEFINED_FUNCTIONS = "UserDefinedFunctions"; + static final String ADDRESSES = "Addresss"; + } + + static class StreamApi { + static final int STREAM_LENGTH_EOF = -1; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InvalidPartitionExceptionRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InvalidPartitionExceptionRetryPolicy.java new file mode 100644 index 0000000000000..a76203f6e2cea --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/InvalidPartitionExceptionRetryPolicy.java @@ -0,0 +1,88 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class InvalidPartitionExceptionRetryPolicy implements IDocumentClientRetryPolicy { + + private final RxCollectionCache clientCollectionCache; + private final IDocumentClientRetryPolicy nextPolicy; + private final String collectionLink; + private final FeedOptions feedOptions; + + private volatile boolean retried = false; + + public InvalidPartitionExceptionRetryPolicy(RxCollectionCache collectionCache, + IDocumentClientRetryPolicy nextPolicy, + String resourceFullName, + FeedOptions feedOptions) { + + this.clientCollectionCache = collectionCache; + this.nextPolicy = nextPolicy; + + // TODO the resource address should be inferred from exception + this.collectionLink = com.azure.data.cosmos.internal.Utils.getCollectionName(resourceFullName); + this.feedOptions = feedOptions; + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + this.nextPolicy.onBeforeSendRequest(request); + } + + @Override + public Mono shouldRetry(Exception e) { + CosmosClientException clientException = Utils.as(e, CosmosClientException.class); + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.GONE) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE)) { + if (!this.retried) { + // TODO: resource address should be accessible from the exception + //this.clientCollectionCache.Refresh(clientException.ResourceAddress); + // TODO: this is blocking. is that fine? + if(this.feedOptions != null) { + this.clientCollectionCache.refresh(collectionLink,this.feedOptions.properties()); + } else { + this.clientCollectionCache.refresh(collectionLink,null); + } + + this.retried = true; + return Mono.just(ShouldRetryResult.retryAfter(Duration.ZERO)); + } else { + return Mono.just(ShouldRetryResult.error(e)); + } + } + + return this.nextPolicy.shouldRetry(e); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/JavaStreamUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/JavaStreamUtils.java new file mode 100644 index 0000000000000..5e07f0b845ff3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/JavaStreamUtils.java @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import java.util.Collection; +import java.util.stream.Collectors; + +public class JavaStreamUtils { + + private static String safeToString(T t) { + return t != null ? t.toString() : "null"; + } + + public static String toString(Collection collection, String delimiter) { + return collection.stream() + .map( t -> safeToString(t) ) + .collect(Collectors.joining(delimiter)); + } + + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/LifeCycleUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/LifeCycleUtils.java new file mode 100644 index 0000000000000..5209b9a1d64f0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/LifeCycleUtils.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LifeCycleUtils { + private final static Logger logger = LoggerFactory.getLogger(LifeCycleUtils.class); + public static void closeQuietly(AutoCloseable closeable) { + try { + if (closeable != null) { + logger.debug("closing an instance of {}", closeable.getClass().getCanonicalName()); + closeable.close(); + } + } catch (Exception e) { + logger.warn("attempting to close an instance of {} failed", closeable.getClass().getCanonicalName(), e); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Lists.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Lists.java new file mode 100644 index 0000000000000..4287412c33b62 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Lists.java @@ -0,0 +1,33 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import java.util.List; + +public class Lists { + + public static V firstOrDefault(List list, V defaultValue) { + return list.isEmpty() ? defaultValue : list.get(0); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Longs.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Longs.java new file mode 100644 index 0000000000000..757782057e061 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Longs.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +public class Longs { + public static long tryParse(String value, long defaultValue) { + if (Strings.isNullOrEmpty(value)) { + return defaultValue; + } + + try { + return Long.valueOf(value); + } catch (NumberFormatException e) { + return defaultValue; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MigrateCollectionDirective.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MigrateCollectionDirective.java new file mode 100644 index 0000000000000..ffead99b1a898 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MigrateCollectionDirective.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +public enum MigrateCollectionDirective { + /** + * Move to SSD + */ + Thaw, + + /** + * Move to HDD + */ + Freeze +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MutableVolatile.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MutableVolatile.java new file mode 100644 index 0000000000000..921476855f13d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/MutableVolatile.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +public class MutableVolatile { + + public MutableVolatile(T initValue){ + v = initValue; + } + + public MutableVolatile() {} + public volatile T v; +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ObservableHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ObservableHelper.java new file mode 100644 index 0000000000000..1a5af062b3042 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ObservableHelper.java @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + **/ +public class ObservableHelper { + + static public Mono inlineIfPossible(Callable> function, IRetryPolicy retryPolicy) { + + if (retryPolicy == null) { + // shortcut + try { + return function.call(); + } catch (Exception e) { + return Mono.error(e); + } + } else { + return BackoffRetryUtility.executeRetry(function, retryPolicy); + } + } + + static public Flux inlineIfPossibleAsObs(Callable> function, IRetryPolicy retryPolicy) { + + if (retryPolicy == null) { + // shortcut + return Flux.defer(() -> { + try { + return function.call(); + } catch (Exception e) { + return Flux.error(e); + } + }); + + } else { + return BackoffRetryUtility.executeRetry(() -> function.call().single(), retryPolicy).flux(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Offer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Offer.java new file mode 100644 index 0000000000000..22c787aeeaa67 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Offer.java @@ -0,0 +1,155 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * Represents an offer in the Azure Cosmos DB database service. + */ +public class Offer extends Resource { + + /** + * Initialize an new instance of the Offer object. + * + * @param offerThroughput the throughput value for this offer. + */ + public Offer(int offerThroughput) { + super(); + this.setOfferVersion(Constants.Properties.OFFER_VERSION_V2); + this.setOfferType(""); + ObjectNode content = Utils.getSimpleObjectMapper().createObjectNode(); + content.put(Constants.Properties.OFFER_THROUGHPUT, offerThroughput); + this.setContent(content); + } + + /** + * Initialize an offer object from json string. + * + * @param jsonString the json string that represents the offer. + */ + public Offer(String jsonString) { + super(jsonString); + } + + /** + * Gets the self-link of a resource to which the resource offer applies. + * + * @return the resource link. + */ + public String getResourceLink() { + return super.getString(Constants.Properties.RESOURCE_LINK); + } + + /** + * Sets the self-link of a resource to which the resource offer applies. + * + * @param resourceLink the resource link. + */ + void setResourceLink(String resourceLink) { + BridgeInternal.setProperty(this, Constants.Properties.RESOURCE_LINK, resourceLink); + } + + /** + * Sets the target resource id of a resource to which this offer applies. + * + * @return the resource id. + */ + public String getOfferResourceId() { + return super.getString(Constants.Properties.OFFER_RESOURCE_ID); + } + + /** + * Sets the target resource id of a resource to which this offer applies. + * + * @param resourceId the resource id. + */ + void setOfferResourceId(String resourceId) { + BridgeInternal.setProperty(this, Constants.Properties.OFFER_RESOURCE_ID, resourceId); + } + + /** + * Gets the OfferType for the resource offer. + * + * @return the offer type. + */ + public String getOfferType() { + return super.getString(Constants.Properties.OFFER_TYPE); + } + + /** + * Sets the OfferType for the resource offer. + * + * @param offerType the offer type. + */ + public void setOfferType(String offerType) { + BridgeInternal.setProperty(this, Constants.Properties.OFFER_TYPE, offerType); + } + + /** + * Gets the version of the current offer. + * + * @return the offer version. + */ + public String getOfferVersion() { + return super.getString(Constants.Properties.OFFER_VERSION); + } + + /** + * Sets the offer version. + * + * @param offerVersion the version of the offer. + */ + public void setOfferVersion(String offerVersion) { + BridgeInternal.setProperty(this, Constants.Properties.OFFER_VERSION, offerVersion); + } + + /** + * Gets the offer throughput for this offer. + * + * @return the offer throughput. + */ + public int getThroughput() { + return this.getContent().get(Constants.Properties.OFFER_THROUGHPUT).asInt(); + } + + /** + * Sets the offer throughput for this offer. + * + * @param throughput the throughput of this offer. + */ + public void setThroughput(int throughput) { + this.getContent().put(Constants.Properties.OFFER_THROUGHPUT, throughput); + } + + private ObjectNode getContent() { + return BridgeInternal.getObject(this, Constants.Properties.OFFER_CONTENT); + } + + private void setContent(ObjectNode offerContent) { + BridgeInternal.setProperty(this, Constants.Properties.OFFER_CONTENT, offerContent); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/OperationType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/OperationType.java new file mode 100644 index 0000000000000..6256a7756ef85 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/OperationType.java @@ -0,0 +1,73 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Operation types in the Azure Cosmos DB database service. + */ +public enum OperationType { + AbortPartitionMigration, + AbortSplit, + AddComputeGatewayRequestCharges, + BatchApply, + BatchReportThroughputUtilization, + CompletePartitionMigration, + CompleteSplit, + Crash, + Create, + Delete, + ExecuteJavaScript, + ForceConfigRefresh, + GetSplitPoint, + Head, + HeadFeed, + MigratePartition, + Pause, + PreCreateValidation, + OfferPreGrowValidation, + OfferUpdateOperation, + PreReplaceValidation, + Query, + Read, + ReadFeed, + Recreate, + Recycle, + Replace, + Resume, + SqlQuery, + Stop, + Throttle, + Update, + Upsert; + + public boolean isWriteOperation() { + return this == Create || + this == Delete || + this == Recreate || + this == ExecuteJavaScript || + this == Replace || + this == Upsert || + this == Update; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyMismatchRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyMismatchRetryPolicy.java new file mode 100644 index 0000000000000..b2dfd9aba5df3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyMismatchRetryPolicy.java @@ -0,0 +1,108 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.caches.RxClientCollectionCache; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * A RetryPolicy implementation that ensures the PartitionKeyDefinitionMap is up-to-date. + * Entries in the PartitionKeyDefinitionMap can become stale if a collection is deleted + * and then recreated with the same name but a different partition key definition, if + * the request is made using name-based links. + * + * TODO: verify with Sergii, other than collection deleted and recreated with the same name + * is there any other scenario which this should be used? + * + */ +public class PartitionKeyMismatchRetryPolicy implements IDocumentClientRetryPolicy { + private RxClientCollectionCache clientCollectionCache; + private IDocumentClientRetryPolicy nextRetryPolicy; + private AtomicInteger retriesAttempted = new AtomicInteger(0); + private String collectionLink; + private RequestOptions options; + private final static int MaxRetries = 1; + + + public PartitionKeyMismatchRetryPolicy( + RxClientCollectionCache clientCollectionCache, + IDocumentClientRetryPolicy nextRetryPolicy, + String resourceFullName, + RequestOptions requestOptions) { + this.clientCollectionCache = clientCollectionCache; + this.nextRetryPolicy = nextRetryPolicy; + + // TODO: this should be retrievable from document client exception. + collectionLink = com.azure.data.cosmos.internal.Utils.getCollectionName(resourceFullName); + this.options = options; + } + + + /// + /// Should the caller retry the operation. + /// + /// Exception that occured when the operation was tried + /// + /// True indicates caller should retry, False otherwise + public Mono shouldRetry(Exception exception) { + CosmosClientException clientException = Utils.as(exception, CosmosClientException.class) ; + + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.BADREQUEST) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.PARTITION_KEY_MISMATCH) + && this.retriesAttempted.get() < MaxRetries) { + //Debug.Assert(clientException.ResourceAddress != null); + + // TODO: + //this.clientCollectionCache.refresh(clientException.ResourceAddress); + if (this.options != null) { + this.clientCollectionCache.refresh(collectionLink, this.options.getProperties()); + } else { + this.clientCollectionCache.refresh(collectionLink, null); + } + + this.retriesAttempted.incrementAndGet(); + + return Mono.just(ShouldRetryResult.retryAfter(Duration.ZERO)); + } + + return this.nextRetryPolicy.shouldRetry(exception); + } + + + /* (non-Javadoc) + * @see com.azure.data.cosmos.internal.internal.query.IDocumentClientRetryPolicy#onBeforeSendRequest(RxDocumentServiceRequest) + */ + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + // TODO Auto-generated method stub + this.nextRetryPolicy.onBeforeSendRequest(request); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRange.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRange.java new file mode 100644 index 0000000000000..4404f44aff93b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRange.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.routing.Range; + +import java.util.List; + +/** + * Represent a partition key range in the Azure Cosmos DB database service. + */ +public class PartitionKeyRange extends Resource { + public static final String MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY = ""; + public static final String MAXIMUM_EXCLUSIVE_EFFECTIVE_PARTITION_KEY = "FF"; + public static final String MASTER_PARTITION_KEY_RANGE_ID = "M"; + + /** + * Initialize a partition key range object. + */ + public PartitionKeyRange() { + super(); + } + + /** + * Initialize a partition key range object from json string. + * + * @param jsonString + * the json string that represents the partition key range + * object. + */ + public PartitionKeyRange(String jsonString) { + super(jsonString); + } + + /** + * Set id of partition key range + * @param id the name of the resource. + * @return the partition key range + */ + public PartitionKeyRange id(String id) { + super.id(id); + return this; + } + + public PartitionKeyRange(String id, String minInclusive, String maxExclusive) { + super(); + this.id(id); + this.setMinInclusive(minInclusive); + this.setMaxExclusive(maxExclusive); + } + + public PartitionKeyRange(String id, String minInclusive, String maxExclusive, List parents) { + super(); + this.id(id); + this.setMinInclusive(minInclusive); + this.setMaxExclusive(maxExclusive); + this.setParents(parents); + } + + public String getMinInclusive() { + return super.getString("minInclusive"); + } + + public void setMinInclusive(String minInclusive) { + BridgeInternal.setProperty(this, "minInclusive", minInclusive); + } + + public String getMaxExclusive() { + return super.getString("maxExclusive"); + } + + public void setMaxExclusive(String maxExclusive) { + BridgeInternal.setProperty(this, "maxExclusive", maxExclusive); + } + + public Range toRange() { + return new Range(this.getMinInclusive(), this.getMaxExclusive(), true, false); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof PartitionKeyRange)) { + return false; + } + + PartitionKeyRange otherRange = (PartitionKeyRange) obj; + + return this.id().compareTo(otherRange.id()) == 0 + && this.getMinInclusive().compareTo(otherRange.getMinInclusive()) == 0 + && this.getMaxExclusive().compareTo(otherRange.getMaxExclusive()) == 0; + } + + @Override + public int hashCode() { + int hash = 0; + hash = (hash * 397) ^ this.id().hashCode(); + hash = (hash * 397) ^ this.getMinInclusive().hashCode(); + hash = (hash * 397) ^ this.getMaxExclusive().hashCode(); + return hash; + } + + public void setParents(List parents) { + BridgeInternal.setProperty(this, Constants.Properties.PARENTS, parents); + } + + /** + * Used internally to indicate the ID of the parent range + * @return a list partition key range ID + */ + public List getParents() { return this.getList(Constants.Properties.PARENTS, String.class); } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRangeGoneRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRangeGoneRetryPolicy.java new file mode 100644 index 0000000000000..a72c6fef177f8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PartitionKeyRangeGoneRetryPolicy.java @@ -0,0 +1,122 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.internal.caches.IPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +// TODO: this need testing +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class PartitionKeyRangeGoneRetryPolicy implements IDocumentClientRetryPolicy { + + private final RxCollectionCache collectionCache; + private final IDocumentClientRetryPolicy nextRetryPolicy; + private final IPartitionKeyRangeCache partitionKeyRangeCache; + private final String collectionLink; + private final FeedOptions feedOptions; + private volatile boolean retried; + + public PartitionKeyRangeGoneRetryPolicy( + RxCollectionCache collectionCache, + IPartitionKeyRangeCache partitionKeyRangeCache, + String collectionLink, + IDocumentClientRetryPolicy nextRetryPolicy, + FeedOptions feedOptions) { + this.collectionCache = collectionCache; + this.partitionKeyRangeCache = partitionKeyRangeCache; + this.collectionLink = collectionLink; + this.nextRetryPolicy = nextRetryPolicy; + this.feedOptions = feedOptions; + } + + /// + /// Should the caller retry the operation. + /// + /// Exception that occured when the operation was tried + /// + /// True indicates caller should retry, False otherwise + public Mono shouldRetry(Exception exception) { + CosmosClientException clientException = Utils.as(exception, CosmosClientException.class); + if (clientException != null && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.GONE) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE)) { + + if (this.retried){ + return Mono.just(ShouldRetryResult.error(clientException)); + } + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + this.collectionLink, + null + // AuthorizationTokenType.PrimaryMasterKey) + ); + if (this.feedOptions != null) { + request.properties = this.feedOptions.properties(); + } + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + + return collectionObs.flatMap(collection -> { + + Mono routingMapObs = this.partitionKeyRangeCache.tryLookupAsync(collection.resourceId(), null, request.properties); + + Mono refreshedRoutingMapObs = routingMapObs.flatMap(routingMap -> { + // Force refresh. + return this.partitionKeyRangeCache.tryLookupAsync( + collection.resourceId(), + routingMap, + request.properties); + }).switchIfEmpty(Mono.defer(Mono::empty)); + + // TODO: Check if this behavior can be replaced by doOnSubscribe + return refreshedRoutingMapObs.flatMap(rm -> { + this.retried = true; + return Mono.just(ShouldRetryResult.retryAfter(Duration.ZERO)); + }).switchIfEmpty(Mono.defer(() -> { + this.retried = true; + return Mono.just(ShouldRetryResult.retryAfter(Duration.ZERO)); + })); + + }); + + } else { + return this.nextRetryPolicy.shouldRetry(exception); + } + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + this.nextRetryPolicy.onBeforeSendRequest(request); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathInfo.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathInfo.java new file mode 100644 index 0000000000000..c03d3bac6d036 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathInfo.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Represents a resource path's information in the Azure Cosmos DB database service. + */ +public final class PathInfo { + public boolean isFeed; + public String resourcePath; + public String resourceIdOrFullName; + public boolean isNameBased; + + public PathInfo(boolean isFeed, String resourcePath, String resourceIdOrFullName, boolean isNameBased) { + this.isFeed = isFeed; + this.resourcePath = resourcePath; + this.resourceIdOrFullName = resourceIdOrFullName; + this.isNameBased = isNameBased; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathParser.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathParser.java new file mode 100644 index 0000000000000..9855d6f2fe8c2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathParser.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import java.util.ArrayList; +import java.util.List; + +/** + * Provide functionality to parse resource paths in the Azure Cosmos DB database service. + */ +public final class PathParser { + + private static final char segmentSeparator = '/'; + + public static List getPathParts(String path) { + ArrayList tokens = new ArrayList(); + int currentIndex = 0; + + while (currentIndex < path.length()) { + if (path.charAt(currentIndex) != segmentSeparator) { + throw new IllegalArgumentException(String.format("INVALID path, failed at index %d.", currentIndex)); + } + + if (++currentIndex == path.length()) + break; + + if (path.charAt(currentIndex) == '\"' || path.charAt(currentIndex) == '\'') { + char quote = path.charAt(currentIndex); + int newIndex = ++currentIndex; + while (true) { + newIndex = path.indexOf(quote, newIndex); + if (newIndex == -1) { + throw new IllegalArgumentException(String.format("INVALID path, failed at index %d.", currentIndex)); + } + + if (path.charAt(newIndex - 1) != '\\') { + break; + } + + ++newIndex; + } + + String token = path.substring(currentIndex, newIndex); + tokens.add(token); + currentIndex = newIndex + 1; + } else { + int newIndex = path.indexOf(segmentSeparator, currentIndex); + String token = null; + if (newIndex == -1) { + token = path.substring(currentIndex); + currentIndex = path.length(); + } else { + token = path.substring(currentIndex, newIndex); + currentIndex = newIndex; + } + + token = token.trim(); + tokens.add(token); + } + } + + return tokens; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Paths.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Paths.java new file mode 100644 index 0000000000000..de499bdc2afea --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Paths.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Used internally. Contains string constants to work with the paths in the Azure Cosmos DB database service. + */ +public class Paths { + static final String ROOT = "/"; + + public static final String DATABASES_PATH_SEGMENT = "dbs"; + public static final String DATABASES_ROOT = ROOT + DATABASES_PATH_SEGMENT; + + public static final String USERS_PATH_SEGMENT = "users"; + public static final String PERMISSIONS_PATH_SEGMENT = "permissions"; + public static final String COLLECTIONS_PATH_SEGMENT = "colls"; + public static final String STORED_PROCEDURES_PATH_SEGMENT = "sprocs"; + public static final String TRIGGERS_PATH_SEGMENT = "triggers"; + public static final String USER_DEFINED_FUNCTIONS_PATH_SEGMENT = "udfs"; + public static final String CONFLICTS_PATH_SEGMENT = "conflicts"; + public static final String DOCUMENTS_PATH_SEGMENT = "docs"; + public static final String ATTACHMENTS_PATH_SEGMENT = "attachments"; + + // /offers + public static final String OFFERS_PATH_SEGMENT = "offers"; + public static final String OFFERS_ROOT = ROOT + OFFERS_PATH_SEGMENT + "/"; + + public static final String ADDRESS_PATH_SEGMENT = "addresses"; + public static final String PARTITIONS_PATH_SEGMENT = "partitions"; + public static final String DATABASE_ACCOUNT_PATH_SEGMENT = "databaseaccount"; + public static final String TOPOLOGY_PATH_SEGMENT = "topology"; + public static final String MEDIA_PATH_SEGMENT = "media"; + public static final String MEDIA_ROOT = ROOT + MEDIA_PATH_SEGMENT; + public static final String SCHEMAS_PATH_SEGMENT = "schemas"; + public static final String PARTITION_KEY_RANGES_PATH_SEGMENT = "pkranges"; + + public static final String USER_DEFINED_TYPES_PATH_SEGMENT = "udts"; + + public static final String RID_RANGE_PATH_SEGMENT = "ridranges"; +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathsHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathsHelper.java new file mode 100644 index 0000000000000..8294feedf2add --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/PathsHelper.java @@ -0,0 +1,866 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.Resource; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * Used internally to provide utility methods to work with the resource's path in the Azure Cosmos DB database service. + */ +public class PathsHelper { + private final static Logger logger = LoggerFactory.getLogger(PathsHelper.class); + + public static String generatePath(ResourceType resourceType, RxDocumentServiceRequest request, boolean isFeed) { + if (request.getIsNameBased()) { + return PathsHelper.generatePathForNameBased(resourceType, request.getResourceAddress(), isFeed); + } else { + return PathsHelper.generatePath(resourceType, request.getResourceId(), isFeed); + } + } + + public static String generatePathForNameBased(Resource resourceType, String resourceOwnerFullName, String resourceName) { + if (resourceName == null) + return null; + + if (resourceType instanceof Database) { + return Paths.DATABASES_PATH_SEGMENT + "/" + resourceName; + } else if (resourceOwnerFullName == null) { + return null; + } else if (resourceType instanceof DocumentCollection) { + return resourceOwnerFullName + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof StoredProcedure) { + return resourceOwnerFullName + "/" + Paths.STORED_PROCEDURES_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof UserDefinedFunction) { + return resourceOwnerFullName + "/" + Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Trigger) { + return resourceOwnerFullName + "/" + Paths.TRIGGERS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Conflict) { + return resourceOwnerFullName + "/" + Paths.CONFLICTS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof User) { + return resourceOwnerFullName + "/" + Paths.USERS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Permission) { + return resourceOwnerFullName + "/" + Paths.PERMISSIONS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Document) { + return resourceOwnerFullName + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Offer) { + return Paths.OFFERS_PATH_SEGMENT + "/" + resourceName; + } else if (resourceType instanceof Resource) { + // just generic Resource type. + return null; + } + + String errorMessage = String.format(RMResources.UnknownResourceType, resourceType.toString()); + assert false : errorMessage; + throw new IllegalArgumentException(errorMessage); + } + + private static String generatePathForNameBased(ResourceType resourceType, String resourceFullName, boolean isFeed) { + if (isFeed && Strings.isNullOrEmpty(resourceFullName) && resourceType != ResourceType.Database) { + String errorMessage = String.format(RMResources.UnexpectedResourceType, resourceType); + throw new IllegalArgumentException(errorMessage); + } + + String resourcePath = null; + if (!isFeed) { + resourcePath = resourceFullName; + } else if (resourceType == ResourceType.Database) { + return Paths.DATABASES_PATH_SEGMENT; + } else if (resourceType == ResourceType.DocumentCollection) { + resourcePath = resourceFullName + "/" + Paths.COLLECTIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.StoredProcedure) { + resourcePath = resourceFullName + "/" + Paths.STORED_PROCEDURES_PATH_SEGMENT; + } else if (resourceType == ResourceType.UserDefinedFunction) { + resourcePath = resourceFullName + "/" + Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Trigger) { + resourcePath = resourceFullName + "/" + Paths.TRIGGERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Conflict) { + resourcePath = resourceFullName + "/" + Paths.CONFLICTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Attachment) { + resourcePath = resourceFullName + "/" + Paths.ATTACHMENTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.User) { + resourcePath = resourceFullName + "/" + Paths.USERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Permission) { + resourcePath = resourceFullName + "/" + Paths.PERMISSIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Document) { + resourcePath = resourceFullName + "/" + Paths.DOCUMENTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Offer) { + return resourceFullName + "/" + Paths.OFFERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.PartitionKeyRange) { + return resourceFullName + "/" + Paths.PARTITION_KEY_RANGES_PATH_SEGMENT; + } else if (resourceType == ResourceType.Schema) { + resourcePath = resourceFullName + "/" + Paths.SCHEMAS_PATH_SEGMENT; + } else { + String errorMessage = String.format(RMResources.UnknownResourceType, resourceType.toString()); + assert false : errorMessage; + throw new IllegalArgumentException(errorMessage); + } + + return resourcePath; + } + + public static String generatePath(ResourceType resourceType, String ownerOrResourceId, boolean isFeed) { + if (isFeed && (ownerOrResourceId == null || ownerOrResourceId.isEmpty()) && + resourceType != ResourceType.Database && + resourceType != ResourceType.Offer && + resourceType != ResourceType.MasterPartition && + resourceType != ResourceType.ServerPartition && + resourceType != ResourceType.DatabaseAccount && + resourceType != ResourceType.Topology) { + throw new IllegalStateException("INVALID resource type"); + } + + if(ownerOrResourceId == null) { + ownerOrResourceId = StringUtils.EMPTY; + } + + if (isFeed && resourceType == ResourceType.Database) { + return Paths.DATABASES_PATH_SEGMENT; + } else if (resourceType == ResourceType.Database) { + return Paths.DATABASES_PATH_SEGMENT + "/" + ownerOrResourceId; + } else if (isFeed && resourceType == ResourceType.DocumentCollection) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.DocumentCollection) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString(); + } else if (isFeed && resourceType == ResourceType.Offer) { + return Paths.OFFERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Offer) { + return Paths.OFFERS_PATH_SEGMENT + "/" + ownerOrResourceId; + } else if (isFeed && resourceType == ResourceType.StoredProcedure) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.STORED_PROCEDURES_PATH_SEGMENT; + } else if (resourceType == ResourceType.StoredProcedure) { + ResourceId storedProcedureId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + storedProcedureId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + storedProcedureId.getDocumentCollectionId().toString() + "/" + + Paths.STORED_PROCEDURES_PATH_SEGMENT + "/" + storedProcedureId.getStoredProcedureId().toString(); + } else if (isFeed && resourceType == ResourceType.UserDefinedFunction) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.UserDefinedFunction) { + ResourceId functionId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + functionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + functionId.getDocumentCollectionId().toString() + "/" + + Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT + "/" + functionId.getUserDefinedFunctionId().toString(); + } else if (isFeed && resourceType == ResourceType.Trigger) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.TRIGGERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Trigger) { + ResourceId triggerId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + triggerId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + triggerId.getDocumentCollectionId().toString() + "/" + + Paths.TRIGGERS_PATH_SEGMENT + "/" + triggerId.getTriggerId().toString(); + } else if (isFeed && resourceType == ResourceType.Conflict) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.CONFLICTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Conflict) { + ResourceId conflictId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + conflictId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + conflictId.getDocumentCollectionId().toString() + "/" + + Paths.CONFLICTS_PATH_SEGMENT + "/" + conflictId.getConflictId().toString(); + } else if (isFeed && resourceType == ResourceType.PartitionKeyRange) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.PARTITION_KEY_RANGES_PATH_SEGMENT; + } else if (resourceType == ResourceType.PartitionKeyRange) { + ResourceId partitionKeyRangeId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + partitionKeyRangeId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + partitionKeyRangeId.getDocumentCollectionId().toString() + "/" + + Paths.PARTITION_KEY_RANGES_PATH_SEGMENT + "/" + partitionKeyRangeId.getPartitionKeyRangeId().toString(); + } else if (isFeed && resourceType == ResourceType.Attachment) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.DOCUMENTS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentId().toString() + "/" + + Paths.ATTACHMENTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Attachment) { + ResourceId attachmentId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + attachmentId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + attachmentId.getDocumentCollectionId().toString() + "/" + + Paths.DOCUMENTS_PATH_SEGMENT + "/" + attachmentId.getDocumentId().toString() + "/" + + Paths.ATTACHMENTS_PATH_SEGMENT + "/" + attachmentId.getAttachmentId().toString(); + } else if (isFeed && resourceType == ResourceType.User) { + return + Paths.DATABASES_PATH_SEGMENT + "/" + ownerOrResourceId + "/" + + Paths.USERS_PATH_SEGMENT; + } else if (resourceType == ResourceType.User) { + ResourceId userId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + userId.getDatabaseId().toString() + "/" + + Paths.USERS_PATH_SEGMENT + "/" + userId.getUserId().toString(); + } else if (isFeed && resourceType == ResourceType.Permission) { + ResourceId userId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + userId.getDatabaseId().toString() + "/" + + Paths.USERS_PATH_SEGMENT + "/" + userId.getUserId().toString() + "/" + + Paths.PERMISSIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Permission) { + ResourceId permissionId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + permissionId.getDatabaseId().toString() + "/" + + Paths.USERS_PATH_SEGMENT + "/" + permissionId.getUserId().toString() + "/" + + Paths.PERMISSIONS_PATH_SEGMENT + "/" + permissionId.getPermissionId().toString(); + } else if (isFeed && resourceType == ResourceType.Document) { + ResourceId documentCollectionId = ResourceId.parse(ownerOrResourceId); + + return + Paths.DATABASES_PATH_SEGMENT + "/" + documentCollectionId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentCollectionId.getDocumentCollectionId().toString() + "/" + + Paths.DOCUMENTS_PATH_SEGMENT; + } else if (resourceType == ResourceType.Document) { + ResourceId documentId = ResourceId.parse(ownerOrResourceId); + + return Paths.DATABASES_PATH_SEGMENT + "/" + documentId.getDatabaseId().toString() + "/" + + Paths.COLLECTIONS_PATH_SEGMENT + "/" + documentId.getDocumentCollectionId().toString() + "/" + + Paths.DOCUMENTS_PATH_SEGMENT + "/" + documentId.getDocumentId().toString(); + } else if (isFeed && resourceType == ResourceType.MasterPartition) { + return Paths.PARTITIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.MasterPartition) { + return Paths.PARTITIONS_PATH_SEGMENT + "/" + ownerOrResourceId; + } else if (isFeed && resourceType == ResourceType.ServerPartition) { + return Paths.PARTITIONS_PATH_SEGMENT; + } else if (resourceType == ResourceType.ServerPartition) { + return Paths.PARTITIONS_PATH_SEGMENT + "/" + ownerOrResourceId; + } else if (isFeed && resourceType == ResourceType.Topology) { + return Paths.TOPOLOGY_PATH_SEGMENT; + } else if (resourceType == ResourceType.Topology) { + return Paths.TOPOLOGY_PATH_SEGMENT + "/" + ownerOrResourceId; + } else if (isFeed && resourceType == ResourceType.DatabaseAccount) { + return Paths.DATABASE_ACCOUNT_PATH_SEGMENT; + } else if (resourceType == ResourceType.DatabaseAccount) { + return Paths.DATABASE_ACCOUNT_PATH_SEGMENT + "/" + ownerOrResourceId; + } + + String errorMessage = "invalid resource type"; + throw new IllegalStateException(errorMessage); + } + + public static PathInfo parsePathSegments(String resourceUrl) { + String[] segments = StringUtils.strip(resourceUrl, "/").split("/"); + if (segments == null || segments.length < 1) { + return null; + } + + int uriSegmentsCount = segments.length; + String segmentOne = StringUtils.strip(segments[uriSegmentsCount - 1], "/"); + String segmentTwo = (uriSegmentsCount >= 2) ? StringUtils.strip(segments[uriSegmentsCount - 2], "/") + : StringUtils.EMPTY; + + // handle name based operation + if (uriSegmentsCount >= 2) { + // parse the databaseId, if failed, it is name based routing + // mediaId is special, we will treat it always as id based. + if (Paths.MEDIA_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.OFFERS_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.PARTITIONS_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.DATABASE_ACCOUNT_PATH_SEGMENT.compareTo(segments[0]) != 0) { + Pair result = ResourceId.tryParse(segments[1]); + if (!result.getLeft() || !result.getRight().isDatabaseId()) { + return parseNameSegments(resourceUrl, segments); + } + } + + } + + // Feed paths have odd number of segments + if ((uriSegmentsCount % 2 != 0) && isResourceType(segmentOne)) { + return new PathInfo(true, segmentOne, + segmentOne.compareToIgnoreCase(Paths.DATABASES_PATH_SEGMENT) != 0 ? segmentTwo : StringUtils.EMPTY, + false); + } else if (isResourceType(segmentTwo)) { + return new PathInfo(false, segmentTwo, segmentOne, false); + } + + return null; + } + + /** + * Method which will return boolean based on whether it is able to parse the + * path and name segment from resource url , and fill info in PathInfo object + * @param resourceUrl Complete ResourceLink + * @param pathInfo Path info object which will hold information + * @param clientVersion The Client version + * @return + */ + public static boolean tryParsePathSegments(String resourceUrl, PathInfo pathInfo, String clientVersion) { + pathInfo.resourcePath = StringUtils.EMPTY; + pathInfo.resourceIdOrFullName = StringUtils.EMPTY; + pathInfo.isFeed = false; + pathInfo.isNameBased = false; + if (StringUtils.isEmpty(resourceUrl)) { + return false; + } + String trimmedStr = StringUtils.strip(resourceUrl, Constants.Properties.PATH_SEPARATOR); + String[] segments = StringUtils.split(trimmedStr, Constants.Properties.PATH_SEPARATOR); + if (segments == null || segments.length < 1) { + return false; + } + int uriSegmentsCount = segments.length; + String segmentOne = segments[uriSegmentsCount - 1]; + String segmentTwo = (uriSegmentsCount >= 2) ? segments[uriSegmentsCount - 2] : StringUtils.EMPTY; + + // handle name based operation + if (uriSegmentsCount >= 2) { + // parse the databaseId, if failed, it is name based routing + // mediaId is special, we will treat it always as id based. + if (Paths.MEDIA_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.OFFERS_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.PARTITIONS_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.DATABASE_ACCOUNT_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.TOPOLOGY_PATH_SEGMENT.compareTo(segments[0]) != 0 + && Paths.RID_RANGE_PATH_SEGMENT.compareTo(segments[0]) != 0) { + Pair result = ResourceId.tryParse(segments[1]); + if (!result.getLeft() || !result.getRight().isDatabaseId()) { + pathInfo.isNameBased = true; + return tryParseNameSegments(resourceUrl, segments, pathInfo); + } + } + } + // Feed paths have odd number of segments + if ((uriSegmentsCount % 2 != 0) && PathsHelper.isResourceType(segmentOne)) { + pathInfo.isFeed = true; + pathInfo.resourcePath = segmentOne; + // The URL for dbs may contain the management endpoint as the segmentTwo which + // should not be used as resourceId + if (!segmentOne.equalsIgnoreCase(Paths.DATABASES_PATH_SEGMENT)) { + pathInfo.resourceIdOrFullName = segmentTwo; + } + } else if (PathsHelper.isResourceType(segmentTwo)) { + pathInfo.isFeed = false; + pathInfo.resourcePath = segmentTwo; + pathInfo.resourceIdOrFullName = segmentOne; + // Media ID is not supposed to be used for any ID verification. However, if the + // old client makes a call for media ID + // we still need to support it. + // For new clients, parse to return the attachment id. For old clients do not + // modify. + if (!StringUtils.isEmpty(clientVersion) + && pathInfo.resourcePath.equalsIgnoreCase(Paths.MEDIA_PATH_SEGMENT)) { + String attachmentId = null; + byte storeIndex = 0; + // MEDIA Id parsing code will come here , supported MediaIdHelper file missing in java sdk(Sync and Async both) + //Below code from .net + // if (!MediaIdHelper.TryParseMediaId(resourceIdOrFullName, out attachmentId, out storeIndex)) + // { + // return false; + //} + //resourceIdOrFullName = attachmentId; + } + } else { + return false; + } + + return true; + + } + + /** + * Method which will return boolean based on whether it is able to parse the + * name segment from resource url , and fill info in PathInfo object + * @param resourceUrl Complete ResourceLink + * @param segments + * @param pathInfo Path info object which will hold information + * @return + */ + private static boolean tryParseNameSegments(String resourceUrl, String[] segments, PathInfo pathInfo) { + pathInfo.isFeed = false; + pathInfo.resourceIdOrFullName = ""; + pathInfo.resourcePath = ""; + if (segments == null || segments.length < 1) { + return false; + } + if (segments.length % 2 == 0) { + // even number, assume it is individual resource + if (isResourceType(segments[segments.length - 2])) { + pathInfo.resourcePath = segments[segments.length - 2]; + pathInfo.resourceIdOrFullName = StringEscapeUtils.unescapeJava(StringUtils.removeEnd( + StringUtils.removeStart(resourceUrl, Paths.ROOT), Paths.ROOT)); + return true; + } + } else { + // odd number, assume it is feed request + if (isResourceType(segments[segments.length - 1])) { + pathInfo.isFeed = true; + pathInfo.resourcePath = segments[segments.length - 1]; + String resourceIdOrFullName = resourceUrl.substring(0, StringUtils.removeEnd(resourceUrl,Paths.ROOT).lastIndexOf(Paths.ROOT)); + pathInfo.resourceIdOrFullName = StringEscapeUtils.unescapeJava(StringUtils.removeEnd( + StringUtils.removeStart(resourceIdOrFullName, Paths.ROOT), Paths.ROOT)); + return true; + } + } + return false; + } + + public static PathInfo parseNameSegments(String resourceUrl, String[] segments) { + if (segments == null || segments.length < 1) { + return null; + } + + if (segments.length % 2 == 0) { + // even number, assume it is individual resource + if (isResourceType(segments[segments.length - 2])) { + return new PathInfo(false, segments[segments.length - 2], + StringEscapeUtils.unescapeJava(StringUtils.strip(resourceUrl, Paths.ROOT)), true); + } + } else { + // odd number, assume it is feed request + if (isResourceType(segments[segments.length - 1])) { + return new PathInfo(true, segments[segments.length - 1], + StringEscapeUtils.unescapeJava(StringUtils.strip( + resourceUrl.substring(0, + StringUtils.removeEnd(resourceUrl, Paths.ROOT).lastIndexOf(Paths.ROOT)), + Paths.ROOT)), + true); + } + } + + return null; + } + + private static boolean isResourceType(String resourcePathSegment) { + if (StringUtils.isEmpty(resourcePathSegment)) { + return false; + } + + switch (resourcePathSegment.toLowerCase()) { + case Paths.ATTACHMENTS_PATH_SEGMENT: + case Paths.COLLECTIONS_PATH_SEGMENT: + case Paths.DATABASES_PATH_SEGMENT: + case Paths.PERMISSIONS_PATH_SEGMENT: + case Paths.USERS_PATH_SEGMENT: + case Paths.DOCUMENTS_PATH_SEGMENT: + case Paths.STORED_PROCEDURES_PATH_SEGMENT: + case Paths.TRIGGERS_PATH_SEGMENT: + case Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT: + case Paths.CONFLICTS_PATH_SEGMENT: + case Paths.MEDIA_PATH_SEGMENT: + case Paths.OFFERS_PATH_SEGMENT: + case Paths.PARTITIONS_PATH_SEGMENT: + case Paths.DATABASE_ACCOUNT_PATH_SEGMENT: + case Paths.TOPOLOGY_PATH_SEGMENT: + case Paths.PARTITION_KEY_RANGES_PATH_SEGMENT: + case Paths.SCHEMAS_PATH_SEGMENT: + return true; + default: + return false; + } + } + + public static String generatePathForNameBased(ResourceType resourceType, String resourceOwnerFullName, String resourceName) { + switch (resourceType) { + case Database: + return Paths.DATABASES_PATH_SEGMENT + "/" + resourceName; + case DocumentCollection: + return resourceOwnerFullName + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + resourceName; + case StoredProcedure: + return resourceOwnerFullName + "/" + Paths.STORED_PROCEDURES_PATH_SEGMENT + "/" + resourceName; + case UserDefinedFunction: + return resourceOwnerFullName + "/" + Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT + "/" + resourceName; + case Trigger: + return resourceOwnerFullName + "/" + Paths.TRIGGERS_PATH_SEGMENT + "/" + resourceName; + case Attachment: + return resourceOwnerFullName + "/" + Paths.ATTACHMENTS_PATH_SEGMENT + "/" + resourceName; + case Conflict: + return resourceOwnerFullName + "/" + Paths.CONFLICTS_PATH_SEGMENT + "/" + resourceName; + case Document: + return resourceOwnerFullName + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/" + resourceName; + case Offer: + return resourceOwnerFullName + "/" + Paths.OFFERS_PATH_SEGMENT + "/" + resourceName; + case Permission: + return resourceOwnerFullName + "/" + Paths.PERMISSIONS_PATH_SEGMENT + "/" + resourceName; + case User: + return resourceOwnerFullName + "/" + Paths.USERS_PATH_SEGMENT + "/" + resourceName; + case PartitionKeyRange: + return resourceOwnerFullName + "/" + Paths.PARTITION_KEY_RANGES_PATH_SEGMENT + "/" + resourceName; + default: + return null; + } + } + + public static String getCollectionPath(String resourceFullName) { + if (resourceFullName != null) { + String trimmedResourceFullName = Utils.trimBeginningAndEndingSlashes(resourceFullName); + int index = indexOfNth(trimmedResourceFullName, '/', 4); + if (index > 0) + return trimmedResourceFullName.substring(0, index); + } + + return resourceFullName; + } + + public static String getDatabasePath(String resourceFullName) { + if (resourceFullName != null) { + int index = indexOfNth(resourceFullName, '/', 2); + if (index > 0) + return resourceFullName.substring(0, index); + } + + return resourceFullName; + } + + public static String getParentByIndex(String resourceFullName, int segmentIndex) { + int index = indexOfNth(resourceFullName, '/', segmentIndex); + if (index > 0) + return resourceFullName.substring(0, index); + else { + index = indexOfNth(resourceFullName, '/', segmentIndex - 1); + if (index > 0) + return resourceFullName; + else + return null; + } + } + public static boolean isNameBased(String resourceIdOrFullName) { + // quick way to tell whether it is resourceId nor not, non conclusively. + if (resourceIdOrFullName != null && !resourceIdOrFullName.isEmpty() + && resourceIdOrFullName.length() > 4 && resourceIdOrFullName.charAt(3) == '/') { + return true; + } + return false; + } + + private static int indexOfNth(String str, char value, int nthOccurance) { + int remaining = nthOccurance; + char[] characters = str.toCharArray(); + for (int i = 0; i < characters.length; i++) { + if (characters[i] == value) { + remaining--; + if (remaining == 0) { + return i; + } + } + } + return -1; + } + + public static ResourceType getResourcePathSegment(String resourcePathSegment) throws BadRequestException { + if (StringUtils.isEmpty(resourcePathSegment)) { + String message = String.format(RMResources.StringArgumentNullOrEmpty, "resourcePathSegment"); + throw new BadRequestException(message); + } + + switch (resourcePathSegment) { + case Paths.ATTACHMENTS_PATH_SEGMENT: + return ResourceType.Attachment; + + case Paths.COLLECTIONS_PATH_SEGMENT: + return ResourceType.DocumentCollection; + + case Paths.DATABASES_PATH_SEGMENT: + return ResourceType.Database; + + case Paths.PERMISSIONS_PATH_SEGMENT: + return ResourceType.Permission; + + case Paths.USERS_PATH_SEGMENT: + return ResourceType.User; + + case Paths.DOCUMENTS_PATH_SEGMENT: + return ResourceType.Document; + + case Paths.STORED_PROCEDURES_PATH_SEGMENT: + return ResourceType.StoredProcedure; + + case Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT: + return ResourceType.UserDefinedFunction; + + case Paths.TRIGGERS_PATH_SEGMENT: + return ResourceType.Trigger; + + case Paths.CONFLICTS_PATH_SEGMENT: + return ResourceType.Conflict; + + case Paths.OFFERS_PATH_SEGMENT: + return ResourceType.Offer; + + case Paths.SCHEMAS_PATH_SEGMENT: + return ResourceType.Schema; + } + + String errorMessage = String.format(RMResources.UnknownResourceType, resourcePathSegment); + throw new BadRequestException(errorMessage); + } + + public static String getResourcePath(ResourceType resourceType) throws BadRequestException { + switch (resourceType) { + case Database: + return Paths.DATABASES_PATH_SEGMENT; + + case DocumentCollection: + return Paths.COLLECTIONS_PATH_SEGMENT; + + case Document: + return Paths.DOCUMENTS_PATH_SEGMENT; + + case StoredProcedure: + return Paths.STORED_PROCEDURES_PATH_SEGMENT; + + case UserDefinedFunction: + return Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT; + + case Trigger: + return Paths.TRIGGERS_PATH_SEGMENT; + + case Conflict: + return Paths.CONFLICTS_PATH_SEGMENT; + + case Attachment: + return Paths.ATTACHMENTS_PATH_SEGMENT; + + case User: + return Paths.USERS_PATH_SEGMENT; + + case Permission: + return Paths.PERMISSIONS_PATH_SEGMENT; + + case Offer: + return Paths.OFFERS_PATH_SEGMENT; + + case MasterPartition: + case ServerPartition: + return Paths.PARTITIONS_PATH_SEGMENT; + + case PartitionKeyRange: + return Paths.PARTITION_KEY_RANGES_PATH_SEGMENT; + + case Media: + return Paths.MEDIA_ROOT; + + case Schema: + return Paths.SCHEMAS_PATH_SEGMENT; + + + case DatabaseAccount: + case Topology: + + return Paths.ROOT; + + default: + String errorMessage = String.format(RMResources.UnknownResourceType, resourceType.toString()); + throw new BadRequestException(errorMessage); + } + } + + public static boolean validateResourceFullName(ResourceType resourceType, String resourceFullName) { + String[] segments = StringUtils.split(resourceFullName, '/'); + String[] resourcePathArray = getResourcePathArray(resourceType); + if (resourcePathArray == null) { + return false; + } + + if (segments.length != resourcePathArray.length * 2) { + return false; + } + for (int i = 0; i < resourcePathArray.length; i++) { + if(resourcePathArray[i].compareTo(segments[2 * i]) != 0) { + return false; + } + } + return true; + } + + private static String[] getResourcePathArray(ResourceType resourceType) { + List segments = new ArrayList(); + segments.add(Paths.DATABASES_PATH_SEGMENT); + + if (resourceType == ResourceType.Permission || + resourceType == ResourceType.User) { + segments.add(Paths.USERS_PATH_SEGMENT); + if (resourceType == ResourceType.Permission) { + segments.add(Paths.PERMISSIONS_PATH_SEGMENT); + } + } else if (resourceType == ResourceType.DocumentCollection || + resourceType == ResourceType.StoredProcedure || + resourceType == ResourceType.UserDefinedFunction || + resourceType == ResourceType.Trigger || + resourceType == ResourceType.Conflict || + resourceType == ResourceType.Attachment || + resourceType == ResourceType.Document || + resourceType == ResourceType.PartitionKeyRange || + resourceType == ResourceType.Schema) { + segments.add(Paths.COLLECTIONS_PATH_SEGMENT); + if (resourceType == ResourceType.StoredProcedure) { + segments.add(Paths.STORED_PROCEDURES_PATH_SEGMENT); + } else if(resourceType == ResourceType.UserDefinedFunction) { + segments.add(Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT); + } else if(resourceType == ResourceType.Trigger) { + segments.add(Paths.TRIGGERS_PATH_SEGMENT); + } else if (resourceType == ResourceType.Conflict) { + segments.add(Paths.CONFLICTS_PATH_SEGMENT); + } else if (resourceType == ResourceType.Schema) { + segments.add(Paths.SCHEMAS_PATH_SEGMENT); + } else if(resourceType == ResourceType.Document || + resourceType == ResourceType.Attachment) { + segments.add(Paths.DOCUMENTS_PATH_SEGMENT); + if (resourceType == ResourceType.Attachment) { + segments.add(Paths.ATTACHMENTS_PATH_SEGMENT); + } + } else if(resourceType == ResourceType.PartitionKeyRange) { + segments.add(Paths.PARTITION_KEY_RANGES_PATH_SEGMENT); + } + } else if (resourceType != ResourceType.Database) { + return null; + } + return segments.stream().toArray(String[]::new); + } + + public static boolean validateResourceId(ResourceType resourceType, String resourceId) { + if (resourceType == ResourceType.Conflict) { + return PathsHelper.validateConflictId(resourceId); + } else if (resourceType == ResourceType.Database) { + return PathsHelper.validateDatabaseId(resourceId); + } else if (resourceType == ResourceType.DocumentCollection) { + return PathsHelper.validateDocumentCollectionId(resourceId); + } else if (resourceType == ResourceType.Document) { + return PathsHelper.validateDocumentId(resourceId); + } else if (resourceType == ResourceType.Permission) { + return PathsHelper.validatePermissionId(resourceId); + } else if (resourceType == ResourceType.StoredProcedure) { + return PathsHelper.validateStoredProcedureId(resourceId); + } else if (resourceType == ResourceType.Trigger) { + return PathsHelper.validateTriggerId(resourceId); + } else if (resourceType == ResourceType.UserDefinedFunction) { + return PathsHelper.validateUserDefinedFunctionId(resourceId); + } else if (resourceType == ResourceType.User) { + return PathsHelper.validateUserId(resourceId); + } else if (resourceType == ResourceType.Attachment) { + return PathsHelper.validateAttachmentId(resourceId); + } else { + logger.error(String.format("ValidateResourceId not implemented for Type %s in ResourceRequestHandler", resourceType.toString())); + return false; + } + } + + public static boolean validateDatabaseId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getDatabase() != 0; + } + + public static boolean validateDocumentCollectionId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getDocumentCollection() != 0; + } + + public static boolean validateDocumentId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getDocument() != 0; + } + + public static boolean validateConflictId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getConflict() != 0; + } + + public static boolean validateAttachmentId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getAttachment() != 0; + } + + public static boolean validatePermissionId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getPermission() != 0; + } + + public static boolean validateStoredProcedureId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getStoredProcedure() != 0; + } + + public static boolean validateTriggerId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getTrigger() != 0; + } + + public static boolean validateUserDefinedFunctionId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getUserDefinedFunction() != 0; + } + + public static boolean validateUserId(String resourceIdString) { + Pair pair = ResourceId.tryParse(resourceIdString); + return pair.getLeft() && pair.getRight().getUser() != 0; + } + + + public static boolean isPublicResource(Resource resourceType) { + if (resourceType instanceof Database || + resourceType instanceof DocumentCollection || + resourceType instanceof StoredProcedure || + resourceType instanceof UserDefinedFunction || + resourceType instanceof Trigger || + resourceType instanceof Conflict || + resourceType instanceof User || + resourceType instanceof Permission || + resourceType instanceof Document || + resourceType instanceof Offer + ) { + return true; + } else { + return false; + } + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Permission.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Permission.java new file mode 100644 index 0000000000000..bd14847bc6996 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Permission.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.Resource; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a per-User Permission to access a specific resource e.g. Document or Collection in the Azure Cosmos DB database service. + */ +public class Permission extends Resource { + /** + * Initialize a permission object. + */ + public Permission() { + super(); + } + + /** + * Initialize a permission object from json string. + * + * @param jsonString the json string that represents the permission. + */ + public Permission(String jsonString) { + super(jsonString); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of permission + */ + public Permission id(String id){ + super.id(id); + return this; + } + + /** + * Gets the self-link of resource to which the permission applies. + * + * @return the resource link. + */ + public String getResourceLink() { + return super.getString(Constants.Properties.RESOURCE_LINK); + } + + /** + * Sets the self-link of resource to which the permission applies. + * + * @param resourceLink the resource link. + */ + public void setResourceLink(String resourceLink) { + BridgeInternal.setProperty(this, Constants.Properties.RESOURCE_LINK, resourceLink); + } + + /** + * Gets the permission mode. + * + * @return the permission mode. + */ + public PermissionMode getPermissionMode() { + String value = super.getString(Constants.Properties.PERMISSION_MODE); + return PermissionMode.valueOf(StringUtils.upperCase(value)); + } + + /** + * Sets the permission mode. + * + * @param permissionMode the permission mode. + */ + public void setPermissionMode(PermissionMode permissionMode) { + BridgeInternal.setProperty(this, Constants.Properties.PERMISSION_MODE, + permissionMode.toString().toLowerCase()); + } + + /** + * Gets the access token granting the defined permission. + * + * @return the access token. + */ + public String getToken() { + return super.getString(Constants.Properties.TOKEN); + } + + /** + * Gets the resource partition key associated with this permission object. + * + * @return the partition key. + */ + public PartitionKey getResourcePartitionKey() { + PartitionKey key = null; + Object value = super.get(Constants.Properties.RESOURCE_PARTITION_KEY); + if (value != null) { + ArrayNode arrayValue = (ArrayNode) value; + key = new PartitionKey(BridgeInternal.getValue(arrayValue.get(0))); + } + + return key; + } + + /** + * Sets the resource partition key associated with this permission object. + * + * @param partitionkey the partition key. + */ + public void setResourcePartitionKey(PartitionKey partitionkey) { + BridgeInternal.setProperty(this, Constants.Properties.RESOURCE_PARTITION_KEY, partitionkey.getInternalPartitionKey().toJson()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Quadruple.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Quadruple.java new file mode 100644 index 0000000000000..612ab51ca2172 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Quadruple.java @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Represents class with four different generic objects. + */ +public class Quadruple { + + private final A val0; + private final B val1; + private final C val2; + private final D val3; + + public static Quadruple with(final A value0, final B value1, final C value2, + final D value3) { + return new Quadruple(value0, value1, value2, value3); + } + + public Quadruple(final A value0, final B value1, final C value2, final D value3) { + this.val0 = value0; + this.val1 = value1; + this.val2 = value2; + this.val3 = value3; + } + + public A getValue0() { + return this.val0; + } + + public B getValue1() { + return this.val1; + } + + public C getValue2() { + return this.val2; + } + + public D getValue3() { + return this.val3; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryCompatibilityMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryCompatibilityMode.java new file mode 100644 index 0000000000000..191f205bbec30 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryCompatibilityMode.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * A client query compatibility mode when making query request in the Azure Cosmos DB database service. Can be used + * to force a specific query request format. + */ +public enum QueryCompatibilityMode { + Default, + Query, + SqlQuery +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetrics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetrics.java new file mode 100644 index 0000000000000..da298ab34d9f4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetrics.java @@ -0,0 +1,315 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.query.metrics.ClientSideMetrics; +import com.azure.data.cosmos.internal.query.metrics.FetchExecutionRange; +import com.azure.data.cosmos.internal.query.metrics.QueryMetricsTextWriter; +import com.azure.data.cosmos.internal.query.metrics.SchedulingTimeSpan; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +/** + * Query metrics in the Azure Cosmos database service. + * This metric represents a moving average for a set of queries whose metrics have been aggregated together. + */ +public final class QueryMetrics { + public static QueryMetrics ZERO = new QueryMetrics( + new ArrayList<>(), /* */ + 0, /* retrievedDocumentCount */ + 0, /* retrievedDocumentSize */ + 0, /* outputDocumentCount */ + 0, /* outputDocumentSize */ + 0, /* indexHitCount */ + Duration.ZERO, + QueryPreparationTimes.ZERO, + Duration.ZERO, + Duration.ZERO, + Duration.ZERO, + RuntimeExecutionTimes.ZERO, + Duration.ZERO, + ClientSideMetrics.ZERO); + private final long retrievedDocumentCount; + private final long retrievedDocumentSize; + private final long outputDocumentCount; + private final long outputDocumentSize; + private final long indexHitDocumentCount; + private final Duration totalQueryExecutionTime; + private final QueryPreparationTimes queryPreparationTimes; + private final Duration indexLookupTime; + private final Duration documentLoadTime; + private final Duration vmExecutionTime; + private final RuntimeExecutionTimes runtimeExecutionTimes; + private final Duration documentWriteTime; + private final ClientSideMetrics clientSideMetrics; + private final List activityIds; + + public QueryMetrics(List activities, long retrievedDocumentCount, long retrievedDocumentSize, long outputDocumentCount, + long outputDocumentSize, long indexHitCount, Duration totalQueryExecutionTime, + QueryPreparationTimes queryPreparationTimes, Duration indexLookupTime, Duration documentLoadTime, + Duration vmExecutionTime, RuntimeExecutionTimes runtimeExecutionTimes, Duration documentWriteTime, + ClientSideMetrics clientSideMetrics) { + this.retrievedDocumentCount = retrievedDocumentCount; + this.retrievedDocumentSize = retrievedDocumentSize; + this.outputDocumentCount = outputDocumentCount; + this.outputDocumentSize = outputDocumentSize; + this.indexHitDocumentCount = indexHitCount; + this.totalQueryExecutionTime = totalQueryExecutionTime; + this.queryPreparationTimes = queryPreparationTimes; + this.indexLookupTime = indexLookupTime; + this.documentLoadTime = documentLoadTime; + this.vmExecutionTime = vmExecutionTime; + this.runtimeExecutionTimes = runtimeExecutionTimes; + this.documentWriteTime = documentWriteTime; + this.clientSideMetrics = clientSideMetrics; + this.activityIds = activities; + } + + /** + * @return the retrievedDocumentCount + */ + public long getRetrievedDocumentCount() { + return retrievedDocumentCount; + } + + /** + * @return the retrievedDocumentSize + */ + public long getRetrievedDocumentSize() { + return retrievedDocumentSize; + } + + /** + * @return the outputDocumentCount + */ + public long getOutputDocumentCount() { + return outputDocumentCount; + } + + /** + * @return the outputDocumentSize + */ + public long getOutputDocumentSize() { + return outputDocumentSize; + } + + /** + * @return the indexHitDocumentCount + */ + public long getIndexHitDocumentCount() { + return indexHitDocumentCount; + } + + /** + * Gets the index hit ratio by query in the Azure Cosmos database service. + * + * @return the IndexHitRatio + */ + public double getIndexHitRatio() { + return this.retrievedDocumentCount == 0 ? 1 : (double) this.indexHitDocumentCount / this.retrievedDocumentCount; + } + + /** + * @return the totalQueryExecutionTime + */ + public Duration getTotalQueryExecutionTime() { + return totalQueryExecutionTime; + } + + /** + * @return the queryPreparationTimes + */ + public QueryPreparationTimes getQueryPreparationTimes() { + return queryPreparationTimes; + } + + /** + * @return the indexLookupTime + */ + public Duration getIndexLookupTime() { + return indexLookupTime; + } + + /** + * @return the documentLoadTime + */ + public Duration getDocumentLoadTime() { + return documentLoadTime; + } + + /** + * @return the vmExecutionTime + */ + public Duration getVMExecutionTime() { + return vmExecutionTime; + } + + /** + * @return the runtimeExecutionTimes + */ + public RuntimeExecutionTimes getRuntimeExecutionTimes() { + return runtimeExecutionTimes; + } + + /** + * @return the documentWriteTime + */ + public Duration getDocumentWriteTime() { + return documentWriteTime; + } + + /** + * @return the clientSideMetrics + */ + public ClientSideMetrics getClientSideMetrics() { + return clientSideMetrics; + } + + /** + * @return number of reties in the Azure Cosmos database service. + */ + public long getRetries() { + return this.clientSideMetrics.getRetries(); + } + + public QueryMetrics add(QueryMetrics... queryMetricsArgs) { + ArrayList queryMetricsList = new ArrayList(); + for (QueryMetrics queryMetrics : queryMetricsArgs) { + queryMetricsList.add(queryMetrics); + } + + queryMetricsList.add(this); + + return QueryMetrics.createFromCollection(queryMetricsList); + } + + private String toTextString() { + return toTextString(0); + } + + private String toTextString(int indentLevel) { + StringBuilder stringBuilder = new StringBuilder(); + QueryMetricsTextWriter queryMetricsTextWriter = new QueryMetricsTextWriter(stringBuilder); + queryMetricsTextWriter.writeQueryMetrics(this); + return stringBuilder.toString(); + } + + public static QueryMetrics createFromCollection(Collection queryMetricsCollection) { + long retrievedDocumentCount = 0; + long retrievedDocumentSize = 0; + long outputDocumentCount = 0; + long outputDocumentSize = 0; + long indexHitDocumentCount = 0; + Duration totalQueryExecutionTime = Duration.ZERO; + Collection queryPreparationTimesCollection = new ArrayList(); + Duration indexLookupTime = Duration.ZERO; + Duration documentLoadTime = Duration.ZERO; + Duration vmExecutionTime = Duration.ZERO; + Collection runtimeExecutionTimesCollection = new ArrayList(); + Duration documentWriteTime = Duration.ZERO; + Collection clientSideMetricsCollection = new ArrayList(); + List activityIds = new ArrayList<>(); + + for (QueryMetrics queryMetrics : queryMetricsCollection) { + if (queryMetrics == null) { + throw new NullPointerException("queryMetricsList can not have null elements"); + } + activityIds.addAll(queryMetrics.activityIds); + retrievedDocumentCount += queryMetrics.retrievedDocumentCount; + retrievedDocumentSize += queryMetrics.retrievedDocumentSize; + outputDocumentCount += queryMetrics.outputDocumentCount; + outputDocumentSize += queryMetrics.outputDocumentSize; + indexHitDocumentCount += queryMetrics.indexHitDocumentCount; + totalQueryExecutionTime = totalQueryExecutionTime.plus(queryMetrics.totalQueryExecutionTime); + queryPreparationTimesCollection.add(queryMetrics.queryPreparationTimes); + indexLookupTime = indexLookupTime.plus(queryMetrics.indexLookupTime); + documentLoadTime = documentLoadTime.plus(queryMetrics.documentLoadTime); + vmExecutionTime = vmExecutionTime.plus(queryMetrics.vmExecutionTime); + runtimeExecutionTimesCollection.add(queryMetrics.runtimeExecutionTimes); + documentWriteTime = documentWriteTime.plus(queryMetrics.documentWriteTime); + clientSideMetricsCollection.add(queryMetrics.clientSideMetrics); + } + + return new QueryMetrics(activityIds, retrievedDocumentCount, retrievedDocumentSize, outputDocumentCount, + outputDocumentSize, + indexHitDocumentCount, totalQueryExecutionTime, + QueryPreparationTimes.createFromCollection(queryPreparationTimesCollection), indexLookupTime, documentLoadTime, + vmExecutionTime, RuntimeExecutionTimes.createFromCollection(runtimeExecutionTimesCollection), + documentWriteTime, ClientSideMetrics.createFromCollection(clientSideMetricsCollection)); + } + + private static double getOrDefault(HashMap metrics, String key) { + Double doubleReference = metrics.get(key); + return doubleReference == null ? 0 : doubleReference; + } + + public static QueryMetrics createFromDelimitedString(String delimitedString) { + HashMap metrics = QueryMetricsUtils.parseDelimitedString(delimitedString); + return QueryMetrics.createFromDelimitedStringAndClientSideMetrics(delimitedString, + new ClientSideMetrics(0, 0, new ArrayList(), + new ArrayList>()), ""); + } + + public static QueryMetrics createFromDelimitedStringAndClientSideMetrics(String delimitedString, ClientSideMetrics clientSideMetrics, + String activityId) { + HashMap metrics = QueryMetricsUtils.parseDelimitedString(delimitedString); + double indexHitRatio; + double retrievedDocumentCount; + indexHitRatio = metrics.get(QueryMetricsConstants.IndexHitRatio); + retrievedDocumentCount = metrics.get(QueryMetricsConstants.RetrievedDocumentCount); + long indexHitCount = (long) (indexHitRatio * retrievedDocumentCount); + double outputDocumentCount = metrics.get(QueryMetricsConstants.OutputDocumentCount); + double outputDocumentSize = metrics.get(QueryMetricsConstants.OutputDocumentSize); + double retrievedDocumentSize = metrics.get(QueryMetricsConstants.RetrievedDocumentSize); + Duration totalQueryExecutionTime = QueryMetricsUtils.getDurationFromMetrics(metrics, QueryMetricsConstants.TotalQueryExecutionTimeInMs); + + List activities = new ArrayList<>(); + activities.add(activityId); + + return new QueryMetrics( + activities, + (long) retrievedDocumentCount, + (long) retrievedDocumentSize, + (long) outputDocumentCount, + (long) outputDocumentSize, + indexHitCount, + totalQueryExecutionTime, + QueryPreparationTimes.createFromDelimitedString(delimitedString), + QueryMetricsUtils.getDurationFromMetrics(metrics, QueryMetricsConstants.IndexLookupTimeInMs), + QueryMetricsUtils.getDurationFromMetrics(metrics, QueryMetricsConstants.DocumentLoadTimeInMs), + QueryMetricsUtils.getDurationFromMetrics(metrics, QueryMetricsConstants.VMExecutionTimeInMs), + RuntimeExecutionTimes.createFromDelimitedString(delimitedString), + QueryMetricsUtils.getDurationFromMetrics(metrics, QueryMetricsConstants.DocumentWriteTimeInMs), + clientSideMetrics); + } + + @Override + public String toString() { + return toTextString(0); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsConstants.java new file mode 100644 index 0000000000000..2fc5ebf913211 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsConstants.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +public final class QueryMetricsConstants { + // QueryMetrics + public static final String RetrievedDocumentCount = "retrievedDocumentCount"; + public static final String RetrievedDocumentSize = "retrievedDocumentSize"; + public static final String OutputDocumentCount = "outputDocumentCount"; + public static final String OutputDocumentSize = "outputDocumentSize"; + public static final String IndexHitRatio = "indexUtilizationRatio"; + public static final String IndexHitDocumentCount = "indexHitDocumentCount"; + public static final String TotalQueryExecutionTimeInMs = "totalExecutionTimeInMs"; + + // QueryPreparationTimes + public static final String QueryCompileTimeInMs = "queryCompileTimeInMs"; + public static final String LogicalPlanBuildTimeInMs = "queryLogicalPlanBuildTimeInMs"; + public static final String PhysicalPlanBuildTimeInMs = "queryPhysicalPlanBuildTimeInMs"; + public static final String QueryOptimizationTimeInMs = "queryOptimizationTimeInMs"; + + // QueryTimes + public static final String IndexLookupTimeInMs = "indexLookupTimeInMs"; + public static final String DocumentLoadTimeInMs = "documentLoadTimeInMs"; + public static final String VMExecutionTimeInMs = "VMExecutionTimeInMs"; + public static final String DocumentWriteTimeInMs = "writeOutputTimeInMs"; + + // RuntimeExecutionTimes + public static final String QueryEngineTimes = "queryEngineTimes"; + public static final String SystemFunctionExecuteTimeInMs = "systemFunctionExecuteTimeInMs"; + public static final String UserDefinedFunctionExecutionTimeInMs = "userFunctionExecuteTimeInMs"; + + // ClientSideMetrics + public static final String Retries = "retries"; + public static final String RequestCharge = "requestCharge"; + + // QueryMetrics Text + public static final String ActivityIds = "Activity Ids"; + public static final String RetrievedDocumentCountText = "Retrieved Document Count"; + public static final String RetrievedDocumentSizeText = "Retrieved Document Size"; + public static final String OutputDocumentCountText = "Output Document Count"; + public static final String OutputDocumentSizeText = "Output Document Size"; + public static final String IndexUtilizationText = "Index Utilization"; + public static final String TotalQueryExecutionTimeText = "Total Query Execution Time"; + + // QueryPreparationTimes Text + public static final String QueryPreparationTimesText = "Query Preparation Times"; + public static final String QueryCompileTimeText = "Query Compilation Time"; + public static final String LogicalPlanBuildTimeText = "Logical Plan Build Time"; + public static final String PhysicalPlanBuildTimeText = "Physical Plan Build Time"; + public static final String QueryOptimizationTimeText = "Query Optimization Time"; + + // QueryTimes Text + public static final String QueryEngineTimesText = "Query Engine Times"; + public static final String IndexLookupTimeText = "Index Lookup Time"; + public static final String DocumentLoadTimeText = "Document Load Time"; + public static final String WriteOutputTimeText = "Document Write Time"; + + // RuntimeExecutionTimes Text + public static final String RuntimeExecutionTimesText = "Runtime Execution Times"; + public static final String TotalExecutionTimeText = "Query Engine Execution Time"; + public static final String SystemFunctionExecuteTimeText = "System Function Execution Time"; + public static final String UserDefinedFunctionExecutionTimeText = "User-defined Function Execution Time"; + + // ClientSideQueryMetrics Text + public static final String ClientSideQueryMetricsText = "Client Side Metrics"; + public static final String RetriesText = "Retry Count"; + public static final String RequestChargeText = "Request Charge"; + public static final String FetchExecutionRangesText = "Partition Execution Timeline"; + public static final String SchedulingMetricsText = "Scheduling Metrics"; +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsUtils.java new file mode 100644 index 0000000000000..dc57f3d0ce223 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryMetricsUtils.java @@ -0,0 +1,191 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; + +public class QueryMetricsUtils { + static final String Indent = StringUtils.SPACE; + private static final int NANOS_TO_MILLIS = 1000000; + private static final String BytesUnitString = "bytes"; + + static HashMap parseDelimitedString(String delimitedString) { + if (delimitedString == null) { + throw new NullPointerException("delimitedString"); + } + + HashMap metrics = new HashMap<>(); + + final int key = 0; + final int value = 1; + String[] headerAttributes = StringUtils.split(delimitedString, ";"); + + for (String attribute : headerAttributes) { + String[] attributeKeyValue = StringUtils.split(attribute, "="); + + if (attributeKeyValue.length != 2) { + throw new NullPointerException("recieved a malformed delimited STRING"); + } + + String attributeKey = attributeKeyValue[key]; + double attributeValue = Double.parseDouble(attributeKeyValue[value]); + metrics.put(attributeKey, attributeValue); + } + + return metrics; + } + + static Duration durationFromMetrics(HashMap metrics, String key) { + // Just attempt to get the metrics + Double durationInMilliseconds = metrics.get(key); + if (durationInMilliseconds == null) { + return Duration.ZERO; + } + + long seconds = (long) (durationInMilliseconds / 1e3); + long nanoseconds = (long) ((durationInMilliseconds - (seconds * 1e3)) * 1e6); + + return Duration.ofSeconds(seconds, nanoseconds); + } + + static Duration getDurationFromMetrics(HashMap metrics, String key) { + double timeSpanInMilliseconds; + Duration timeSpanFromMetrics; + timeSpanInMilliseconds = metrics.get(key); + timeSpanFromMetrics = QueryMetricsUtils.doubleMillisecondsToDuration(timeSpanInMilliseconds); + return timeSpanFromMetrics; + } + + private static Duration doubleMillisecondsToDuration(double timeSpanInMilliseconds) { + long timeInNanoSeconds = (long) (timeSpanInMilliseconds * NANOS_TO_MILLIS); + return Duration.ofNanos(timeInNanoSeconds); + } + + private static void appendToStringBuilder(StringBuilder stringBuilder, String property, String value, + String units, int indentLevel) { + final String FormatString = "%-40s : %15s %-12s %s"; + + stringBuilder.append(String.format( + Locale.ROOT, + FormatString, + StringUtils.repeat(Indent, indentLevel) + property, + value, + units, + System.lineSeparator())); + } + + static void appendBytesToStringBuilder(StringBuilder stringBuilder, String property, long bytes, int indentLevel) { + final String BytesFormatString = "%d"; + + QueryMetricsUtils.appendToStringBuilder( + stringBuilder, + property, + String.format(BytesFormatString, bytes), + BytesUnitString, + indentLevel); + } + + static void appendMillisecondsToStringBuilder(StringBuilder stringBuilder, String property, double milliseconds, + int indentLevel) { + final String MillisecondsFormatString = "%f"; + final String MillisecondsUnitString = "milliseconds"; + + QueryMetricsUtils.appendToStringBuilder(stringBuilder, property, String.format(MillisecondsFormatString, + milliseconds), MillisecondsUnitString, indentLevel); + } + + static void appendNanosecondsToStringBuilder(StringBuilder stringBuilder, String property, double nanoSeconds, + int indentLevel) { + final String MillisecondsFormatString = "%.2f"; + final String MillisecondsUnitString = "milliseconds"; + QueryMetricsUtils.appendToStringBuilder(stringBuilder, property, String.format(MillisecondsFormatString, + nanosToMilliSeconds(nanoSeconds)), MillisecondsUnitString, indentLevel); + } + + static double nanosToMilliSeconds(double nanos) { + return nanos / NANOS_TO_MILLIS; + } + + static void appendHeaderToStringBuilder(StringBuilder stringBuilder, String headerTitle, int indentLevel) { + final String FormatString = "%s %s"; + stringBuilder.append(String.format( + Locale.ROOT, + FormatString, + String.join(StringUtils.repeat(Indent, indentLevel)) + headerTitle, + System.lineSeparator())); + } + + static void appendRUToStringBuilder(StringBuilder stringBuilder, String property, double requestCharge, + int indentLevel) { + final String RequestChargeFormatString = "%s"; + final String RequestChargeUnitString = "RUs"; + + QueryMetricsUtils.appendToStringBuilder( + stringBuilder, + property, + String.format(Locale.ROOT, RequestChargeFormatString, requestCharge), + RequestChargeUnitString, + indentLevel); + } + + static void appendActivityIdsToStringBuilder(StringBuilder stringBuilder, String activityIdsLabel, + List activityIds, int indentLevel) { + stringBuilder.append(activityIdsLabel); + stringBuilder.append(System.lineSeparator()); + for (String activityId : activityIds) { + stringBuilder.append(Indent); + stringBuilder.append(activityId); + stringBuilder.append(System.lineSeparator()); + } + } + + static void appendPercentageToStringBuilder(StringBuilder stringBuilder, String property, double percentage, + int indentLevel) { + final String PercentageFormatString = "%.2f"; + final String PercentageUnitString = "%"; + + QueryMetricsUtils.appendToStringBuilder(stringBuilder, property, String.format(PercentageFormatString, + percentage * 100), PercentageUnitString, indentLevel); + } + + static void appendCountToStringBuilder(StringBuilder stringBuilder, String property, long count, int indentLevel) { + final String CountFormatString = "%s"; + final String CountUnitString = ""; + + QueryMetricsUtils.appendToStringBuilder( + stringBuilder, + property, + String.format(CountFormatString, count), + CountUnitString, + indentLevel); + } + + static void appendNewlineToStringBuilder(StringBuilder stringBuilder) { + QueryMetricsUtils.appendHeaderToStringBuilder(stringBuilder, StringUtils.EMPTY, 0); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryPreparationTimes.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryPreparationTimes.java new file mode 100644 index 0000000000000..e50c3fbd91fdc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/QueryPreparationTimes.java @@ -0,0 +1,178 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import java.time.Duration; +import java.util.Collection; +import java.util.HashMap; + +public final class QueryPreparationTimes { + + static final QueryPreparationTimes ZERO = new QueryPreparationTimes(Duration.ZERO, Duration.ZERO, Duration.ZERO, Duration.ZERO); + + private final Duration queryCompilationTime; + private final Duration logicalPlanBuildTime; + private final Duration physicalPlanBuildTime; + private final Duration queryOptimizationTime; + + /** + * @param queryCompilationTime + * @param logicalPlanBuildTime + * @param physicalPlanBuildTime + * @param queryOptimizationTime + */ + QueryPreparationTimes(Duration queryCompilationTime, Duration logicalPlanBuildTime, Duration physicalPlanBuildTime, + Duration queryOptimizationTime) { + super(); + + if (queryCompilationTime == null) { + throw new NullPointerException("queryCompilationTime"); + } + + if (logicalPlanBuildTime == null) { + throw new NullPointerException("logicalPlanBuildTime"); + } + + if (physicalPlanBuildTime == null) { + throw new NullPointerException("physicalPlanBuildTime"); + } + + if (queryOptimizationTime == null) { + throw new NullPointerException("queryOptimizationTime"); + } + + this.queryCompilationTime = queryCompilationTime; + this.logicalPlanBuildTime = logicalPlanBuildTime; + this.physicalPlanBuildTime = physicalPlanBuildTime; + this.queryOptimizationTime = queryOptimizationTime; + } + + /** + * @return the queryCompilationTime + */ + public Duration getQueryCompilationTime() { + return queryCompilationTime; + } + + /** + * @return the logicalPlanBuildTime + */ + public Duration getLogicalPlanBuildTime() { + return logicalPlanBuildTime; + } + + /** + * @return the physicalPlanBuildTime + */ + public Duration getPhysicalPlanBuildTime() { + return physicalPlanBuildTime; + } + + /** + * @return the queryOptimizationTime + */ + public Duration getQueryOptimizationTime() { + return queryOptimizationTime; + } + + static QueryPreparationTimes createFromCollection( + Collection queryPreparationTimesCollection) { + if (queryPreparationTimesCollection == null) { + throw new NullPointerException("queryPreparationTimesCollection"); + } + + Duration queryCompilationTime = Duration.ZERO; + Duration logicalPlanBuildTime = Duration.ZERO; + Duration physicalPlanBuildTime = Duration.ZERO; + Duration queryOptimizationTime = Duration.ZERO; + + for (QueryPreparationTimes queryPreparationTimes : queryPreparationTimesCollection) { + if (queryPreparationTimes == null) { + throw new NullPointerException("queryPreparationTimesList can not have a null element"); + } + + queryCompilationTime = queryCompilationTime.plus(queryPreparationTimes.queryCompilationTime); + logicalPlanBuildTime = logicalPlanBuildTime.plus(queryPreparationTimes.logicalPlanBuildTime); + physicalPlanBuildTime = physicalPlanBuildTime.plus(queryPreparationTimes.physicalPlanBuildTime); + queryOptimizationTime = queryOptimizationTime.plus(queryPreparationTimes.queryOptimizationTime); + } + + return new QueryPreparationTimes( + queryCompilationTime, + logicalPlanBuildTime, + physicalPlanBuildTime, + queryOptimizationTime); + } + + static QueryPreparationTimes createFromDelimitedString(String delimitedString) { + HashMap metrics = QueryMetricsUtils.parseDelimitedString(delimitedString); + + return new QueryPreparationTimes( + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.QueryCompileTimeInMs), + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.LogicalPlanBuildTimeInMs), + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.PhysicalPlanBuildTimeInMs), + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.QueryOptimizationTimeInMs)); + } + + String toDelimitedString() { + String formatString = "%s=%.2f;%s=%.2f;%s=%.2f;%s=%.2f"; + return String.format( + formatString, + QueryMetricsConstants.QueryCompileTimeInMs, + this.queryCompilationTime.toMillis(), + QueryMetricsConstants.LogicalPlanBuildTimeInMs, + this.logicalPlanBuildTime.toMillis(), + QueryMetricsConstants.PhysicalPlanBuildTimeInMs, + this.physicalPlanBuildTime.toMillis(), + QueryMetricsConstants.QueryOptimizationTimeInMs, + this.queryOptimizationTime.toMillis()); + } + + String toTextString(int indentLevel) { + if (indentLevel == Integer.MAX_VALUE) { + throw new NumberFormatException("indentLevel input must be less than Integer.MaxValue"); + } + + StringBuilder stringBuilder = new StringBuilder(); + + QueryMetricsUtils.appendHeaderToStringBuilder(stringBuilder, QueryMetricsConstants.QueryPreparationTimesText, + indentLevel); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, QueryMetricsConstants.QueryCompileTimeText + , this.queryCompilationTime.toNanos(), indentLevel + 1); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.LogicalPlanBuildTimeText, this.logicalPlanBuildTime.toNanos(), + indentLevel + 1); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.PhysicalPlanBuildTimeText, this.physicalPlanBuildTime.toNanos(), + indentLevel + 1); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.QueryOptimizationTimeText, this.queryOptimizationTime.toNanos(), + indentLevel + 1); + return stringBuilder.toString(); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RMResources.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RMResources.java new file mode 100644 index 0000000000000..d8c58e928e9e2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RMResources.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +public class RMResources { + + public static final String UnknownResourceType = "Resource type %s is unknown"; + public static final String InvalidDocumentCollection = "The specified document collection is invalid."; + public static final String StringArgumentNullOrEmpty = "STRING agument %s is null or empty"; + public static final String PartitionKeyAndParitionKeyRangeIdBothSpecified = "Both Partition Key and Partition Key range are Specified in %s"; + public static final String PartitionKeyRangeIdOrPartitionKeyMustBeSpecified = "One of the partition key range id or partition key must be specified"; + public static final String TooFewPartitionKeyComponents = "PartitionKey has fewer components than defined the collection resource."; + public static final String TooManyPartitionKeyComponents = "PartitionKey has more components than defined the collection resource."; + public static final String UnableToDeserializePartitionKeyValue = "Cannot deserialize PartitionKey value '%s"; + public static final String Gone = "The requested resource is no longer available at the server."; + public static final String ExceptionMessageAddIpAddress = "%s, Local IP: %s"; + public static final String ExceptionMessage = "Message: %s"; + public static final String ServiceUnavailable = "Service is currently unavailable, please retry after a while. If this problem persists please contact support."; + public static final String InternalServerError = "Unknown server error occurred when processing this request."; + public static final String InvalidBackendResponse = "The backend response was not in the correct format."; + public static final String PartitionKeyRangeNotFound = "PartitionKeyRange with id %s in collection %s doesn't exist"; + public static final String InvalidTarget = "Target for the request is invalid"; + public static final String InvalidPartitionKey = "Partition key %s is invalid."; + public static final String PartitionKeyMismatch = "Partition key provided either doesn't correspond to definition in the collection or doesn't match partition key field values specified in the document."; + public static final String MissingPartitionKeyValue = "PartitionKey value must be supplied for this operation."; + public static final String InvalidConflictResolutionMode = "INVALID mode '%s' for setting '%s'. MODE expected is '%s'."; + public static final String InvalidRegionsInSessionToken = "Compared session tokens '%s' and '%s' has unexpected regions."; + public static final String InvalidSessionToken = "The session token provided '%s' is invalid."; + public static final String ResourceTokenNotFound = "Resource token not found."; + public static final String Unauthorized = "Unable to authenticate the request. The request requires valid user authentication."; + public static final String Forbidden = "Unable to proceed with the request. Please check the authorization claims to ensure the required permissions to process the request."; + public static final String NotFound = "Entity with the specified id does not exist in the system."; + public static final String BadRequest = "One of the input values is invalid."; + public static final String MethodNotAllowed = "The requested verb is not supported."; + public static final String EntityAlreadyExists = "Entity with the specified id already exists in the system."; + public static final String PreconditionFailed = "Operation cannot be performed because one of the specified precondition is not met."; + public static final String RequestEntityTooLarge = "The size of the response exceeded the maximum allowed size, limit the response size by specifying smaller value for '%s' header."; + public static final String Locked = ""; + public static final String RetryWith = "Retry the request."; + public static final String TooManyRequests = "The request rate is too large. Please retry after sometime."; + public static final String UnexpectedResourceType = "ResourceType %s is unexpected."; + public static final String InvalidHeaderValue = "Value '%s' specified for the header '%s' is invalid."; + public static final String RequestTimeout = "Request timed out."; + public static final String GlobalStrongWriteBarrierNotMet = "Global STRONG write barrier has not been met for the request."; + public static final String InvalidRequestHeaderValue = "INVALID value for request header %s: %s"; + public static final String InvalidResourceAddress = "INVALID address for resource %s: %s"; + public static final String ReadQuorumNotMet = "READ Quorum size of %d is not met for the request."; + public static final String ReadSessionNotAvailable = "The read session is not available for the input session token."; + public static final String InvalidUrl = "InvalidUrl"; + public static final String InvalidResourceUrlQuery = "The value %s specified for query %s is invalid."; + public static final String PartitionKeyRangeIdAbsentInContext = "PartitionKeyRangeId is absent in the context."; +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReadFeedKeyType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReadFeedKeyType.java new file mode 100644 index 0000000000000..7d4ae90623ec2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReadFeedKeyType.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +/** + * Type of Start and End key for ReadFeedKey + */ +public enum ReadFeedKeyType { + /** + * Use resource name + */ + ResourceId, + + /** + * Use effective partition key + */ + EffectivePartitionKey +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RemoteStorageType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RemoteStorageType.java new file mode 100644 index 0000000000000..b36fecad18f33 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RemoteStorageType.java @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal; + +public enum RemoteStorageType { + /** + * Use standard storage + */ + NotSpecified, + + /** + * Use standard storage + */ + Standard, + + /** + * Use premium storage + */ + Premium +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicy.java new file mode 100644 index 0000000000000..86570eb1c4b72 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicy.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.caches.RxClientCollectionCache; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +public class RenameCollectionAwareClientRetryPolicy implements IDocumentClientRetryPolicy { + + private final static Logger logger = LoggerFactory.getLogger(RenameCollectionAwareClientRetryPolicy.class); + + private final IDocumentClientRetryPolicy retryPolicy; + private final ISessionContainer sessionContainer; + private final RxClientCollectionCache collectionCache; + private RxDocumentServiceRequest request; + private boolean hasTriggered = false; + + public RenameCollectionAwareClientRetryPolicy(ISessionContainer sessionContainer, RxClientCollectionCache collectionCache, IDocumentClientRetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + this.sessionContainer = sessionContainer; + this.collectionCache = collectionCache; + this.request = null; + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + this.request = request; + this.retryPolicy.onBeforeSendRequest(request); + } + + @Override + public Mono shouldRetry(Exception e) { + return this.retryPolicy.shouldRetry(e).flatMap(shouldRetryResult -> { + if (!shouldRetryResult.shouldRetry && !this.hasTriggered) { + CosmosClientException clientException = Utils.as(e, CosmosClientException.class); + + if (this.request == null) { + // someone didn't call OnBeforeSendRequest - nothing we can do + logger.error("onBeforeSendRequest is not invoked, encountered failure due to request being null", e); + return Mono.just(ShouldRetryResult.error(e)); + } + + if (clientException != null && this.request.getIsNameBased() && + Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.NOTFOUND) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)) { + // Clear the session token, because the collection name might be reused. + logger.warn("Clear the token for named base request {}", request.getResourceAddress()); + + this.sessionContainer.clearTokenByCollectionFullName(request.getResourceAddress()); + + this.hasTriggered = true; + + String oldCollectionRid = request.requestContext.resolvedCollectionRid; + + request.forceNameCacheRefresh = true; + request.requestContext.resolvedCollectionRid = null; + + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + + return collectionObs.flatMap(collectionInfo -> { + if (!StringUtils.isEmpty(oldCollectionRid) && !StringUtils.isEmpty(collectionInfo.resourceId())) { + return Mono.just(ShouldRetryResult.retryAfter(Duration.ZERO)); + } + return Mono.just(shouldRetryResult); + }).switchIfEmpty(Mono.defer(() -> { + logger.warn("Can't recover from session unavailable exception because resolving collection name {} returned null", request.getResourceAddress()); + return Mono.just(shouldRetryResult); + })).onErrorResume(throwable -> { + // When resolveCollectionAsync throws an exception ignore it because it's an attempt to recover an existing + // error. When the recovery fails we return ShouldRetryResult.noRetry and propagate the original exception to the client + + logger.warn("Can't recover from session unavailable exception because resolving collection name {} failed with {}", request.getResourceAddress(), throwable.getMessage()); + if (throwable instanceof Exception) { + return Mono.just(ShouldRetryResult.error((Exception) throwable)); + } + return Mono.error(throwable); + }); + } + } + return Mono.just(shouldRetryResult); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicatedResourceClientUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicatedResourceClientUtils.java new file mode 100644 index 0000000000000..a75c5c83fab7b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicatedResourceClientUtils.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class ReplicatedResourceClientUtils { + + public static boolean isReadingFromMaster(ResourceType resourceType, OperationType operationType) { + if (resourceType == ResourceType.Offer || + resourceType == ResourceType.Database || + resourceType == ResourceType.User || + resourceType == ResourceType.UserDefinedType || + resourceType == ResourceType.Permission || + resourceType == ResourceType.Topology || + resourceType == ResourceType.DatabaseAccount || + (resourceType == ResourceType.PartitionKeyRange && operationType != OperationType.GetSplitPoint && operationType != OperationType.AbortSplit) || + (resourceType == ResourceType.DocumentCollection && (operationType == OperationType.ReadFeed || operationType == OperationType.Query || operationType == OperationType.SqlQuery))) + { + return true; + } + + return false; + } + + public static boolean isMasterResource(ResourceType resourceType) { + if (resourceType == ResourceType.Offer || + resourceType == ResourceType.Database || + resourceType == ResourceType.User || + resourceType == ResourceType.UserDefinedType || + resourceType == ResourceType.Permission || + resourceType == ResourceType.Topology || + resourceType == ResourceType.DatabaseAccount || + resourceType == ResourceType.PartitionKeyRange || + resourceType == ResourceType.DocumentCollection) { + return true; + } + + return false; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicationPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicationPolicy.java new file mode 100644 index 0000000000000..0036edba15523 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ReplicationPolicy.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; + +/** + * Encapsulates the replication policy in the Azure Cosmos DB database service. + */ +public class ReplicationPolicy extends JsonSerializable { + private static final int DEFAULT_MAX_REPLICA_SET_SIZE = 4; + private static final int DEFAULT_MIN_REPLICA_SET_SIZE = 3; + + public ReplicationPolicy() { + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the replication policy. + */ + public ReplicationPolicy(String jsonString) { + super(jsonString); + } + + public int getMaxReplicaSetSize() { + Integer maxReplicaSetSize = super.getInt(Constants.Properties.MAX_REPLICA_SET_SIZE); + if (maxReplicaSetSize == null) { + return DEFAULT_MAX_REPLICA_SET_SIZE; + } + + return maxReplicaSetSize; + } + + public void setMaxReplicaSetSize(int value) { + Integer maxReplicaSetSize = super.getInt(Constants.Properties.MAX_REPLICA_SET_SIZE); + BridgeInternal.setProperty(this, Constants.Properties.MAX_REPLICA_SET_SIZE, value); + } + + public int getMinReplicaSetSize() { + Integer minReplicaSetSize = super.getInt(Constants.Properties.MIN_REPLICA_SET_SIZE); + if (minReplicaSetSize == null) { + return DEFAULT_MIN_REPLICA_SET_SIZE; + } + + return minReplicaSetSize; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestChargeTracker.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestChargeTracker.java new file mode 100644 index 0000000000000..3621fca0ff29b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestChargeTracker.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * Tracks requests charge in the Azure Cosmos DB database service. + */ +public final class RequestChargeTracker { + private final static int NUMBER_OF_DECIMAL_POINT_TO_RESERVE_FACTOR = 1000; + private final AtomicLong totalRUs = new AtomicLong(); + + public double getTotalRequestCharge() { + return ((double) this.totalRUs.get()) / NUMBER_OF_DECIMAL_POINT_TO_RESERVE_FACTOR; + } + + public void addCharge(double ruUsage) { + this.totalRUs.addAndGet((long) (ruUsage * NUMBER_OF_DECIMAL_POINT_TO_RESERVE_FACTOR)); + } + + public double getAndResetCharge() { + return (double) this.totalRUs.getAndSet(0) / NUMBER_OF_DECIMAL_POINT_TO_RESERVE_FACTOR; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestOptions.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestOptions.java new file mode 100644 index 0000000000000..556491686f7df --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RequestOptions.java @@ -0,0 +1,334 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.AccessCondition; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.IndexingDirective; +import com.azure.data.cosmos.PartitionKey; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Encapsulates options that can be specified for a request issued to the Azure Cosmos DB database service. + */ +public class RequestOptions { + private Map customOptions; + private List preTriggerInclude; + private List postTriggerInclude; + private AccessCondition accessCondition; + private IndexingDirective indexingDirective; + private ConsistencyLevel consistencyLevel; + private String sessionToken; + private Integer resourceTokenExpirySeconds; + private String offerType; + private Integer offerThroughput; + private PartitionKey partitionkey; + private String partitionKeyRangeId; + private boolean scriptLoggingEnabled; + private boolean populateQuotaInfo; + private Map properties; + + /** + * Gets the triggers to be invoked before the operation. + * + * @return the triggers to be invoked before the operation. + */ + public List getPreTriggerInclude() { + return this.preTriggerInclude; + } + + /** + * Sets the triggers to be invoked before the operation. + * + * @param preTriggerInclude the triggers to be invoked before the operation. + */ + public void setPreTriggerInclude(List preTriggerInclude) { + this.preTriggerInclude = preTriggerInclude; + } + + /** + * Gets the triggers to be invoked after the operation. + * + * @return the triggers to be invoked after the operation. + */ + public List getPostTriggerInclude() { + return this.postTriggerInclude; + } + + /** + * Sets the triggers to be invoked after the operation. + * + * @param postTriggerInclude the triggers to be invoked after the operation. + */ + public void setPostTriggerInclude(List postTriggerInclude) { + this.postTriggerInclude = postTriggerInclude; + } + + /** + * Gets the conditions associated with the request. + * + * @return the access condition. + */ + public AccessCondition getAccessCondition() { + return this.accessCondition; + } + + /** + * Sets the conditions associated with the request. + * + * @param accessCondition the access condition. + */ + public void setAccessCondition(AccessCondition accessCondition) { + this.accessCondition = accessCondition; + } + + /** + * Gets the indexing directive (index, do not index etc). + * + * @return the indexing directive. + */ + public IndexingDirective getIndexingDirective() { + return this.indexingDirective; + } + + /** + * Sets the indexing directive (index, do not index etc). + * + * @param indexingDirective the indexing directive. + */ + public void setIndexingDirective(IndexingDirective indexingDirective) { + this.indexingDirective = indexingDirective; + } + + /** + * Gets the consistency level required for the request. + * + * @return the consistency level. + */ + public ConsistencyLevel getConsistencyLevel() { + return this.consistencyLevel; + } + + /** + * Sets the consistency level required for the request. + * + * @param consistencyLevel the consistency level. + */ + public void setConsistencyLevel(ConsistencyLevel consistencyLevel) { + this.consistencyLevel = consistencyLevel; + } + + /** + * Gets the token for use with session consistency. + * + * @return the session token. + */ + public String getSessionToken() { + return this.sessionToken; + } + + /** + * Sets the token for use with session consistency. + * + * @param sessionToken the session token. + */ + public void setSessionToken(String sessionToken) { + this.sessionToken = sessionToken; + } + + /** + * Gets the expiry time for resource token. Used when creating, updating, reading permission. + * + * @return the resource token expiry seconds. + */ + public Integer getResourceTokenExpirySeconds() { + return this.resourceTokenExpirySeconds; + } + + /** + * Sets the expiry time for resource token. Used when creating, updating, reading permission. + * + * @param resourceTokenExpirySeconds the resource token expiry seconds. + */ + public void setResourceTokenExpirySeconds(Integer resourceTokenExpirySeconds) { + this.resourceTokenExpirySeconds = resourceTokenExpirySeconds; + } + + /** + * Gets the offer type when creating a document collection. + * + * @return the offer type. + */ + public String getOfferType() { + return this.offerType; + } + + /** + * Sets the offer type when creating a document collection. + * + * @param offerType the offer type. + */ + public void setOfferType(String offerType) { + this.offerType = offerType; + } + + /** + * Gets the throughput in the form of Request Units per second when creating a document collection. + * + * @return the throughput value. + */ + public Integer getOfferThroughput() { + return this.offerThroughput; + } + + /** + * Sets the throughput in the form of Request Units per second when creating a document collection. + * + * @param offerThroughput the throughput value. + */ + public void setOfferThroughput(Integer offerThroughput) { + this.offerThroughput = offerThroughput; + } + + /** + * Gets the partition key used to identify the current request's target partition. + * + * @return the partition key value. + */ + public PartitionKey getPartitionKey() { + return this.partitionkey; + } + + /** + * Sets the partition key used to identify the current request's target partition. + * + * @param partitionkey the partition key value. + */ + public void setPartitionKey(PartitionKey partitionkey) { + this.partitionkey = partitionkey; + } + + /** + * Internal usage only: Gets the partition key range id used to identify the current request's target partition. + * + * @return the partition key range id value. + */ + String getPartitionKeyRangeId() { + return this.partitionKeyRangeId; + } + + /** + * Internal usage only: Sets the partition key range id used to identify the current request's target partition. + * + * @param partitionKeyRangeId the partition key range id value. + */ + protected void setPartitionKeyRengeId(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + } + + /** + * Gets whether Javascript stored procedure logging is enabled for the current request in the Azure Cosmos DB database + * service or not. + * + * @return true if Javascript stored procedure logging is enabled + */ + public boolean isScriptLoggingEnabled() { + return scriptLoggingEnabled; + } + + /** + * Sets whether Javascript stored procedure logging is enabled for the current request in the Azure Cosmos DB database + * service or not. + * + * @param scriptLoggingEnabled true if stored procedure Javascript logging is enabled + */ + public void setScriptLoggingEnabled(boolean scriptLoggingEnabled) { + this.scriptLoggingEnabled = scriptLoggingEnabled; + } + + /** + * Gets the PopulateQuotaInfo setting for document collection read requests in the Azure Cosmos DB database service. + * PopulateQuotaInfo is used to enable/disable getting document collection quota related stats for document + * collection read requests. + * + * @return true if PopulateQuotaInfo is enabled + */ + public boolean isPopulateQuotaInfo() { + return populateQuotaInfo; + } + + /** + * Sets the PopulateQuotaInfo setting for document collection read requests in the Azure Cosmos DB database service. + * PopulateQuotaInfo is used to enable/disable getting document collection quota related stats for document + * collection read requests. + * + * @param populateQuotaInfo a boolean value indicating whether PopulateQuotaInfo is enabled or not + */ + public void setPopulateQuotaInfo(boolean populateQuotaInfo) { + this.populateQuotaInfo = populateQuotaInfo; + } + + /** + * Sets the custom request option value by key + * + * @param name a string representing the custom option's name + * @param value a STRING representing the custom option's value + */ + public void setHeader(String name, String value) { + if (this.customOptions == null) { + this.customOptions = new HashMap<>(); + } + this.customOptions.put(name, value); + } + + /** + * Gets the custom request options + * + * @return Map of custom request options + */ + public Map getHeaders() { + return this.customOptions; + } + /** + * Gets the properties + * + * @return Map of request options properties + */ + public Map getProperties() { + return properties; + } + + /** + * Sets the properties used to identify the request token. + * + * @param properties the properties. + */ + public void setProperties(Map properties) { + this.properties = properties; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResetSessionTokenRetryPolicyFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResetSessionTokenRetryPolicyFactory.java new file mode 100644 index 0000000000000..8a76dde7f420b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResetSessionTokenRetryPolicyFactory.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.caches.RxClientCollectionCache; + +public class ResetSessionTokenRetryPolicyFactory implements IRetryPolicyFactory { + + private final IRetryPolicyFactory retryPolicy; + private final ISessionContainer sessionContainer; + private final RxClientCollectionCache collectionCache; + + public ResetSessionTokenRetryPolicyFactory(ISessionContainer sessionContainer, RxClientCollectionCache collectionCache, IRetryPolicyFactory retryPolicy) { + this.retryPolicy = retryPolicy; + this.sessionContainer = sessionContainer; + this.collectionCache = collectionCache; + } + + @Override + public IDocumentClientRetryPolicy getRequestPolicy() { + return new RenameCollectionAwareClientRetryPolicy(this.sessionContainer, this.collectionCache, retryPolicy.getRequestPolicy()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceId.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceId.java new file mode 100644 index 0000000000000..deeba0aec6352 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceId.java @@ -0,0 +1,540 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** + * Used internally to represents a Resource ID in the Azure Cosmos DB database service. + */ +public class ResourceId { + static final short Length = 20; + static final short OFFER_ID_LENGTH = 3; + static final short MAX_PATH_FRAGMENT = 8; + + private int database; + private int documentCollection; + private long storedProcedure; + private long trigger; + private long userDefinedFunction; + private long conflict; + private long document; + private long partitionKeyRange; + private int user; + private long permission; + private int attachment; + private long offer; + + private ResourceId() { + this.offer = 0; + this.database = 0; + this.documentCollection = 0; + this.storedProcedure = 0; + this.trigger = 0; + this.userDefinedFunction = 0; + this.document = 0; + this.partitionKeyRange = 0; + this.user = 0; + this.conflict = 0; + this.permission = 0; + this.attachment = 0; + } + + public static ResourceId parse(String id) throws IllegalArgumentException { + Pair pair = ResourceId.tryParse(id); + + if (!pair.getKey()) { + throw new IllegalArgumentException(String.format( + "INVALID resource id %s", id)); + } + return pair.getValue(); + } + + public static byte[] parse(ResourceType type, String id) { + if (ResourceId.hasNonHierarchicalResourceId(type)) { + return id.getBytes(StandardCharsets.UTF_8); + } + return ResourceId.parse(id).getValue(); + } + + private static boolean hasNonHierarchicalResourceId(ResourceType type) { + switch (type) { + case MasterPartition: + case ServerPartition: + case RidRange: + return true; + default: + return false; + } + } + + public static ResourceId newDatabaseId(int dbid) { + ResourceId resourceId = new ResourceId(); + resourceId.database = dbid; + return resourceId; + } + + public static ResourceId newDocumentCollectionId(String databaseId, int collectionId) { + ResourceId dbId = ResourceId.parse(databaseId); + + return newDocumentCollectionId(dbId.database, collectionId); + } + + static ResourceId newDocumentCollectionId(int dbId, int collectionId) { + ResourceId collectionResourceId = new ResourceId(); + collectionResourceId.database = dbId; + collectionResourceId.documentCollection = collectionId; + + return collectionResourceId; + } + + public static ResourceId newUserId(String databaseId, int userId) { + ResourceId dbId = ResourceId.parse(databaseId); + + ResourceId userResourceId = new ResourceId(); + userResourceId.database = dbId.database; + userResourceId.user = userId; + + return userResourceId; + } + + public static ResourceId newPermissionId(String userId, long permissionId) { + ResourceId usrId = ResourceId.parse(userId); + + ResourceId permissionResourceId = new ResourceId(); + permissionResourceId.database = usrId.database; + permissionResourceId.user = usrId.user; + permissionResourceId.permission = permissionId; + return permissionResourceId; + } + + public static ResourceId newAttachmentId(String documentId, int attachmentId) { + ResourceId docId = ResourceId.parse(documentId); + + ResourceId attachmentResourceId = new ResourceId(); + attachmentResourceId.database = docId.database; + attachmentResourceId.documentCollection = docId.documentCollection; + attachmentResourceId.document = docId.document; + attachmentResourceId.attachment = attachmentId; + + return attachmentResourceId; + } + + public static Pair tryParse(String id) { + ResourceId rid = null; + + try { + if (StringUtils.isEmpty(id)) + return Pair.of(false, null); + + if (id.length() % 4 != 0) { + // our ResourceId string is always padded + return Pair.of(false, null); + } + + byte[] buffer = null; + + Pair pair = ResourceId.verify(id); + + if (!pair.getKey()) + return Pair.of(false, null); + + buffer = pair.getValue(); + + if (buffer.length % 4 != 0 && buffer.length != ResourceId.OFFER_ID_LENGTH) { + return Pair.of(false, null); + } + + rid = new ResourceId(); + + if (buffer.length == ResourceId.OFFER_ID_LENGTH) { + rid.offer = 0; + for (int index = 0; index < ResourceId.OFFER_ID_LENGTH; index++) + { + rid.offer |= (long)(buffer[index] << (index * 8)); + } + return Pair.of(true, rid); + } + + if (buffer.length >= 4) + rid.database = ByteBuffer.wrap(buffer).getInt(); + + if (buffer.length >= 8) { + byte[] temp = new byte[4]; + ResourceId.blockCopy(buffer, 4, temp, 0, 4); + + boolean isCollection = (temp[0] & (128)) > 0; + + if (isCollection) { + rid.documentCollection = ByteBuffer.wrap(temp).getInt(); + + if (buffer.length >= 16) { + byte[] subCollRes = new byte[8]; + ResourceId.blockCopy(buffer, 8, subCollRes, 0, 8); + + long subCollectionResource = ByteBuffer.wrap(buffer, 8, 8).getLong(); + if ((subCollRes[7] >> 4) == (byte) CollectionChildResourceType.Document) { + rid.document = subCollectionResource; + + if (buffer.length == 20) { + rid.attachment = ByteBuffer.wrap(buffer, 16, 4).getInt(); + } + } else if (Math.abs(subCollRes[7] >> 4) == (byte) CollectionChildResourceType.StoredProcedure) { + rid.storedProcedure = subCollectionResource; + } else if ((subCollRes[7] >> 4) == (byte) CollectionChildResourceType.Trigger) { + rid.trigger = subCollectionResource; + } else if ((subCollRes[7] >> 4) == (byte) CollectionChildResourceType.UserDefinedFunction) { + rid.userDefinedFunction = subCollectionResource; + } else if ((subCollRes[7] >> 4) == (byte) CollectionChildResourceType.Conflict) { + rid.conflict = subCollectionResource; + } else if ((subCollRes[7] >> 4) == (byte) CollectionChildResourceType.PartitionKeyRange) { + rid.partitionKeyRange = subCollectionResource; + } else { + return Pair.of(false, rid); + } + } else if (buffer.length != 8) { + return Pair.of(false, rid); + } + } else { + rid.user = ByteBuffer.wrap(temp).getInt(); + + if (buffer.length == 16) { + rid.permission = ByteBuffer.wrap(buffer, 8, 8).getLong(); + } else if (buffer.length != 8) { + return Pair.of(false, rid); + } + } + } + + return Pair.of(true, rid); + } catch (Exception e) { + return Pair.of(false, null); + } + } + + public static Pair verify(String id) { + if (StringUtils.isEmpty(id)) + throw new IllegalArgumentException("id"); + + byte[] buffer = null; + + try { + buffer = ResourceId.fromBase64String(id); + } catch (Exception e) { + } + + if (buffer == null || buffer.length > ResourceId.Length) { + buffer = null; + return Pair.of(false, buffer); + } + + return Pair.of(true, buffer); + } + + public static boolean verifyBool(String id) { + return verify(id).getKey(); + } + + static byte[] fromBase64String(String s) { + return Utils.Base64Decoder.decode(s.replace('-', '/')); + } + + static String toBase64String(byte[] buffer) { + return ResourceId.toBase64String(buffer, 0, buffer.length); + } + + static String toBase64String(byte[] buffer, int offset, int length) { + byte[] subBuffer = Arrays.copyOfRange(buffer, offset, length); + + return Utils.encodeBase64String(subBuffer).replace('/', '-'); + } + + // Copy the bytes provided with a for loop, faster when there are only a few + // bytes to copy + static void blockCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count) { + int stop = srcOffset + count; + for (int i = srcOffset; i < stop; i++) + dst[dstOffset++] = src[i]; + } + + private static byte[] convertToBytesUsingByteBuffer(int value) { + ByteOrder order = ByteOrder.BIG_ENDIAN; + ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.order(order); + return buffer.putInt(value).array(); + } + + private static byte[] convertToBytesUsingByteBuffer(long value) { + ByteOrder order = ByteOrder.BIG_ENDIAN; + ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.order(order); + return buffer.putLong(value).array(); + } + + public boolean isDatabaseId() { + return this.getDatabase() != 0 && (this.getDocumentCollection() == 0 && this.getUser() == 0); + } + + public int getDatabase() { + return this.database; + } + + public ResourceId getDatabaseId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + return rid; + } + + public int getDocumentCollection() { + return this.documentCollection; + } + + public ResourceId getDocumentCollectionId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + return rid; + } + + /** + * Unique (across all databases) Id for the DocumentCollection. + * First 4 bytes are DatabaseId and next 4 bytes are CollectionId. + * + * @return the unique collectionId + */ + public long getUniqueDocumentCollectionId() { + return (long) this.database << 32 | this.documentCollection; + } + + public long getStoredProcedure() { + return this.storedProcedure; + } + + public ResourceId getStoredProcedureId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.storedProcedure = this.storedProcedure; + return rid; + } + + public long getTrigger() { + return this.trigger; + } + + public ResourceId getTriggerId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.trigger = this.trigger; + return rid; + } + + public long getUserDefinedFunction() { + return this.userDefinedFunction; + } + + public ResourceId getUserDefinedFunctionId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.userDefinedFunction = this.userDefinedFunction; + return rid; + } + + public long getConflict() { + return this.conflict; + } + + public ResourceId getConflictId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.conflict = this.conflict; + return rid; + } + + public long getDocument() { + return this.document; + } + + public ResourceId getDocumentId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.document = this.document; + return rid; + } + + public long getPartitionKeyRange() { + return this.partitionKeyRange; + } + + public ResourceId getPartitionKeyRangeId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.partitionKeyRange = this.partitionKeyRange; + return rid; + } + + public int getUser() { + return this.user; + } + + public ResourceId getUserId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.user = this.user; + return rid; + } + + public long getPermission() { + return this.permission; + } + + public ResourceId getPermissionId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.user = this.user; + rid.permission = this.permission; + return rid; + } + + public int getAttachment() { + return this.attachment; + } + + public ResourceId getAttachmentId() { + ResourceId rid = new ResourceId(); + rid.database = this.database; + rid.documentCollection = this.documentCollection; + rid.document = this.document; + rid.attachment = this.attachment; + return rid; + } + + public long getOffer() { return this.offer; } + + public ResourceId getOfferId() { + ResourceId rid = new ResourceId(); + rid.offer = this.offer; + return rid; + } + + public byte[] getValue() { + int len = 0; + if (this.offer != 0) + len += ResourceId.OFFER_ID_LENGTH; + else if (this.database != 0) + len += 4; + if (this.documentCollection != 0 || this.user != 0) + len += 4; + if (this.document != 0 || this.permission != 0 + || this.storedProcedure != 0 || this.trigger != 0 + || this.userDefinedFunction != 0 || this.conflict != 0 + || this.partitionKeyRange != 0) + len += 8; + if (this.attachment != 0) + len += 4; + + byte[] val = new byte[len]; + + if (this.offer != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.offer), + 0, val, 0, ResourceId.OFFER_ID_LENGTH); + else if (this.database != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.database), + 0, val, 0, 4); + + if (this.documentCollection != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.documentCollection), + 0, val, 4, 4); + else if (this.user != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.user), + 0, val, 4, 4); + + if (this.storedProcedure != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.storedProcedure), + 0, val, 8, 8); + else if (this.trigger != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.trigger), + 0, val, 8, 8); + else if (this.userDefinedFunction != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.userDefinedFunction), + 0, val, 8, 8); + else if (this.conflict != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.conflict), + 0, val, 8, 8); + else if (this.document != 0) + ResourceId.blockCopy(convertToBytesUsingByteBuffer(this.document), + 0, val, 8, 8); + else if (this.permission != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.permission), + 0, val, 8, 8); + else if (this.partitionKeyRange != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.partitionKeyRange), + 0, val, 8, 8); + + if (this.attachment != 0) + ResourceId.blockCopy( + convertToBytesUsingByteBuffer(this.attachment), + 0, val, 16, 4); + + return val; + } + + public String toString() { + return ResourceId.toBase64String(this.getValue()); + } + + public boolean equals(ResourceId other) { + if (other == null) { + return false; + } + + return Arrays.equals(this.getValue(), other.getValue()); + } + + // Using a byte however, we only need nibble here. + private static class CollectionChildResourceType { + public static final byte Document = 0x0; + public static final byte StoredProcedure = 0x08; + public static final byte Trigger = 0x07; + public static final byte UserDefinedFunction = 0x06; + public static final byte Conflict = 0x04; + public static final byte PartitionKeyRange = 0x05; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceResponse.java new file mode 100644 index 0000000000000..2c9f2b1684094 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceResponse.java @@ -0,0 +1,445 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import com.azure.data.cosmos.Resource; +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents the service response to a request made from DocumentClient in the Azure Cosmos DB database service. + * Contains both the resource and the response headers. + * + * @param the resource type of the resource response. + */ +public final class ResourceResponse { + private Class cls; + private T resource; + private RxDocumentServiceResponse response; + private Map usageHeaders; + private Map quotaHeaders; + + public ResourceResponse(RxDocumentServiceResponse response, Class cls) { + this.response = response; + this.usageHeaders = new HashMap(); + this.quotaHeaders = new HashMap(); + this.cls = cls; + this.resource = this.response.getResource(this.cls); + } + + /** + * Max Quota. + * + * @return the database quota. + */ + public long getDatabaseQuota() { + return this.getMaxQuotaHeader(Constants.Quota.DATABASE); + } + + /** + * Current Usage. + * + * @return the current database usage. + */ + public long getDatabaseUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.DATABASE); + } + + /** + * Max Quota. + * + * @return the collection quota. + */ + public long getCollectionQuota() { + return this.getMaxQuotaHeader(Constants.Quota.COLLECTION); + } + + /** + * Current Usage. + * + * @return the current collection usage. + */ + public long getCollectionUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.COLLECTION); + } + + /** + * Max Quota. + * + * @return the user quota. + */ + public long getUserQuota() { + return this.getMaxQuotaHeader(Constants.Quota.USER); + } + + /** + * Current Usage. + * + * @return the current user usage. + */ + public long getUserUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.USER); + } + + /** + * Max Quota. + * + * @return the permission quota. + */ + public long getPermissionQuota() { + return this.getMaxQuotaHeader(Constants.Quota.PERMISSION); + } + + /** + * Current Usage. + * + * @return the current permission usage. + */ + public long getPermissionUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.PERMISSION); + } + + /** + * Max Quota. + * + * @return the collection size quota. + */ + public long getCollectionSizeQuota() { + return this.getMaxQuotaHeader(Constants.Quota.COLLECTION_SIZE); + } + + /** + * Current Usage. + * + * @return the collection size usage. + */ + public long getCollectionSizeUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.COLLECTION_SIZE); + } + + /** + * Max Quota. + * + * @return the document quota. + */ + public long getDocumentQuota() { + return this.getMaxQuotaHeader(Constants.Quota.DOCUMENTS_SIZE); + } + + /** + * Current Usage. + * + * @return the document usage. + */ + public long getDocumentUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.DOCUMENTS_SIZE); + } + + /** + * Max document count quota. + * + * @return the document count quota. + */ + public long getDocumentCountQuota() { + return this.getMaxQuotaHeader(Constants.Quota.DOCUMENTS_COUNT); + } + + /** + * Current document count usage. + * + * @return the document count usage. + */ + public long getDocumentCountUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.DOCUMENTS_COUNT); + } + + /** + * Max Quota. + * + * @return the stored procedures quota. + */ + public long getStoredProceduresQuota() { + return this.getMaxQuotaHeader(Constants.Quota.STORED_PROCEDURE); + } + + /** + * Current Usage. + * + * @return the current stored procedures usage. + */ + public long getStoredProceduresUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.STORED_PROCEDURE); + } + + /** + * Max Quota. + * + * @return the triggers quota. + */ + public long getTriggersQuota() { + return this.getMaxQuotaHeader(Constants.Quota.TRIGGER); + } + + /** + * Current Usage. + * + * @return the current triggers usage. + */ + public long getTriggersUsage() { + return this.getCurrentQuotaHeader(Constants.Quota.TRIGGER); + } + + /** + * Max Quota. + * + * @return the user defined functions quota. + */ + public long getUserDefinedFunctionsQuota() { + return this.getMaxQuotaHeader(Constants.Quota.USER_DEFINED_FUNCTION); + } + + /** + * Current Usage. + * + * @return the current user defined functions usage. + */ + public long getUserDefinedFunctionsUsage() { + return this.getCurrentQuotaHeader( + Constants.Quota.USER_DEFINED_FUNCTION); + } + + /** + * Gets the Activity ID for the request. + * + * @return the activity id. + */ + public String getActivityId() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.ACTIVITY_ID); + } + + /** + * Gets the token used for managing client's consistency requirements. + * + * @return the session token. + */ + public String getSessionToken() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + + /** + * Gets the HTTP status code associated with the response. + * + * @return the status code. + */ + public int getStatusCode() { + return this.response.getStatusCode(); + } + + /** + * Gets the maximum size limit for this entity (in megabytes (MB) for server resources and in count for master + * resources). + * + * @return the max resource quota. + */ + public String getMaxResourceQuota() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.MAX_RESOURCE_QUOTA); + } + + /** + * Gets the current size of this entity (in megabytes (MB) for server resources and in count for master resources) + * + * @return the current resource quota usage. + */ + public String getCurrentResourceQuotaUsage() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.CURRENT_RESOURCE_QUOTA_USAGE); + } + + /** + * Gets the resource for the request. + * + * @return the resource. + */ + public T getResource() { + return this.resource; + } + + /** + * Gets the number of index paths (terms) generated by the operation. + * + * @return the request charge. + */ + public double getRequestCharge() { + String value = this.getResponseHeaders().get(HttpConstants.HttpHeaders.REQUEST_CHARGE); + if (StringUtils.isEmpty(value)) { + return 0; + } + return Double.valueOf(value); + } + + /** + * Gets the headers associated with the response. + * + * @return the response headers. + */ + public Map getResponseHeaders() { + return this.response.getResponseHeaders(); + } + + /** + * Gets the progress of an index transformation, if one is underway. + * + * @return the progress of an index transformation. + */ + public long getIndexTransformationProgress() { + String value = this.getResponseHeaders().get(HttpConstants.HttpHeaders.INDEX_TRANSFORMATION_PROGRESS); + if (StringUtils.isEmpty(value)) { + return -1; + } + return Long.parseLong(value); + } + + /** + * Gets the progress of lazy indexing. + * + * @return the progress of lazy indexing. + */ + public long getLazyIndexingProgress() { + String value = this.getResponseHeaders().get(HttpConstants.HttpHeaders.LAZY_INDEXING_PROGRESS); + if (StringUtils.isEmpty(value)) { + return -1; + } + return Long.parseLong(value); + } + + /** + * Gets the request diagnostic statistics for the current request to Azure Cosmos DB service. + * + * @return request diagnostic statistics for the current request to Azure Cosmos DB service. + */ + public CosmosResponseDiagnostics getCosmosResponseDiagnostics() { + return this.response.getCosmosResponseRequestDiagnosticStatistics(); + } + + /** + * Gets the end-to-end request latency for the current request to Azure Cosmos DB service. + * + * @return end-to-end request latency for the current request to Azure Cosmos DB service. + */ + public Duration getRequestLatency() { + CosmosResponseDiagnostics cosmosResponseDiagnostics = this.response.getCosmosResponseRequestDiagnosticStatistics(); + if (cosmosResponseDiagnostics == null) { + return Duration.ZERO; + } + + return cosmosResponseDiagnostics.requestLatency(); + } + + /** + * Gets the diagnostics information for the current request to Azure Cosmos DB service. + * + * @return diagnostics information for the current request to Azure Cosmos DB service. + */ + public String getCosmosResponseDiagnosticString() { + CosmosResponseDiagnostics cosmosResponseRequestDiagnosticStatistics = this.response.getCosmosResponseRequestDiagnosticStatistics(); + if (cosmosResponseRequestDiagnosticStatistics == null) { + return StringUtils.EMPTY; + } + return cosmosResponseRequestDiagnosticStatistics.toString(); + } + + long getCurrentQuotaHeader(String headerName) { + if (this.usageHeaders.size() == 0 && + !StringUtils.isEmpty(this.getMaxResourceQuota()) && + !StringUtils.isEmpty(this.getCurrentResourceQuotaUsage())) { + this.populateQuotaHeader(this.getMaxResourceQuota(), this.getCurrentResourceQuotaUsage()); + } + + if (this.usageHeaders.containsKey(headerName)) { + return this.usageHeaders.get(headerName); + } + + return 0; + } + + long getMaxQuotaHeader(String headerName) { + if (this.quotaHeaders.size() == 0 && + !StringUtils.isEmpty(this.getMaxResourceQuota()) && + !this.getCurrentResourceQuotaUsage().isEmpty()) { + this.populateQuotaHeader(this.getMaxResourceQuota(), this.getCurrentResourceQuotaUsage()); + } + + if (this.quotaHeaders.containsKey(headerName)) { + return this.quotaHeaders.get(headerName); + } + + return 0; + } + + private void populateQuotaHeader(String headerMaxQuota, String headerCurrentUsage) { + String[] headerMaxQuotaWords = headerMaxQuota.split(Constants.Quota.DELIMITER_CHARS, -1); + String[] headerCurrentUsageWords = headerCurrentUsage.split(Constants.Quota.DELIMITER_CHARS, -1); + + assert (headerMaxQuotaWords.length == headerCurrentUsageWords.length); + + for (int i = 0; i < headerMaxQuotaWords.length; ++i) { + if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.DATABASE)) { + this.quotaHeaders.put(Constants.Quota.DATABASE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.DATABASE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.COLLECTION)) { + this.quotaHeaders.put(Constants.Quota.COLLECTION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.COLLECTION, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.USER)) { + this.quotaHeaders.put(Constants.Quota.USER, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.USER, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.PERMISSION)) { + this.quotaHeaders.put(Constants.Quota.PERMISSION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.PERMISSION, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.COLLECTION_SIZE)) { + this.quotaHeaders.put(Constants.Quota.COLLECTION_SIZE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.COLLECTION_SIZE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.DOCUMENTS_SIZE)) { + this.quotaHeaders.put(Constants.Quota.DOCUMENTS_SIZE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.DOCUMENTS_SIZE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.STORED_PROCEDURE)) { + this.quotaHeaders.put(Constants.Quota.STORED_PROCEDURE, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.STORED_PROCEDURE, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.TRIGGER)) { + this.quotaHeaders.put(Constants.Quota.TRIGGER, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.TRIGGER, Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.USER_DEFINED_FUNCTION)) { + this.quotaHeaders.put(Constants.Quota.USER_DEFINED_FUNCTION, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.USER_DEFINED_FUNCTION, + Long.valueOf(headerCurrentUsageWords[i + 1])); + } else if (headerMaxQuotaWords[i].equalsIgnoreCase(Constants.Quota.DOCUMENTS_COUNT)) { + this.quotaHeaders.put(Constants.Quota.DOCUMENTS_COUNT, Long.valueOf(headerMaxQuotaWords[i + 1])); + this.usageHeaders.put(Constants.Quota.DOCUMENTS_COUNT, + Long.valueOf(headerCurrentUsageWords[i + 1])); + } + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceThrottleRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceThrottleRetryPolicy.java new file mode 100644 index 0000000000000..47ae481869fb2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceThrottleRetryPolicy.java @@ -0,0 +1,133 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class ResourceThrottleRetryPolicy implements IDocumentClientRetryPolicy{ + + private final static Logger logger = LoggerFactory.getLogger(ResourceThrottleRetryPolicy.class); + + private final static int DefaultMaxWaitTimeInSeconds = 60; + private final static int DefaultRetryInSeconds = 5; + private final int backoffDelayFactor; + private final int maxAttemptCount; + private final Duration maxWaitTime; + + // TODO: is this thread safe? + // should we make this atomic int? + private int currentAttemptCount; + private Duration cumulativeRetryDelay; + + public ResourceThrottleRetryPolicy(int maxAttemptCount, int maxWaitTimeInSeconds) { + this(maxAttemptCount, maxWaitTimeInSeconds, 1); + } + + public ResourceThrottleRetryPolicy(int maxAttemptCount) { + this(maxAttemptCount, DefaultMaxWaitTimeInSeconds, 1); + } + + public ResourceThrottleRetryPolicy(int maxAttemptCount, int maxWaitTimeInSeconds, int backoffDelayFactor) { + Utils.checkStateOrThrow(maxWaitTimeInSeconds < Integer.MAX_VALUE / 1000, "maxWaitTimeInSeconds", "maxWaitTimeInSeconds must be less than " + Integer.MAX_VALUE / 1000); + + this.maxAttemptCount = maxAttemptCount; + this.backoffDelayFactor = backoffDelayFactor; + this.maxWaitTime = Duration.ofSeconds(maxWaitTimeInSeconds); + this.currentAttemptCount = 0; + this.cumulativeRetryDelay = Duration.ZERO; + } + + @Override + public Mono shouldRetry(Exception exception) { + Duration retryDelay = Duration.ZERO; + + if (this.currentAttemptCount < this.maxAttemptCount && + (retryDelay = checkIfRetryNeeded(exception)) != null) { + this.currentAttemptCount++; + logger.warn( + "Operation will be retried after {} milliseconds. Current attempt {}, Cumulative delay {}", + retryDelay.toMillis(), + this.currentAttemptCount, + this.cumulativeRetryDelay, + exception); + return Mono.just(ShouldRetryResult.retryAfter(retryDelay)); + } else { + logger.debug( + "Operation will NOT be retried. Current attempt {}", + this.currentAttemptCount, + exception); + return Mono.just(ShouldRetryResult.noRetry()); + } + } + + @Override + public void onBeforeSendRequest(RxDocumentServiceRequest request) { + // no op + } + + // if retry not needed reaturns null + /// + /// Returns True if the given exception is retriable + /// + /// Exception to examine + /// retryDelay + /// True if the exception is retriable; False otherwise + private Duration checkIfRetryNeeded(Exception exception) { + Duration retryDelay = Duration.ZERO; + + CosmosClientException dce = Utils.as(exception, CosmosClientException.class); + + if (dce != null){ + + if (Exceptions.isStatusCode(dce, HttpConstants.StatusCodes.TOO_MANY_REQUESTS)) { + retryDelay = Duration.ofMillis(dce.retryAfterInMilliseconds()); + if (this.backoffDelayFactor > 1) { + retryDelay = Duration.ofNanos(retryDelay.toNanos() * this.backoffDelayFactor); + } + + if (retryDelay.toMillis() < this.maxWaitTime.toMillis() && + this.maxWaitTime.toMillis() >= (this.cumulativeRetryDelay = retryDelay.plus(this.cumulativeRetryDelay)).toMillis()) + { + if (retryDelay == Duration.ZERO){ + // we should never reach here as BE should turn non-zero of retryDelay + logger.trace("Received retryDelay of 0 with Http 429", exception); + retryDelay = Duration.ofSeconds(DefaultRetryInSeconds); + } + + return retryDelay; + } + } + } + // if retry not needed returns null + return null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceTokenAuthorizationHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceTokenAuthorizationHelper.java new file mode 100644 index 0000000000000..4a37d5b7574fa --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceTokenAuthorizationHelper.java @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.routing.PartitionKeyAndResourceTokenPair; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Map; + +/** + * This class is used internally and act as a helper in authorization of + * resources from permission feed and its supporting method. + * + */ +public class ResourceTokenAuthorizationHelper { + + private static final Logger logger = LoggerFactory.getLogger(ResourceTokenAuthorizationHelper.class); + + /** + * This method help to differentiate between master key and resource token + * + * @param token + * ResourceToken provide + * @return Whether given token is resource token or not + */ + public static boolean isResourceToken(String token) { + int typeSeparatorPosition = token.indexOf('&'); + if (typeSeparatorPosition == -1) { + return false; + } + String authType = token.substring(0, typeSeparatorPosition); + int typeKeyValueSepartorPosition = authType.indexOf('='); + if (typeKeyValueSepartorPosition == -1 || !authType.substring(0, typeKeyValueSepartorPosition) + .equalsIgnoreCase(Constants.Properties.AUTH_SCHEMA_TYPE)) { + return false; + } + + String authTypeValue = authType.substring(typeKeyValueSepartorPosition + 1); + + return authTypeValue.equalsIgnoreCase(Constants.Properties.RESOURCE_TOKEN); + } + + /** + * Private method which will fetch resource token based on partition key and + * resource address . + * + * @param resourceTokensMap + * @param resourceAddress + * @param partitionKey + * @return + */ + private static String getResourceToken(Map> resourceTokensMap, + String resourceAddress, + PartitionKeyInternal partitionKey) { + List partitionKeyAndResourceTokenPairs = resourceTokensMap + .get(resourceAddress); + if (partitionKeyAndResourceTokenPairs != null) { + for (PartitionKeyAndResourceTokenPair pair : partitionKeyAndResourceTokenPairs) { + if (pair.getPartitionKey().contains(partitionKey) || partitionKey.equals(PartitionKeyInternal.Empty)) { + return pair.getResourceToken(); + } + } + } + + return null; + } + + /** + * This method will try to fetch the resource token to access the resource . + * + * @param resourceTokensMap + * It contains the resource link and its partition key and resource + * token list . + * @param headers + * Header information of the request . + * @param resourceAddress + * Resource full name or ID . + * @param requestVerb + * The verb . + */ + public static String getAuthorizationTokenUsingResourceTokens( + Map> resourceTokensMap, + String requestVerb, + String resourceAddress, + Map headers) { + PartitionKeyInternal partitionKey = PartitionKeyInternal.Empty; + String partitionKeyString = headers.get(HttpConstants.HttpHeaders.PARTITION_KEY); + if (partitionKeyString != null) { + partitionKey = PartitionKeyInternal.fromJsonString(partitionKeyString); + } + + if (PathsHelper.isNameBased(resourceAddress)) { + String resourceToken = null; + for (int index = 2; index < ResourceId.MAX_PATH_FRAGMENT; index = index + 2) { + String resourceParent = PathsHelper.getParentByIndex(resourceAddress, index); + if (resourceParent == null) + break; + resourceToken = getResourceToken(resourceTokensMap, resourceParent, partitionKey); + if (resourceToken != null) + break; + } + + // Get or Head for collection can be done with any child token + if (resourceToken == null && PathsHelper.getCollectionPath(resourceAddress).equalsIgnoreCase(resourceAddress) + && HttpConstants.HttpMethods.GET.equalsIgnoreCase(requestVerb) + || HttpConstants.HttpMethods.HEAD.equalsIgnoreCase(requestVerb)) { + String resourceAddressWithSlash = resourceAddress.endsWith(Constants.Properties.PATH_SEPARATOR) + ? resourceAddress + : resourceAddress + Constants.Properties.PATH_SEPARATOR; + for (String key : resourceTokensMap.keySet()) { + if (key.startsWith(resourceAddressWithSlash)) { + if (resourceTokensMap.get(key) != null && resourceTokensMap.get(key).size() > 0) + resourceToken = resourceTokensMap.get(key).get(0).getResourceToken(); + break; + } + } + } + + if (resourceToken == null) { + throw new IllegalArgumentException(RMResources.ResourceTokenNotFound); + } + + logger.debug("returned token for resourceAddress [{}] = [{}]", + resourceAddress, resourceToken); + return resourceToken; + } else { + String resourceToken = null; + ResourceId resourceId = ResourceId.parse(resourceAddress); + if (resourceId.getAttachment() != 0 || resourceId.getPermission() != 0 + || resourceId.getStoredProcedure() != 0 || resourceId.getTrigger() != 0 + || resourceId.getUserDefinedFunction() != 0) { + // Use the leaf ID - attachment/permission/sproc/trigger/udf + resourceToken = getResourceToken(resourceTokensMap, resourceAddress, partitionKey); + } + + if (resourceToken == null && (resourceId.getAttachment() != 0 || resourceId.getDocument() != 0)) { + // Use DocumentID for attachment/document + resourceToken = getResourceToken(resourceTokensMap, resourceId.getDocumentId().toString(), + partitionKey); + } + + if (resourceToken == null && (resourceId.getAttachment() != 0 || resourceId.getDocument() != 0 + || resourceId.getStoredProcedure() != 0 || resourceId.getTrigger() != 0 + || resourceId.getUserDefinedFunction() != 0 || resourceId.getDocumentCollection() != 0)) { + // Use CollectionID for attachment/document/sproc/trigger/udf/collection + resourceToken = getResourceToken(resourceTokensMap, resourceId.getDocumentCollectionId().toString(), + partitionKey); + } + + if (resourceToken == null && (resourceId.getPermission() != 0 || resourceId.getUser() != 0)) { + // Use UserID for permission/user + resourceToken = getResourceToken(resourceTokensMap, resourceId.getUserId().toString(), partitionKey); + } + + if (resourceToken == null) { + // Use DatabaseId if all else fail + resourceToken = getResourceToken(resourceTokensMap, resourceId.getDatabaseId().toString(), + partitionKey); + } + // Get or Head for collection can be done with any child token + if (resourceToken == null && resourceId.getDocumentCollection() != 0 + && (HttpConstants.HttpMethods.GET.equalsIgnoreCase(requestVerb) + || HttpConstants.HttpMethods.HEAD.equalsIgnoreCase(requestVerb))) { + for (String key : resourceTokensMap.keySet()) { + ResourceId tokenRid; + Pair pair = ResourceId.tryParse(key); + ResourceId test1= pair.getRight().getDocumentCollectionId(); + boolean test = test1.equals(resourceId); + if (!PathsHelper.isNameBased(key) && pair.getLeft() + && pair.getRight().getDocumentCollectionId().equals(resourceId)) { + if (resourceTokensMap.get(key) != null && resourceTokensMap.get(key).size() > 0) { + resourceToken = resourceTokensMap.get(key).get(0).getResourceToken(); + } + } + } + + } + + if (resourceToken == null) { + throw new IllegalArgumentException(RMResources.ResourceTokenNotFound); + } + + logger.debug("returned token for resourceAddress [{}] = [{}]", + resourceAddress, resourceToken); + return resourceToken; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceType.java new file mode 100644 index 0000000000000..fb0a92940e91d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/ResourceType.java @@ -0,0 +1,124 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Resource types in the Azure Cosmos DB database service. + */ +public enum ResourceType { + + // REQUIRED: This enum must be kept in sync with the ResourceType enum in backend native + + Unknown(-1), + Attachment(3), + BatchApply(112), + DocumentCollection(1), + ComputeGatewayCharges(131), + Conflict(107), + Database(0), + DatabaseAccount(118), + Document(2), + Index(104), + IndexBookmark(105), + IndexSize(106), + LargeInvalid(100), + LogStoreLogs(126), + MasterPartition(120), + Module(9), + ModuleCommand(103), + Offer(113), + PartitionKeyRange(125), + PartitionSetInformation(114), + Permission(5), + PreviousImage(128), + Progress(6), + Record(108), + Replica(7), + RestoreMetadata(127), + RidRange(130), + Schema(124), + SchemaContainer(123), + ServerPartition(121), + SmallMaxInvalid(10), + StoredProcedure(109), + Timestamp(117), + Tombstone(8), + Topology(122), + Trigger(110), + User(4), + UserDefinedFunction(111), + UserDefinedType(133), + VectorClock(129), + XPReplicatorAddress(115), + + // These names make it unclear what they map to in ResourceType. + Address(-5), + Key(-2), + Media(-3), + ServiceFabricService(-4); + + final private int value; + + ResourceType(int value) { + this.value = value; + } + + public int value() { + return this.value; + } + + public boolean isCollectionChild() { + return this == ResourceType.Document || + this == ResourceType.Attachment || + this == ResourceType.Conflict || + this == ResourceType.Schema || + this.isScript(); + } + + public boolean isMasterResource() { + return this == ResourceType.Offer || + this == ResourceType.Database || + this == ResourceType.User || + this == ResourceType.Permission || + this == ResourceType.Topology || + this == ResourceType.PartitionKeyRange || + this == ResourceType.DocumentCollection; + } + + /// + /// Resources for which this method returns true, are spread between multiple partitions + /// + public boolean isPartitioned() { + return this == ResourceType.Document || + this == ResourceType.Attachment || + this == ResourceType.Conflict; + } + + public boolean isScript() { + return this == ResourceType.UserDefinedFunction || + this == ResourceType.Trigger || + this == ResourceType.StoredProcedure; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryPolicy.java new file mode 100644 index 0000000000000..713e9068eeda9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryPolicy.java @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.RetryOptions; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * Represents the retry policy configuration associated with a DocumentClient instance. + */ +public class RetryPolicy implements IRetryPolicyFactory { + private final GlobalEndpointManager globalEndpointManager; + private final boolean enableEndpointDiscovery; + private final RetryOptions retryOptions; + + public RetryPolicy(GlobalEndpointManager globalEndpointManager, ConnectionPolicy connectionPolicy) { + this.enableEndpointDiscovery = connectionPolicy.enableEndpointDiscovery(); + this.globalEndpointManager = globalEndpointManager; + this.retryOptions = connectionPolicy.retryOptions(); + } + + @Override + public IDocumentClientRetryPolicy getRequestPolicy() { + ClientRetryPolicy clientRetryPolicy = new ClientRetryPolicy(this.globalEndpointManager, + this.enableEndpointDiscovery, this.retryOptions); + + return clientRetryPolicy; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryUtils.java new file mode 100644 index 0000000000000..4e50ed2a6f5dc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RetryUtils.java @@ -0,0 +1,142 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import org.apache.commons.lang3.time.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class RetryUtils { + private final static Logger logger = LoggerFactory.getLogger(BackoffRetryUtility.class); + + static Function, Flux> toRetryWhenFunc(IRetryPolicy policy) { + return throwableFlux -> throwableFlux.flatMap(t -> { + Exception e = Utils.as(t, Exception.class); + if (e == null) { + return Flux.error(t); + } + Flux shouldRetryResultFlux = policy.shouldRetry(e).flux(); + return shouldRetryResultFlux.flatMap(s -> { + + if (s.backOffTime != null) { + return Mono.delay(Duration.ofMillis(s.backOffTime.toMillis())).flux(); + } else if (s.exception != null) { + return Flux.error(s.exception); + } else { + // NoRetry return original failure + return Flux.error(t); + } + }); + }); + } + + /** + * This method will be called after getting error on callbackMethod , and then keep trying between + * callbackMethod and inBackoffAlternateCallbackMethod until success or as stated in + * retry policy. + * @param callbackMethod The callbackMethod + * @param retryPolicy Retry policy + * @param inBackoffAlternateCallbackMethod The inBackoffAlternateCallbackMethod + * @param minBackoffForInBackoffCallback Minimum backoff for InBackoffCallbackMethod + * @return + */ + + public static Function> toRetryWithAlternateFunc(Function, Mono> callbackMethod, IRetryPolicy retryPolicy, Function, Mono> inBackoffAlternateCallbackMethod, Duration minBackoffForInBackoffCallback) { + return throwable -> { + Exception e = Utils.as(throwable, Exception.class); + if (e == null) { + return Mono.error(throwable); + } + + Flux shouldRetryResultFlux = retryPolicy.shouldRetry(e).flux(); + return shouldRetryResultFlux.flatMap(shouldRetryResult -> { + if (!shouldRetryResult.shouldRetry) { + if(shouldRetryResult.exception == null) { + return Mono.error(e); + } else { + return Mono.error(shouldRetryResult.exception); + } + } + + if (inBackoffAlternateCallbackMethod != null + && shouldRetryResult.backOffTime.compareTo(minBackoffForInBackoffCallback) > 0) { + StopWatch stopwatch = new StopWatch(); + startStopWatch(stopwatch); + return inBackoffAlternateCallbackMethod.apply(shouldRetryResult.policyArg) + .onErrorResume(recurrsiveWithAlternateFunc(callbackMethod, retryPolicy, + inBackoffAlternateCallbackMethod, shouldRetryResult, stopwatch, + minBackoffForInBackoffCallback)); + } else { + return recurrsiveFunc(callbackMethod, retryPolicy, inBackoffAlternateCallbackMethod, + shouldRetryResult, minBackoffForInBackoffCallback) + .delaySubscription(Duration.ofMillis(shouldRetryResult.backOffTime.toMillis())); + } + }).single(); + }; + } + + private static Mono recurrsiveFunc(Function, Mono> callbackMethod, IRetryPolicy retryPolicy, Function, Mono> inBackoffAlternateCallbackMethod, IRetryPolicy.ShouldRetryResult shouldRetryResult, Duration minBackoffForInBackoffCallback) { + return callbackMethod.apply(shouldRetryResult.policyArg).onErrorResume(toRetryWithAlternateFunc( + callbackMethod, retryPolicy, inBackoffAlternateCallbackMethod, minBackoffForInBackoffCallback)); + } + + private static Function> recurrsiveWithAlternateFunc(Function, Mono> callbackMethod, IRetryPolicy retryPolicy, Function, Mono> inBackoffAlternateCallbackMethod, IRetryPolicy.ShouldRetryResult shouldRetryResult, StopWatch stopwatch, Duration minBackoffForInBackoffCallback) { + return throwable -> { + Exception e = Utils.as(throwable, Exception.class); + if (e == null) { + return Mono.error(throwable); + } + + stopStopWatch(stopwatch); + logger.info("Failed inBackoffAlternateCallback with {}, proceeding with retry. Time taken: {}ms", + e.toString(), stopwatch.getTime()); + Duration backoffTime = shouldRetryResult.backOffTime.toMillis() > stopwatch.getTime() + ? Duration.ofMillis(shouldRetryResult.backOffTime.toMillis() - stopwatch.getTime()) + : Duration.ZERO; + return recurrsiveFunc(callbackMethod, retryPolicy, inBackoffAlternateCallbackMethod, shouldRetryResult, + minBackoffForInBackoffCallback) + .delaySubscription(Flux.just(0L).delayElements(Duration.ofMillis(backoffTime.toMillis()))); + }; + } + + private static void stopStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.stop(); + } + } + + private static void startStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.start(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeConstants.java new file mode 100644 index 0000000000000..8d68ec3abec07 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeConstants.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Used internally. Runtime constants in the Azure Cosmos DB database service Java SDK. + */ +public class RuntimeConstants { + public static class MediaTypes { + // http://www.iana.org/assignments/media-types/media-types.xhtml + public static final String ANY = "*/*"; + public static final String IMAGE_JPEG = "image/jpeg"; + public static final String IMAGE_PNG = "image/png"; + public static final String JAVA_SCRIPT = "application/x-javascript"; + public static final String JSON = "application/json"; + public static final String OCTET_STREAM = "application/octet-stream"; + public static final String QUERY_JSON = "application/query+json"; + public static final String SQL = "application/sql"; + public static final String TEXT_HTML = "text/html"; + public static final String TEXT_PLAIN = "text/plain"; + public static final String XML = "application/xml"; + } + + public static class ProtocolScheme { + public static final String HTTPS = "https"; + public static final String TCP = "rntbd"; + } + + static class Separators { + static final char[] Url = new char[] {'/'}; + static final char[] Quote = new char[] {'\''}; + static final char[] DomainId = new char[] {'-'}; + static final char[] Query = new char[] {'?', '&', '='}; + static final char[] Parenthesis = new char[] {'(', ')'}; + static final char[] UserAgentHeader = new char[] {'(', ')', ';', ','}; + + + //Note that the accept header separator here is ideally comma. Semicolon is used for separators within individual + //header for now cloud moe does not recognize such accept header hence we allow both semicolon or comma separated + //accept header + static final char[] Header = new char[] {';', ','}; + static final char[] CookieSeparator = new char[] {';'}; + static final char[] CookieValueSeparator = new char[] {'='}; + static final char[] PPMUserToken = new char[] {':'}; + static final char[] Identifier = new char[] {'-'}; + static final char[] Host = new char[] {'.'}; + static final char[] Version = new char[] {','}; + static final char[] Pair = new char[] {';'}; + static final char[] ETag = new char[] {'#'}; + static final char[] MemberQuery = new char[] {'+'}; + + static final String HeaderEncodingBegin = "=?"; + static final String HeaderEncodingEnd = "?="; + static final String HeaderEncodingSeparator = "?"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeExecutionTimes.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeExecutionTimes.java new file mode 100644 index 0000000000000..3d5153cc53772 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RuntimeExecutionTimes.java @@ -0,0 +1,159 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import java.time.Duration; +import java.util.Collection; +import java.util.HashMap; + +/** + * Query runtime execution times in the Azure Cosmos DB service. + */ +public final class RuntimeExecutionTimes { + + static final RuntimeExecutionTimes ZERO = new RuntimeExecutionTimes(Duration.ZERO, Duration.ZERO, Duration.ZERO); + + private final Duration queryEngineExecutionTime; + private final Duration systemFunctionExecutionTime; + private final Duration userDefinedFunctionExecutionTime; + + /** + * @param queryEngineExecutionTime + * @param systemFunctionExecutionTime + * @param userDefinedFunctionExecutionTime + */ + RuntimeExecutionTimes(Duration queryEngineExecutionTime, Duration systemFunctionExecutionTime, + Duration userDefinedFunctionExecutionTime) { + super(); + + if (queryEngineExecutionTime == null) { + throw new NullPointerException("queryEngineExecutionTime"); + } + + if (systemFunctionExecutionTime == null) { + throw new NullPointerException("systemFunctionExecutionTime"); + } + + if (userDefinedFunctionExecutionTime == null) { + throw new NullPointerException("userDefinedFunctionExecutionTime"); + } + + this.queryEngineExecutionTime = queryEngineExecutionTime; + this.systemFunctionExecutionTime = systemFunctionExecutionTime; + this.userDefinedFunctionExecutionTime = userDefinedFunctionExecutionTime; + } + + /** + * @return the queryEngineExecutionTime + */ + public Duration getQueryEngineExecutionTime() { + return queryEngineExecutionTime; + } + + /** + * @return the systemFunctionExecutionTime + */ + public Duration getSystemFunctionExecutionTime() { + return systemFunctionExecutionTime; + } + + /** + * @return the userDefinedFunctionExecutionTime + */ + public Duration getUserDefinedFunctionExecutionTime() { + return userDefinedFunctionExecutionTime; + } + + static RuntimeExecutionTimes createFromCollection( + Collection runtimeExecutionTimesCollection) { + if (runtimeExecutionTimesCollection == null) { + throw new NullPointerException("runtimeExecutionTimesCollection"); + } + + Duration queryEngineExecutionTime = Duration.ZERO; + Duration systemFunctionExecutionTime = Duration.ZERO; + Duration userDefinedFunctionExecutionTime = Duration.ZERO; + + for (RuntimeExecutionTimes runtimeExecutionTime : runtimeExecutionTimesCollection) { + queryEngineExecutionTime = queryEngineExecutionTime.plus(runtimeExecutionTime.queryEngineExecutionTime); + systemFunctionExecutionTime = systemFunctionExecutionTime.plus(runtimeExecutionTime.systemFunctionExecutionTime); + userDefinedFunctionExecutionTime = userDefinedFunctionExecutionTime.plus(runtimeExecutionTime.userDefinedFunctionExecutionTime); + } + + return new RuntimeExecutionTimes( + queryEngineExecutionTime, + systemFunctionExecutionTime, + userDefinedFunctionExecutionTime); + } + + static RuntimeExecutionTimes createFromDelimitedString(String delimitedString) { + HashMap metrics = QueryMetricsUtils.parseDelimitedString(delimitedString); + + Duration vmExecutionTime = QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.VMExecutionTimeInMs); + Duration indexLookupTime = QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.IndexLookupTimeInMs); + Duration documentLoadTime = QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.DocumentLoadTimeInMs); + Duration documentWriteTime = QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.DocumentWriteTimeInMs); + + return new RuntimeExecutionTimes( + vmExecutionTime.minus(indexLookupTime).minus(documentLoadTime).minus(documentWriteTime), + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.SystemFunctionExecuteTimeInMs), + QueryMetricsUtils.durationFromMetrics(metrics, QueryMetricsConstants.UserDefinedFunctionExecutionTimeInMs)); + } + + String toDelimitedString() { + String formatString = "%s=%2f;%s=%2f"; + + // queryEngineExecutionTime is not emitted, since it is calculated as + // vmExecutionTime - indexLookupTime - documentLoadTime - documentWriteTime + return String.format( + formatString, + QueryMetricsConstants.SystemFunctionExecuteTimeInMs, + this.systemFunctionExecutionTime.toMillis(), + QueryMetricsConstants.UserDefinedFunctionExecutionTimeInMs, + this.userDefinedFunctionExecutionTime.toMillis()); + } + + String toTextString(int indentLevel) { + if (indentLevel == Integer.MAX_VALUE) { + throw new NumberFormatException("indentLevel input must be less than Int32.MaxValue"); + } + StringBuilder stringBuilder = new StringBuilder(); + + QueryMetricsUtils.appendHeaderToStringBuilder(stringBuilder, QueryMetricsConstants.RuntimeExecutionTimesText, + indentLevel); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.TotalExecutionTimeText, this.queryEngineExecutionTime.toNanos(), + indentLevel + 1); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.SystemFunctionExecuteTimeText, + this.systemFunctionExecutionTime.toNanos(), indentLevel + 1); + + QueryMetricsUtils.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsConstants.UserDefinedFunctionExecutionTimeText, + this.userDefinedFunctionExecutionTime.toNanos(), indentLevel + 1); + + return stringBuilder.toString(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentClientImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentClientImpl.java new file mode 100644 index 0000000000000..a8445b91fd5bb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentClientImpl.java @@ -0,0 +1,2778 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.AccessConditionType; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosResourceType; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.TokenResolver; +import com.azure.data.cosmos.internal.caches.RxClientCollectionCache; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.caches.RxPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.directconnectivity.GatewayServiceConfigurationReader; +import com.azure.data.cosmos.internal.directconnectivity.GlobalAddressResolver; +import com.azure.data.cosmos.internal.directconnectivity.ServerStoreModel; +import com.azure.data.cosmos.internal.directconnectivity.StoreClient; +import com.azure.data.cosmos.internal.directconnectivity.StoreClientFactory; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpClientConfig; +import com.azure.data.cosmos.internal.query.DocumentQueryExecutionContextFactory; +import com.azure.data.cosmos.internal.query.IDocumentQueryClient; +import com.azure.data.cosmos.internal.query.IDocumentQueryExecutionContext; +import com.azure.data.cosmos.internal.query.Paginator; +import com.azure.data.cosmos.internal.routing.PartitionKeyAndResourceTokenPair; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static com.azure.data.cosmos.BridgeInternal.documentFromObject; +import static com.azure.data.cosmos.BridgeInternal.getAltLink; +import static com.azure.data.cosmos.BridgeInternal.toDatabaseAccount; +import static com.azure.data.cosmos.BridgeInternal.toFeedResponsePage; +import static com.azure.data.cosmos.BridgeInternal.toResourceResponse; +import static com.azure.data.cosmos.BridgeInternal.toStoredProcedureResponse; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class RxDocumentClientImpl implements AsyncDocumentClient, IAuthorizationTokenProvider { + private final static ObjectMapper mapper = Utils.getSimpleObjectMapper(); + private final Logger logger = LoggerFactory.getLogger(RxDocumentClientImpl.class); + private final String masterKeyOrResourceToken; + private final URI serviceEndpoint; + private final ConnectionPolicy connectionPolicy; + private final ConsistencyLevel consistencyLevel; + private final BaseAuthorizationTokenProvider authorizationTokenProvider; + private final UserAgentContainer userAgentContainer; + private final boolean hasAuthKeyResourceToken; + private final Configs configs; + private TokenResolver tokenResolver; + private SessionContainer sessionContainer; + private String firstResourceTokenFromPermissionFeed = StringUtils.EMPTY; + private RxClientCollectionCache collectionCache; + private RxStoreModel gatewayProxy; + private RxStoreModel storeModel; + private GlobalAddressResolver addressResolver; + private RxPartitionKeyRangeCache partitionKeyRangeCache; + private Map> resourceTokensMap; + + // RetryPolicy retries a request when it encounters session unavailable (see ClientRetryPolicy). + // Once it exhausts all write regions it clears the session container, then it uses RxClientCollectionCache + // to resolves the request's collection name. If it differs from the session container's resource id it + // explains the session unavailable exception: somebody removed and recreated the collection. In this + // case we retry once again (with empty session token) otherwise we return the error to the client + // (see RenameCollectionAwareClientRetryPolicy) + private IRetryPolicyFactory resetSessionTokenRetryPolicy; + /** + * Compatibility mode: Allows to specify compatibility mode used by client when + * making query requests. Should be removed when application/sql is no longer + * supported. + */ + private final QueryCompatibilityMode queryCompatibilityMode = QueryCompatibilityMode.Default; + private final HttpClient reactorHttpClient; + private final GlobalEndpointManager globalEndpointManager; + private final RetryPolicy retryPolicy; + private volatile boolean useMultipleWriteLocations; + + // creator of TransportClient is responsible for disposing it. + private StoreClientFactory storeClientFactory; + + private GatewayServiceConfigurationReader gatewayConfigurationReader; + + public RxDocumentClientImpl(URI serviceEndpoint, + String masterKeyOrResourceToken, + List permissionFeed, + ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, + Configs configs, + TokenResolver tokenResolver) { + this(serviceEndpoint, masterKeyOrResourceToken, permissionFeed, connectionPolicy, consistencyLevel, configs); + this.tokenResolver = tokenResolver; + } + + public RxDocumentClientImpl(URI serviceEndpoint, + String masterKeyOrResourceToken, + List permissionFeed, + ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, + Configs configs) { + this(serviceEndpoint, masterKeyOrResourceToken, connectionPolicy, consistencyLevel, configs); + if (permissionFeed != null && permissionFeed.size() > 0) { + this.resourceTokensMap = new HashMap<>(); + for (Permission permission : permissionFeed) { + String[] segments = StringUtils.split(permission.getResourceLink(), + Constants.Properties.PATH_SEPARATOR.charAt(0)); + + if (segments.length <= 0) { + throw new IllegalArgumentException("resourceLink"); + } + + List partitionKeyAndResourceTokenPairs = null; + PathInfo pathInfo = new PathInfo(false, StringUtils.EMPTY, StringUtils.EMPTY, false); + if (!PathsHelper.tryParsePathSegments(permission.getResourceLink(), pathInfo, null)) { + throw new IllegalArgumentException(permission.getResourceLink()); + } + + partitionKeyAndResourceTokenPairs = resourceTokensMap.get(pathInfo.resourceIdOrFullName); + if (partitionKeyAndResourceTokenPairs == null) { + partitionKeyAndResourceTokenPairs = new ArrayList<>(); + this.resourceTokensMap.put(pathInfo.resourceIdOrFullName, partitionKeyAndResourceTokenPairs); + } + + PartitionKey partitionKey = permission.getResourcePartitionKey(); + partitionKeyAndResourceTokenPairs.add(new PartitionKeyAndResourceTokenPair( + partitionKey != null ? partitionKey.getInternalPartitionKey() : PartitionKeyInternal.Empty, + permission.getToken())); + logger.debug("Initializing resource token map , with map key [{}] , partition key [{}] and resource token", + pathInfo.resourceIdOrFullName, partitionKey != null ? partitionKey.toString() : null, permission.getToken()); + + } + + if(this.resourceTokensMap.isEmpty()) { + throw new IllegalArgumentException("permissionFeed"); + } + + String firstToken = permissionFeed.get(0).getToken(); + if(ResourceTokenAuthorizationHelper.isResourceToken(firstToken)) { + this.firstResourceTokenFromPermissionFeed = firstToken; + } + } + } + + public RxDocumentClientImpl(URI serviceEndpoint, String masterKeyOrResourceToken, ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, Configs configs) { + + logger.info( + "Initializing DocumentClient with" + + " serviceEndpoint [{}], connectionPolicy [{}], consistencyLevel [{}], directModeProtocol [{}]", + serviceEndpoint, connectionPolicy, consistencyLevel, configs.getProtocol()); + + this.configs = configs; + this.masterKeyOrResourceToken = masterKeyOrResourceToken; + this.serviceEndpoint = serviceEndpoint; + + if (masterKeyOrResourceToken != null && ResourceTokenAuthorizationHelper.isResourceToken(masterKeyOrResourceToken)) { + this.authorizationTokenProvider = null; + hasAuthKeyResourceToken = true; + } else if(masterKeyOrResourceToken != null && !ResourceTokenAuthorizationHelper.isResourceToken(masterKeyOrResourceToken)){ + hasAuthKeyResourceToken = false; + this.authorizationTokenProvider = new BaseAuthorizationTokenProvider(this.masterKeyOrResourceToken); + } else { + hasAuthKeyResourceToken = false; + this.authorizationTokenProvider = null; + } + + if (connectionPolicy != null) { + this.connectionPolicy = connectionPolicy; + } else { + this.connectionPolicy = new ConnectionPolicy(); + } + + this.sessionContainer = new SessionContainer(this.serviceEndpoint.getHost()); + this.consistencyLevel = consistencyLevel; + + this.userAgentContainer = new UserAgentContainer(); + + String userAgentSuffix = this.connectionPolicy.userAgentSuffix(); + if (userAgentSuffix != null && userAgentSuffix.length() > 0) { + userAgentContainer.setSuffix(userAgentSuffix); + } + + this.reactorHttpClient = httpClient(); + this.globalEndpointManager = new GlobalEndpointManager(asDatabaseAccountManagerInternal(), this.connectionPolicy, /**/configs); + this.retryPolicy = new RetryPolicy(this.globalEndpointManager, this.connectionPolicy); + this.resetSessionTokenRetryPolicy = retryPolicy; + } + + private void initializeGatewayConfigurationReader() { + String resourceToken; + if(this.tokenResolver != null) { + resourceToken = this.tokenResolver.getAuthorizationToken("GET", "", CosmosResourceType.System, null); + } else if(!this.hasAuthKeyResourceToken && this.authorizationTokenProvider == null) { + resourceToken = this.firstResourceTokenFromPermissionFeed; + } else { + assert this.masterKeyOrResourceToken != null; + resourceToken = this.masterKeyOrResourceToken; + } + + this.gatewayConfigurationReader = new GatewayServiceConfigurationReader(this.serviceEndpoint, + this.hasAuthKeyResourceToken, + resourceToken, + this.connectionPolicy, + this.authorizationTokenProvider, + this.reactorHttpClient); + + DatabaseAccount databaseAccount = this.gatewayConfigurationReader.initializeReaderAsync().block(); + this.useMultipleWriteLocations = this.connectionPolicy.usingMultipleWriteLocations() && BridgeInternal.isEnableMultipleWriteLocations(databaseAccount); + + // TODO: add support for openAsync + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/332589 + this.globalEndpointManager.refreshLocationAsync(databaseAccount).block(); + } + + public void init() { + + // TODO: add support for openAsync + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/332589 + this.gatewayProxy = createRxGatewayProxy(this.sessionContainer, + this.consistencyLevel, + this.queryCompatibilityMode, + this.userAgentContainer, + this.globalEndpointManager, + this.reactorHttpClient); + this.globalEndpointManager.init(); + this.initializeGatewayConfigurationReader(); + + this.collectionCache = new RxClientCollectionCache(this.sessionContainer, this.gatewayProxy, this, this.retryPolicy); + this.resetSessionTokenRetryPolicy = new ResetSessionTokenRetryPolicyFactory(this.sessionContainer, this.collectionCache, this.retryPolicy); + + this.partitionKeyRangeCache = new RxPartitionKeyRangeCache(RxDocumentClientImpl.this, + collectionCache); + + if (this.connectionPolicy.connectionMode() == ConnectionMode.GATEWAY) { + this.storeModel = this.gatewayProxy; + } else { + this.initializeDirectConnectivity(); + } + } + + private void initializeDirectConnectivity() { + + this.storeClientFactory = new StoreClientFactory( + this.configs, + this.connectionPolicy.requestTimeoutInMillis() / 1000, + // this.maxConcurrentConnectionOpenRequests, + 0, + this.userAgentContainer + ); + + this.addressResolver = new GlobalAddressResolver( + this.reactorHttpClient, + this.globalEndpointManager, + this.configs.getProtocol(), + this, + this.collectionCache, + this.partitionKeyRangeCache, + userAgentContainer, + // TODO: GATEWAY Configuration Reader + // this.gatewayConfigurationReader, + null, + this.connectionPolicy); + + this.createStoreModel(true); + } + + DatabaseAccountManagerInternal asDatabaseAccountManagerInternal() { + return new DatabaseAccountManagerInternal() { + + @Override + public URI getServiceEndpoint() { + return RxDocumentClientImpl.this.getServiceEndpoint(); + } + + @Override + public Flux getDatabaseAccountFromEndpoint(URI endpoint) { + logger.info("Getting database account endpoint from {}", endpoint); + return RxDocumentClientImpl.this.getDatabaseAccountFromEndpoint(endpoint); + } + + @Override + public ConnectionPolicy getConnectionPolicy() { + return RxDocumentClientImpl.this.getConnectionPolicy(); + } + }; + } + + RxGatewayStoreModel createRxGatewayProxy(ISessionContainer sessionContainer, + ConsistencyLevel consistencyLevel, + QueryCompatibilityMode queryCompatibilityMode, + UserAgentContainer userAgentContainer, + GlobalEndpointManager globalEndpointManager, + HttpClient httpClient) { + return new RxGatewayStoreModel(sessionContainer, + consistencyLevel, + queryCompatibilityMode, + userAgentContainer, + globalEndpointManager, + httpClient); + } + + private HttpClient httpClient() { + + HttpClientConfig httpClientConfig = new HttpClientConfig(this.configs) + .withMaxIdleConnectionTimeoutInMillis(this.connectionPolicy.idleConnectionTimeoutInMillis()) + .withPoolSize(this.connectionPolicy.maxPoolSize()) + .withHttpProxy(this.connectionPolicy.proxy()) + .withRequestTimeoutInMillis(this.connectionPolicy.requestTimeoutInMillis()); + + return HttpClient.createFixed(httpClientConfig); + } + + private void createStoreModel(boolean subscribeRntbdStatus) { + // EnableReadRequestsFallback, if not explicitly set on the connection policy, + // is false if the account's consistency is bounded staleness, + // and true otherwise. + + StoreClient storeClient = this.storeClientFactory.createStoreClient( + this.addressResolver, + this.sessionContainer, + this.gatewayConfigurationReader, + this, + false + ); + + this.storeModel = new ServerStoreModel(storeClient); + } + + + @Override + public URI getServiceEndpoint() { + return this.serviceEndpoint; + } + + @Override + public URI getWriteEndpoint() { + return globalEndpointManager.getWriteEndpoints().stream().findFirst().map(loc -> { + try { + return loc.toURI(); + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } + }).orElse(null); + } + + @Override + public URI getReadEndpoint() { + return globalEndpointManager.getReadEndpoints().stream().findFirst().map(loc -> { + try { + return loc.toURI(); + } catch (URISyntaxException e) { + throw new IllegalStateException(e); + } + }).orElse(null); + } + + @Override + public ConnectionPolicy getConnectionPolicy() { + return this.connectionPolicy; + } + + @Override + public Flux> createDatabase(Database database, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> createDatabaseInternal(database, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> createDatabaseInternal(Database database, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + + if (database == null) { + throw new IllegalArgumentException("Database"); + } + + logger.debug("Creating a Database. id: [{}]", database.id()); + validateResource(database); + + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Create, + ResourceType.Database, Paths.DATABASES_ROOT, database, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.create(request).map(response -> toResourceResponse(response, Database.class)); + } catch (Exception e) { + logger.debug("Failure in creating a database. due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deleteDatabase(String databaseLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteDatabaseInternal(databaseLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteDatabaseInternal(String databaseLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + + logger.debug("Deleting a Database. databaseLink: [{}]", databaseLink); + String path = Utils.joinPath(databaseLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.Database, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, Database.class)); + } catch (Exception e) { + logger.debug("Failure in deleting a database. due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readDatabase(String databaseLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readDatabaseInternal(databaseLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readDatabaseInternal(String databaseLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + + logger.debug("Reading a Database. databaseLink: [{}]", databaseLink); + String path = Utils.joinPath(databaseLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Database, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(response -> toResourceResponse(response, Database.class)); + } catch (Exception e) { + logger.debug("Failure in reading a database. due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readDatabases(FeedOptions options) { + return readFeed(options, ResourceType.Database, Database.class, Paths.DATABASES_ROOT); + } + + private String parentResourceLinkToQueryLink(String parentResouceLink, ResourceType resourceTypeEnum) { + switch (resourceTypeEnum) { + case Database: + return Paths.DATABASES_ROOT; + + case DocumentCollection: + return Utils.joinPath(parentResouceLink, Paths.COLLECTIONS_PATH_SEGMENT); + + case Document: + return Utils.joinPath(parentResouceLink, Paths.DOCUMENTS_PATH_SEGMENT); + + case Offer: + return Paths.OFFERS_ROOT; + + case User: + return Utils.joinPath(parentResouceLink, Paths.USERS_PATH_SEGMENT); + + case Permission: + return Utils.joinPath(parentResouceLink, Paths.PERMISSIONS_PATH_SEGMENT); + + case Attachment: + return Utils.joinPath(parentResouceLink, Paths.ATTACHMENTS_PATH_SEGMENT); + + case StoredProcedure: + return Utils.joinPath(parentResouceLink, Paths.STORED_PROCEDURES_PATH_SEGMENT); + + case Trigger: + return Utils.joinPath(parentResouceLink, Paths.TRIGGERS_PATH_SEGMENT); + + case UserDefinedFunction: + return Utils.joinPath(parentResouceLink, Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT); + + default: + throw new IllegalArgumentException("resource type not supported"); + } + } + + private Flux> createQuery( + String parentResourceLink, + SqlQuerySpec sqlQuery, + FeedOptions options, + Class klass, + ResourceType resourceTypeEnum) { + + String queryResourceLink = parentResourceLinkToQueryLink(parentResourceLink, resourceTypeEnum); + + UUID activityId = Utils.randomUUID(); + IDocumentQueryClient queryClient = DocumentQueryClientImpl(RxDocumentClientImpl.this); + Flux> executionContext = + DocumentQueryExecutionContextFactory.createDocumentQueryExecutionContextAsync(queryClient, resourceTypeEnum, klass, sqlQuery , options, queryResourceLink, false, activityId); + return executionContext.flatMap(IDocumentQueryExecutionContext::executeAsync); + } + + + @Override + public Flux> queryDatabases(String query, FeedOptions options) { + return queryDatabases(new SqlQuerySpec(query), options); + } + + + @Override + public Flux> queryDatabases(SqlQuerySpec querySpec, FeedOptions options) { + return createQuery(Paths.DATABASES_ROOT, querySpec, options, Database.class, ResourceType.Database); + } + + @Override + public Flux> createCollection(String databaseLink, + DocumentCollection collection, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> this.createCollectionInternal(databaseLink, collection, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> createCollectionInternal(String databaseLink, + DocumentCollection collection, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + if (collection == null) { + throw new IllegalArgumentException("collection"); + } + + logger.debug("Creating a Collection. databaseLink: [{}], Collection id: [{}]", databaseLink, + collection.id()); + validateResource(collection); + + String path = Utils.joinPath(databaseLink, Paths.COLLECTIONS_PATH_SEGMENT); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Create, + ResourceType.DocumentCollection, path, collection, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.create(request).map(response -> toResourceResponse(response, DocumentCollection.class)) + .doOnNext(resourceResponse -> { + // set the session token + this.sessionContainer.setSessionToken(resourceResponse.getResource().resourceId(), + getAltLink(resourceResponse.getResource()), + resourceResponse.getResponseHeaders()); + }); + } catch (Exception e) { + logger.debug("Failure in creating a collection. due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> replaceCollection(DocumentCollection collection, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceCollectionInternal(collection, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> replaceCollectionInternal(DocumentCollection collection, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (collection == null) { + throw new IllegalArgumentException("collection"); + } + + logger.debug("Replacing a Collection. id: [{}]", collection.id()); + validateResource(collection); + + String path = Utils.joinPath(collection.selfLink(), null); + Map requestHeaders = this.getRequestHeaders(options); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.DocumentCollection, path, collection, requestHeaders, options); + + // TODO: .Net has some logic for updating session token which we don't + // have here + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, DocumentCollection.class)) + .doOnNext(resourceResponse -> { + if (resourceResponse.getResource() != null) { + // set the session token + this.sessionContainer.setSessionToken(resourceResponse.getResource().resourceId(), + getAltLink(resourceResponse.getResource()), + resourceResponse.getResponseHeaders()); + } + }); + + } catch (Exception e) { + logger.debug("Failure in replacing a collection. due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deleteCollection(String collectionLink, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteCollectionInternal(collectionLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteCollectionInternal(String collectionLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + logger.debug("Deleting a Collection. collectionLink: [{}]", collectionLink); + String path = Utils.joinPath(collectionLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.DocumentCollection, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, DocumentCollection.class)); + + } catch (Exception e) { + logger.debug("Failure in deleting a collection, due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + private Flux delete(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.DELETE); + return getStoreProxy(request).processMessage(request); + } + + private Flux read(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.GET); + return getStoreProxy(request).processMessage(request); + } + + Flux readFeed(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.GET); + return gatewayProxy.processMessage(request); + } + + private Flux query(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.POST); + return this.getStoreProxy(request).processMessage(request) + .map(response -> { + this.captureSessionToken(request, response); + return response; + } + ); + } + + @Override + public Flux> readCollection(String collectionLink, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readCollectionInternal(collectionLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readCollectionInternal(String collectionLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + logger.debug("Reading a Collection. collectionLink: [{}]", collectionLink); + String path = Utils.joinPath(collectionLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.DocumentCollection, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(response -> toResourceResponse(response, DocumentCollection.class)); + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in reading a collection, due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readCollections(String databaseLink, FeedOptions options) { + + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + + return readFeed(options, ResourceType.DocumentCollection, DocumentCollection.class, + Utils.joinPath(databaseLink, Paths.COLLECTIONS_PATH_SEGMENT)); + } + + @Override + public Flux> queryCollections(String databaseLink, String query, + FeedOptions options) { + return createQuery(databaseLink, new SqlQuerySpec(query), options, DocumentCollection.class, ResourceType.DocumentCollection); + } + + @Override + public Flux> queryCollections(String databaseLink, + SqlQuerySpec querySpec, FeedOptions options) { + return createQuery(databaseLink, querySpec, options, DocumentCollection.class, ResourceType.DocumentCollection); + } + + private static String serializeProcedureParams(Object[] objectArray) { + String[] stringArray = new String[objectArray.length]; + + for (int i = 0; i < objectArray.length; ++i) { + Object object = objectArray[i]; + if (object instanceof JsonSerializable) { + stringArray[i] = ((JsonSerializable) object).toJson(); + } else { + + // POJO, ObjectNode, number, STRING or Boolean + try { + stringArray[i] = mapper.writeValueAsString(object); + } catch (IOException e) { + throw new IllegalArgumentException("Can't serialize the object into the json string", e); + } + } + } + + return String.format("[%s]", StringUtils.join(stringArray, ",")); + } + + private static void validateResource(Resource resource) { + if (!StringUtils.isEmpty(resource.id())) { + if (resource.id().indexOf('/') != -1 || resource.id().indexOf('\\') != -1 || + resource.id().indexOf('?') != -1 || resource.id().indexOf('#') != -1) { + throw new IllegalArgumentException("Id contains illegal chars."); + } + + if (resource.id().endsWith(" ")) { + throw new IllegalArgumentException("Id ends with a space."); + } + } + } + + private Map getRequestHeaders(RequestOptions options) { + Map headers = new HashMap<>(); + + if (this.useMultipleWriteLocations) { + headers.put(HttpConstants.HttpHeaders.ALLOW_TENTATIVE_WRITES, Boolean.TRUE.toString()); + } + + if (consistencyLevel != null) { + headers.put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, consistencyLevel.toString()); + } + + if (options == null) { + return headers; + } + + Map customOptions = options.getHeaders(); + if (customOptions != null) { + headers.putAll(customOptions); + } + + if (options.getAccessCondition() != null) { + if (options.getAccessCondition().type() == AccessConditionType.IF_MATCH) { + headers.put(HttpConstants.HttpHeaders.IF_MATCH, options.getAccessCondition().condition()); + } else { + headers.put(HttpConstants.HttpHeaders.IF_NONE_MATCH, options.getAccessCondition().condition()); + } + } + + if (options.getConsistencyLevel() != null) { + headers.put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, options.getConsistencyLevel().toString()); + } + + if (options.getIndexingDirective() != null) { + headers.put(HttpConstants.HttpHeaders.INDEXING_DIRECTIVE, options.getIndexingDirective().toString()); + } + + if (options.getPostTriggerInclude() != null && options.getPostTriggerInclude().size() > 0) { + String postTriggerInclude = StringUtils.join(options.getPostTriggerInclude(), ","); + headers.put(HttpConstants.HttpHeaders.POST_TRIGGER_INCLUDE, postTriggerInclude); + } + + if (options.getPreTriggerInclude() != null && options.getPreTriggerInclude().size() > 0) { + String preTriggerInclude = StringUtils.join(options.getPreTriggerInclude(), ","); + headers.put(HttpConstants.HttpHeaders.PRE_TRIGGER_INCLUDE, preTriggerInclude); + } + + if (!Strings.isNullOrEmpty(options.getSessionToken())) { + headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, options.getSessionToken()); + } + + if (options.getResourceTokenExpirySeconds() != null) { + headers.put(HttpConstants.HttpHeaders.RESOURCE_TOKEN_EXPIRY, + String.valueOf(options.getResourceTokenExpirySeconds())); + } + + if (options.getOfferThroughput() != null && options.getOfferThroughput() >= 0) { + headers.put(HttpConstants.HttpHeaders.OFFER_THROUGHPUT, options.getOfferThroughput().toString()); + } else if (options.getOfferType() != null) { + headers.put(HttpConstants.HttpHeaders.OFFER_TYPE, options.getOfferType()); + } + + if (options.isPopulateQuotaInfo()) { + headers.put(HttpConstants.HttpHeaders.POPULATE_QUOTA_INFO, String.valueOf(true)); + } + + if (options.isScriptLoggingEnabled()) { + headers.put(HttpConstants.HttpHeaders.SCRIPT_ENABLE_LOGGING, String.valueOf(true)); + } + + return headers; + } + + private Mono addPartitionKeyInformation(RxDocumentServiceRequest request, Document document, + RequestOptions options) { + + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + return collectionObs + .map(collection -> { + addPartitionKeyInformation(request, document, options, collection); + return request; + }); + } + + private Mono addPartitionKeyInformation(RxDocumentServiceRequest request, Document document, RequestOptions options, + Mono collectionObs) { + + return collectionObs.map(collection -> { + addPartitionKeyInformation(request, document, options, collection); + return request; + }); + } + + private void addPartitionKeyInformation(RxDocumentServiceRequest request, Document document, RequestOptions options, + DocumentCollection collection) { + PartitionKeyDefinition partitionKeyDefinition = collection.getPartitionKey(); + + PartitionKeyInternal partitionKeyInternal = null; + if (options != null && options.getPartitionKey() != null && options.getPartitionKey().equals(PartitionKey.None)){ + partitionKeyInternal = BridgeInternal.getNonePartitionKey(partitionKeyDefinition); + } else if (options != null && options.getPartitionKey() != null) { + partitionKeyInternal = options.getPartitionKey().getInternalPartitionKey(); + } else if (partitionKeyDefinition == null || partitionKeyDefinition.paths().size() == 0) { + // For backward compatibility, if collection doesn't have partition key defined, we assume all documents + // have empty value for it and user doesn't need to specify it explicitly. + partitionKeyInternal = PartitionKeyInternal.getEmpty(); + } else if (document != null) { + partitionKeyInternal = extractPartitionKeyValueFromDocument(document, partitionKeyDefinition); + } else { + throw new UnsupportedOperationException("PartitionKey value must be supplied for this operation."); + } + + request.getHeaders().put(HttpConstants.HttpHeaders.PARTITION_KEY, escapeNonAscii(partitionKeyInternal.toJson())); + } + + private static String escapeNonAscii(String partitionKeyJson) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < partitionKeyJson.length(); i++) { + int val = partitionKeyJson.charAt(i); + if (val > 127) { + sb.append("\\u").append(String.format("%04X", val)); + } else { + sb.append(partitionKeyJson.charAt(i)); + } + } + return sb.toString(); + } + + private static PartitionKeyInternal extractPartitionKeyValueFromDocument( + Document document, + PartitionKeyDefinition partitionKeyDefinition) { + if (partitionKeyDefinition != null) { + String path = partitionKeyDefinition.paths().iterator().next(); + List parts = PathParser.getPathParts(path); + if (parts.size() >= 1) { + Object value = document.getObjectByPath(parts); + if (value == null || value.getClass() == ObjectNode.class) { + value = BridgeInternal.getNonePartitionKey(partitionKeyDefinition); + } + + if (value instanceof PartitionKeyInternal) { + return (PartitionKeyInternal) value; + } else { + return PartitionKeyInternal.fromObjectArray(Collections.singletonList(value), false); + } + } + } + + return null; + } + + private Mono getCreateDocumentRequest(String documentCollectionLink, Object document, + RequestOptions options, boolean disableAutomaticIdGeneration, OperationType operationType) { + + if (StringUtils.isEmpty(documentCollectionLink)) { + throw new IllegalArgumentException("documentCollectionLink"); + } + if (document == null) { + throw new IllegalArgumentException("document"); + } + + Document typedDocument = documentFromObject(document, mapper); + + RxDocumentClientImpl.validateResource(typedDocument); + + if (typedDocument.id() == null && !disableAutomaticIdGeneration) { + // We are supposed to use GUID. Basically UUID is the same as GUID + // when represented as a string. + typedDocument.id(UUID.randomUUID().toString()); + } + String path = Utils.joinPath(documentCollectionLink, Paths.DOCUMENTS_PATH_SEGMENT); + Map requestHeaders = this.getRequestHeaders(options); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, ResourceType.Document, path, + typedDocument, requestHeaders, options); + + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + return addPartitionKeyInformation(request, typedDocument, options, collectionObs); + } + + private void populateHeaders(RxDocumentServiceRequest request, String httpMethod) { + if (this.masterKeyOrResourceToken != null) { + request.getHeaders().put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + } + + if (this.masterKeyOrResourceToken != null || this.resourceTokensMap != null || this.tokenResolver != null) { + String resourceName = request.getResourceAddress(); + + String authorization = this.getUserAuthorizationToken( + resourceName, request.getResourceType(), httpMethod, request.getHeaders(), + AuthorizationTokenType.PrimaryMasterKey, request.properties); + try { + authorization = URLEncoder.encode(authorization, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("Failed to encode authtoken.", e); + } + request.getHeaders().put(HttpConstants.HttpHeaders.AUTHORIZATION, authorization); + } + + if ((HttpConstants.HttpMethods.POST.equals(httpMethod) || HttpConstants.HttpMethods.PUT.equals(httpMethod)) + && !request.getHeaders().containsKey(HttpConstants.HttpHeaders.CONTENT_TYPE)) { + request.getHeaders().put(HttpConstants.HttpHeaders.CONTENT_TYPE, RuntimeConstants.MediaTypes.JSON); + } + + if (!request.getHeaders().containsKey(HttpConstants.HttpHeaders.ACCEPT)) { + request.getHeaders().put(HttpConstants.HttpHeaders.ACCEPT, RuntimeConstants.MediaTypes.JSON); + } + } + + @Override + public String getUserAuthorizationToken(String resourceName, + ResourceType resourceType, + String requestVerb, + Map headers, + AuthorizationTokenType tokenType, + Map properties) { + + if (this.tokenResolver != null) { + return this.tokenResolver.getAuthorizationToken(requestVerb, resourceName, this.resolveCosmosResourceType(resourceType), + properties != null ? Collections.unmodifiableMap(properties) : null); + } else if (masterKeyOrResourceToken != null && !hasAuthKeyResourceToken) { + return this.authorizationTokenProvider.generateKeyAuthorizationSignature(requestVerb, resourceName, + resourceType, headers); + } else if (masterKeyOrResourceToken != null && hasAuthKeyResourceToken && resourceTokensMap == null) { + return masterKeyOrResourceToken; + } else { + assert resourceTokensMap != null; + if(resourceType.equals(ResourceType.DatabaseAccount)) { + return this.firstResourceTokenFromPermissionFeed; + } + return ResourceTokenAuthorizationHelper.getAuthorizationTokenUsingResourceTokens(resourceTokensMap, requestVerb, resourceName, headers); + } + } + + private CosmosResourceType resolveCosmosResourceType(ResourceType resourceType) { + try { + return CosmosResourceType.valueOf(resourceType.toString()); + } catch (IllegalArgumentException e) { + return CosmosResourceType.System; + } + } + + void captureSessionToken(RxDocumentServiceRequest request, RxDocumentServiceResponse response) { + this.sessionContainer.setSessionToken(request, response.getResponseHeaders()); + } + + private Flux create(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.POST); + RxStoreModel storeProxy = this.getStoreProxy(request); + return storeProxy.processMessage(request); + } + + private Flux upsert(RxDocumentServiceRequest request) { + + populateHeaders(request, HttpConstants.HttpMethods.POST); + Map headers = request.getHeaders(); + // headers can never be null, since it will be initialized even when no + // request options are specified, + // hence using assertion here instead of exception, being in the private + // method + assert (headers != null); + headers.put(HttpConstants.HttpHeaders.IS_UPSERT, "true"); + + return getStoreProxy(request).processMessage(request) + .map(response -> { + this.captureSessionToken(request, response); + return response; + } + ); + } + + private Flux replace(RxDocumentServiceRequest request) { + populateHeaders(request, HttpConstants.HttpMethods.PUT); + return getStoreProxy(request).processMessage(request); + } + + @Override + public Flux> createDocument(String collectionLink, Object document, + RequestOptions options, boolean disableAutomaticIdGeneration) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + if (options == null || options.getPartitionKey() == null) { + requestRetryPolicy = new PartitionKeyMismatchRetryPolicy(collectionCache, requestRetryPolicy, collectionLink, options); + } + + IDocumentClientRetryPolicy finalRetryPolicyInstance = requestRetryPolicy; + return ObservableHelper.inlineIfPossibleAsObs(() -> createDocumentInternal(collectionLink, document, options, disableAutomaticIdGeneration, finalRetryPolicyInstance), requestRetryPolicy); + } + + private Flux> createDocumentInternal(String collectionLink, Object document, + RequestOptions options, final boolean disableAutomaticIdGeneration, IDocumentClientRetryPolicy requestRetryPolicy) { + + try { + logger.debug("Creating a Document. collectionLink: [{}]", collectionLink); + + Mono requestObs = getCreateDocumentRequest(collectionLink, document, + options, disableAutomaticIdGeneration, OperationType.Create); + + Flux responseObservable = requestObs + .flux() + .flatMap(req -> { + if (requestRetryPolicy != null) { + requestRetryPolicy.onBeforeSendRequest(req); + } + + return create(req); + }); + + return responseObservable + .map(serviceResponse -> toResourceResponse(serviceResponse, Document.class)); + + } catch (Exception e) { + logger.debug("Failure in creating a document due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertDocument(String collectionLink, Object document, + RequestOptions options, boolean disableAutomaticIdGeneration) { + + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + if (options == null || options.getPartitionKey() == null) { + requestRetryPolicy = new PartitionKeyMismatchRetryPolicy(collectionCache, requestRetryPolicy, collectionLink, options); + } + IDocumentClientRetryPolicy finalRetryPolicyInstance = requestRetryPolicy; + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertDocumentInternal(collectionLink, document, options, disableAutomaticIdGeneration, finalRetryPolicyInstance), requestRetryPolicy); + } + + private Flux> upsertDocumentInternal(String collectionLink, Object document, + RequestOptions options, boolean disableAutomaticIdGeneration, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + logger.debug("Upserting a Document. collectionLink: [{}]", collectionLink); + + Flux reqObs = getCreateDocumentRequest(collectionLink, document, + options, disableAutomaticIdGeneration, OperationType.Upsert).flux(); + + Flux responseObservable = reqObs.flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(req); + } + + return upsert(req);}); + return responseObservable + .map(serviceResponse -> toResourceResponse(serviceResponse, Document.class)); + + } catch (Exception e) { + logger.debug("Failure in upserting a document due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> replaceDocument(String documentLink, Object document, + RequestOptions options) { + + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + if (options == null || options.getPartitionKey() == null) { + String collectionLink = Utils.getCollectionName(documentLink); + requestRetryPolicy = new PartitionKeyMismatchRetryPolicy(collectionCache, requestRetryPolicy, collectionLink, options); + } + IDocumentClientRetryPolicy finalRequestRetryPolicy = requestRetryPolicy; + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceDocumentInternal(documentLink, document, options, finalRequestRetryPolicy), requestRetryPolicy); + } + + private Flux> replaceDocumentInternal(String documentLink, Object document, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(documentLink)) { + throw new IllegalArgumentException("documentLink"); + } + + if (document == null) { + throw new IllegalArgumentException("document"); + } + + Document typedDocument = documentFromObject(document, mapper); + + return this.replaceDocumentInternal(documentLink, typedDocument, options, retryPolicyInstance); + + } catch (Exception e) { + logger.debug("Failure in replacing a document due to [{}]", e.getMessage()); + return Flux.error(e); + } + } + + @Override + public Flux> replaceDocument(Document document, RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + if (options == null || options.getPartitionKey() == null) { + String collectionLink = document.selfLink(); + requestRetryPolicy = new PartitionKeyMismatchRetryPolicy(collectionCache, requestRetryPolicy, collectionLink, options); + } + IDocumentClientRetryPolicy finalRequestRetryPolicy = requestRetryPolicy; + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceDocumentInternal(document, options, finalRequestRetryPolicy), requestRetryPolicy); + } + + private Flux> replaceDocumentInternal(Document document, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (document == null) { + throw new IllegalArgumentException("document"); + } + + return this.replaceDocumentInternal(document.selfLink(), document, options, retryPolicyInstance); + + } catch (Exception e) { + logger.debug("Failure in replacing a database due to [{}]", e.getMessage()); + return Flux.error(e); + } + } + + private Flux> replaceDocumentInternal(String documentLink, Document document, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + if (document == null) { + throw new IllegalArgumentException("document"); + } + + logger.debug("Replacing a Document. documentLink: [{}]", documentLink); + final String path = Utils.joinPath(documentLink, null); + final Map requestHeaders = getRequestHeaders(options); + final RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.Document, path, document, requestHeaders, options); + + validateResource(document); + + Mono collectionObs = collectionCache.resolveCollectionAsync(request); + Mono requestObs = addPartitionKeyInformation(request, document, options, collectionObs); + + return requestObs.flux().flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return replace(request) + .map(resp -> toResourceResponse(resp, Document.class));} ); + } + + @Override + public Flux> deleteDocument(String documentLink, RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteDocumentInternal(documentLink, options, requestRetryPolicy), requestRetryPolicy); + } + + private Flux> deleteDocumentInternal(String documentLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(documentLink)) { + throw new IllegalArgumentException("documentLink"); + } + + logger.debug("Deleting a Document. documentLink: [{}]", documentLink); + String path = Utils.joinPath(documentLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.Document, path, requestHeaders, options); + + Mono collectionObs = collectionCache.resolveCollectionAsync(request); + + Mono requestObs = addPartitionKeyInformation(request, null, options, collectionObs); + + return requestObs.flux().flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(req); + } + return this.delete(req) + .map(serviceResponse -> toResourceResponse(serviceResponse, Document.class));}); + + } catch (Exception e) { + logger.debug("Failure in deleting a document due to [{}]", e.getMessage()); + return Flux.error(e); + } + } + + @Override + public Flux> readDocument(String documentLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readDocumentInternal(documentLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readDocumentInternal(String documentLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(documentLink)) { + throw new IllegalArgumentException("documentLink"); + } + + logger.debug("Reading a Document. documentLink: [{}]", documentLink); + String path = Utils.joinPath(documentLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Document, path, requestHeaders, options); + + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + + Mono requestObs = addPartitionKeyInformation(request, null, options, collectionObs); + + return requestObs.flux().flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(serviceResponse -> toResourceResponse(serviceResponse, Document.class)); + }); + + } catch (Exception e) { + logger.debug("Failure in reading a document due to [{}]", e.getMessage()); + return Flux.error(e); + } + } + + @Override + public Flux> readDocuments(String collectionLink, FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return queryDocuments(collectionLink, "SELECT * FROM r", options); + } + + @Override + public Flux> queryDocuments(String collectionLink, String query, + FeedOptions options) { + return queryDocuments(collectionLink, new SqlQuerySpec(query), options); + } + + private IDocumentQueryClient DocumentQueryClientImpl(RxDocumentClientImpl rxDocumentClientImpl) { + + return new IDocumentQueryClient () { + + @Override + public RxCollectionCache getCollectionCache() { + return RxDocumentClientImpl.this.collectionCache; + } + + @Override + public RxPartitionKeyRangeCache getPartitionKeyRangeCache() { + return RxDocumentClientImpl.this.partitionKeyRangeCache; + } + + @Override + public IRetryPolicyFactory getResetSessionTokenRetryPolicy() { + return RxDocumentClientImpl.this.resetSessionTokenRetryPolicy; + } + + @Override + public ConsistencyLevel getDefaultConsistencyLevelAsync() { + return RxDocumentClientImpl.this.gatewayConfigurationReader.getDefaultConsistencyLevel(); + } + + @Override + public ConsistencyLevel getDesiredConsistencyLevelAsync() { + // TODO Auto-generated method stub + return RxDocumentClientImpl.this.consistencyLevel; + } + + @Override + public Mono executeQueryAsync(RxDocumentServiceRequest request) { + return RxDocumentClientImpl.this.query(request).single(); + } + + @Override + public QueryCompatibilityMode getQueryCompatibilityMode() { + // TODO Auto-generated method stub + return QueryCompatibilityMode.Default; + } + + @Override + public Mono readFeedAsync(RxDocumentServiceRequest request) { + // TODO Auto-generated method stub + return null; + } + }; + } + + @Override + public Flux> queryDocuments(String collectionLink, SqlQuerySpec querySpec, + FeedOptions options) { + return createQuery(collectionLink, querySpec, options, Document.class, ResourceType.Document); + } + + @Override + public Flux> queryDocumentChangeFeed(final String collectionLink, + final ChangeFeedOptions changeFeedOptions) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + ChangeFeedQueryImpl changeFeedQueryImpl = new ChangeFeedQueryImpl(this, ResourceType.Document, + Document.class, collectionLink, changeFeedOptions); + + return changeFeedQueryImpl.executeAsync(); + } + + @Override + public Flux> readPartitionKeyRanges(final String collectionLink, + FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return readFeed(options, ResourceType.PartitionKeyRange, PartitionKeyRange.class, + Utils.joinPath(collectionLink, Paths.PARTITION_KEY_RANGES_PATH_SEGMENT)); + } + + private RxDocumentServiceRequest getStoredProcedureRequest(String collectionLink, StoredProcedure storedProcedure, + RequestOptions options, OperationType operationType) { + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + if (storedProcedure == null) { + throw new IllegalArgumentException("storedProcedure"); + } + + validateResource(storedProcedure); + + String path = Utils.joinPath(collectionLink, Paths.STORED_PROCEDURES_PATH_SEGMENT); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, ResourceType.StoredProcedure, + path, storedProcedure, requestHeaders, options); + + return request; + } + + private RxDocumentServiceRequest getUserDefinedFunctionRequest(String collectionLink, UserDefinedFunction udf, + RequestOptions options, OperationType operationType) { + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + if (udf == null) { + throw new IllegalArgumentException("udf"); + } + + validateResource(udf); + + String path = Utils.joinPath(collectionLink, Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, + ResourceType.UserDefinedFunction, path, udf, requestHeaders, options); + + return request; + } + + @Override + public Flux> createStoredProcedure(String collectionLink, + StoredProcedure storedProcedure, RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> createStoredProcedureInternal(collectionLink, storedProcedure, options, requestRetryPolicy), requestRetryPolicy); + } + + private Flux> createStoredProcedureInternal(String collectionLink, + StoredProcedure storedProcedure, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + + logger.debug("Creating a StoredProcedure. collectionLink: [{}], storedProcedure id [{}]", + collectionLink, storedProcedure.id()); + RxDocumentServiceRequest request = getStoredProcedureRequest(collectionLink, storedProcedure, options, + OperationType.Create); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.create(request).map(response -> toResourceResponse(response, StoredProcedure.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in creating a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertStoredProcedure(String collectionLink, + StoredProcedure storedProcedure, RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertStoredProcedureInternal(collectionLink, storedProcedure, options, requestRetryPolicy), requestRetryPolicy); + } + + private Flux> upsertStoredProcedureInternal(String collectionLink, + StoredProcedure storedProcedure, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + + logger.debug("Upserting a StoredProcedure. collectionLink: [{}], storedProcedure id [{}]", + collectionLink, storedProcedure.id()); + RxDocumentServiceRequest request = getStoredProcedureRequest(collectionLink, storedProcedure, options, + OperationType.Upsert); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.upsert(request).map(response -> toResourceResponse(response, StoredProcedure.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in upserting a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> replaceStoredProcedure(StoredProcedure storedProcedure, + RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceStoredProcedureInternal(storedProcedure, options, requestRetryPolicy), requestRetryPolicy); + } + + private Flux> replaceStoredProcedureInternal(StoredProcedure storedProcedure, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + + if (storedProcedure == null) { + throw new IllegalArgumentException("storedProcedure"); + } + logger.debug("Replacing a StoredProcedure. storedProcedure id [{}]", storedProcedure.id()); + + RxDocumentClientImpl.validateResource(storedProcedure); + + String path = Utils.joinPath(storedProcedure.selfLink(), null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.StoredProcedure, path, storedProcedure, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, StoredProcedure.class)); + + } catch (Exception e) { + logger.debug("Failure in replacing a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deleteStoredProcedure(String storedProcedureLink, + RequestOptions options) { + IDocumentClientRetryPolicy requestRetryPolicy = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteStoredProcedureInternal(storedProcedureLink, options, requestRetryPolicy), requestRetryPolicy); + } + + private Flux> deleteStoredProcedureInternal(String storedProcedureLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + + if (StringUtils.isEmpty(storedProcedureLink)) { + throw new IllegalArgumentException("storedProcedureLink"); + } + + logger.debug("Deleting a StoredProcedure. storedProcedureLink [{}]", storedProcedureLink); + String path = Utils.joinPath(storedProcedureLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.StoredProcedure, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, StoredProcedure.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in deleting a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readStoredProcedure(String storedProcedureLink, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readStoredProcedureInternal(storedProcedureLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readStoredProcedureInternal(String storedProcedureLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + + if (StringUtils.isEmpty(storedProcedureLink)) { + throw new IllegalArgumentException("storedProcedureLink"); + } + + logger.debug("Reading a StoredProcedure. storedProcedureLink [{}]", storedProcedureLink); + String path = Utils.joinPath(storedProcedureLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.StoredProcedure, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.read(request).map(response -> toResourceResponse(response, StoredProcedure.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in reading a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readStoredProcedures(String collectionLink, + FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return readFeed(options, ResourceType.StoredProcedure, StoredProcedure.class, + Utils.joinPath(collectionLink, Paths.STORED_PROCEDURES_PATH_SEGMENT)); + } + + @Override + public Flux> queryStoredProcedures(String collectionLink, String query, + FeedOptions options) { + return queryStoredProcedures(collectionLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryStoredProcedures(String collectionLink, + SqlQuerySpec querySpec, FeedOptions options) { + return createQuery(collectionLink, querySpec, options, StoredProcedure.class, ResourceType.StoredProcedure); + } + + @Override + public Flux executeStoredProcedure(String storedProcedureLink, + Object[] procedureParams) { + return this.executeStoredProcedure(storedProcedureLink, null, procedureParams); + } + + @Override + public Flux executeStoredProcedure(String storedProcedureLink, + RequestOptions options, Object[] procedureParams) { + return ObservableHelper.inlineIfPossibleAsObs(() -> executeStoredProcedureInternal(storedProcedureLink, options, procedureParams), this.resetSessionTokenRetryPolicy.getRequestPolicy()); + } + + private Flux executeStoredProcedureInternal(String storedProcedureLink, + RequestOptions options, Object[] procedureParams) { + + try { + logger.debug("Executing a StoredProcedure. storedProcedureLink [{}]", storedProcedureLink); + String path = Utils.joinPath(storedProcedureLink, null); + + Map requestHeaders = getRequestHeaders(options); + requestHeaders.put(HttpConstants.HttpHeaders.ACCEPT, RuntimeConstants.MediaTypes.JSON); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.ExecuteJavaScript, + ResourceType.StoredProcedure, path, + procedureParams != null ? RxDocumentClientImpl.serializeProcedureParams(procedureParams) : "", + requestHeaders, options); + + Flux reqObs = addPartitionKeyInformation(request, null, options).flux(); + return reqObs.flatMap(req -> create(request) + .map(response -> { + this.captureSessionToken(request, response); + return toStoredProcedureResponse(response); + })); + + } catch (Exception e) { + logger.debug("Failure in executing a StoredProcedure due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> createTrigger(String collectionLink, Trigger trigger, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> createTriggerInternal(collectionLink, trigger, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> createTriggerInternal(String collectionLink, Trigger trigger, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + + logger.debug("Creating a Trigger. collectionLink [{}], trigger id [{}]", collectionLink, + trigger.id()); + RxDocumentServiceRequest request = getTriggerRequest(collectionLink, trigger, options, + OperationType.Create); + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.create(request).map(response -> toResourceResponse(response, Trigger.class)); + + } catch (Exception e) { + logger.debug("Failure in creating a Trigger due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertTrigger(String collectionLink, Trigger trigger, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertTriggerInternal(collectionLink, trigger, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> upsertTriggerInternal(String collectionLink, Trigger trigger, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + + logger.debug("Upserting a Trigger. collectionLink [{}], trigger id [{}]", collectionLink, + trigger.id()); + RxDocumentServiceRequest request = getTriggerRequest(collectionLink, trigger, options, + OperationType.Upsert); + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.upsert(request).map(response -> toResourceResponse(response, Trigger.class)); + + } catch (Exception e) { + logger.debug("Failure in upserting a Trigger due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + private RxDocumentServiceRequest getTriggerRequest(String collectionLink, Trigger trigger, RequestOptions options, + OperationType operationType) { + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + if (trigger == null) { + throw new IllegalArgumentException("trigger"); + } + + RxDocumentClientImpl.validateResource(trigger); + + String path = Utils.joinPath(collectionLink, Paths.TRIGGERS_PATH_SEGMENT); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, ResourceType.Trigger, path, + trigger, requestHeaders, options); + + return request; + } + + @Override + public Flux> replaceTrigger(Trigger trigger, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceTriggerInternal(trigger, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> replaceTriggerInternal(Trigger trigger, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (trigger == null) { + throw new IllegalArgumentException("trigger"); + } + + logger.debug("Replacing a Trigger. trigger id [{}]", trigger.id()); + RxDocumentClientImpl.validateResource(trigger); + + String path = Utils.joinPath(trigger.selfLink(), null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.Trigger, path, trigger, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, Trigger.class)); + + } catch (Exception e) { + logger.debug("Failure in replacing a Trigger due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deleteTrigger(String triggerLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteTriggerInternal(triggerLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteTriggerInternal(String triggerLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(triggerLink)) { + throw new IllegalArgumentException("triggerLink"); + } + + logger.debug("Deleting a Trigger. triggerLink [{}]", triggerLink); + String path = Utils.joinPath(triggerLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.Trigger, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, Trigger.class)); + + } catch (Exception e) { + logger.debug("Failure in deleting a Trigger due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readTrigger(String triggerLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readTriggerInternal(triggerLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readTriggerInternal(String triggerLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(triggerLink)) { + throw new IllegalArgumentException("triggerLink"); + } + + logger.debug("Reading a Trigger. triggerLink [{}]", triggerLink); + String path = Utils.joinPath(triggerLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Trigger, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.read(request).map(response -> toResourceResponse(response, Trigger.class)); + + } catch (Exception e) { + logger.debug("Failure in reading a Trigger due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readTriggers(String collectionLink, FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return readFeed(options, ResourceType.Trigger, Trigger.class, + Utils.joinPath(collectionLink, Paths.TRIGGERS_PATH_SEGMENT)); + } + + @Override + public Flux> queryTriggers(String collectionLink, String query, + FeedOptions options) { + return queryTriggers(collectionLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryTriggers(String collectionLink, SqlQuerySpec querySpec, + FeedOptions options) { + return createQuery(collectionLink, querySpec, options, Trigger.class, ResourceType.Trigger); + } + + @Override + public Flux> createUserDefinedFunction(String collectionLink, + UserDefinedFunction udf, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> createUserDefinedFunctionInternal(collectionLink, udf, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> createUserDefinedFunctionInternal(String collectionLink, + UserDefinedFunction udf, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + logger.debug("Creating a UserDefinedFunction. collectionLink [{}], udf id [{}]", collectionLink, + udf.id()); + RxDocumentServiceRequest request = getUserDefinedFunctionRequest(collectionLink, udf, options, + OperationType.Create); + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.create(request).map(response -> toResourceResponse(response, UserDefinedFunction.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in creating a UserDefinedFunction due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertUserDefinedFunction(String collectionLink, + UserDefinedFunction udf, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertUserDefinedFunctionInternal(collectionLink, udf, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> upsertUserDefinedFunctionInternal(String collectionLink, + UserDefinedFunction udf, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + logger.debug("Upserting a UserDefinedFunction. collectionLink [{}], udf id [{}]", collectionLink, + udf.id()); + RxDocumentServiceRequest request = getUserDefinedFunctionRequest(collectionLink, udf, options, + OperationType.Upsert); + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.upsert(request).map(response -> toResourceResponse(response, UserDefinedFunction.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in upserting a UserDefinedFunction due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> replaceUserDefinedFunction(UserDefinedFunction udf, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceUserDefinedFunctionInternal(udf, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> replaceUserDefinedFunctionInternal(UserDefinedFunction udf, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + if (udf == null) { + throw new IllegalArgumentException("udf"); + } + + logger.debug("Replacing a UserDefinedFunction. udf id [{}]", udf.id()); + validateResource(udf); + + String path = Utils.joinPath(udf.selfLink(), null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.UserDefinedFunction, path, udf, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, UserDefinedFunction.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in replacing a UserDefinedFunction due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deleteUserDefinedFunction(String udfLink, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteUserDefinedFunctionInternal(udfLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteUserDefinedFunctionInternal(String udfLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + if (StringUtils.isEmpty(udfLink)) { + throw new IllegalArgumentException("udfLink"); + } + + logger.debug("Deleting a UserDefinedFunction. udfLink [{}]", udfLink); + String path = Utils.joinPath(udfLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.UserDefinedFunction, path, requestHeaders, options); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, UserDefinedFunction.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in deleting a UserDefinedFunction due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readUserDefinedFunction(String udfLink, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readUserDefinedFunctionInternal(udfLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readUserDefinedFunctionInternal(String udfLink, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + // we are using an observable factory here + // observable will be created fresh upon subscription + // this is to ensure we capture most up to date information (e.g., + // session) + try { + if (StringUtils.isEmpty(udfLink)) { + throw new IllegalArgumentException("udfLink"); + } + + logger.debug("Reading a UserDefinedFunction. udfLink [{}]", udfLink); + String path = Utils.joinPath(udfLink, null); + Map requestHeaders = this.getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.UserDefinedFunction, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.read(request).map(response -> toResourceResponse(response, UserDefinedFunction.class)); + + } catch (Exception e) { + // this is only in trace level to capture what's going on + logger.debug("Failure in reading a UserDefinedFunction due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readUserDefinedFunctions(String collectionLink, + FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return readFeed(options, ResourceType.UserDefinedFunction, UserDefinedFunction.class, + Utils.joinPath(collectionLink, Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT)); + } + + @Override + public Flux> queryUserDefinedFunctions(String collectionLink, + String query, FeedOptions options) { + return queryUserDefinedFunctions(collectionLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryUserDefinedFunctions(String collectionLink, + SqlQuerySpec querySpec, FeedOptions options) { + return createQuery(collectionLink, querySpec, options, UserDefinedFunction.class, ResourceType.UserDefinedFunction); + } + + @Override + public Flux> readConflict(String conflictLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readConflictInternal(conflictLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readConflictInternal(String conflictLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (StringUtils.isEmpty(conflictLink)) { + throw new IllegalArgumentException("conflictLink"); + } + + logger.debug("Reading a Conflict. conflictLink [{}]", conflictLink); + String path = Utils.joinPath(conflictLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Conflict, path, requestHeaders, options); + + Flux reqObs = addPartitionKeyInformation(request, null, options).flux(); + + return reqObs.flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(response -> toResourceResponse(response, Conflict.class)); + }); + + } catch (Exception e) { + logger.debug("Failure in reading a Conflict due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readConflicts(String collectionLink, FeedOptions options) { + + if (StringUtils.isEmpty(collectionLink)) { + throw new IllegalArgumentException("collectionLink"); + } + + return readFeed(options, ResourceType.Conflict, Conflict.class, + Utils.joinPath(collectionLink, Paths.CONFLICTS_PATH_SEGMENT)); + } + + @Override + public Flux> queryConflicts(String collectionLink, String query, + FeedOptions options) { + return queryConflicts(collectionLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryConflicts(String collectionLink, SqlQuerySpec querySpec, + FeedOptions options) { + return createQuery(collectionLink, querySpec, options, Conflict.class, ResourceType.Conflict); + } + + @Override + public Flux> deleteConflict(String conflictLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteConflictInternal(conflictLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteConflictInternal(String conflictLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (StringUtils.isEmpty(conflictLink)) { + throw new IllegalArgumentException("conflictLink"); + } + + logger.debug("Deleting a Conflict. conflictLink [{}]", conflictLink); + String path = Utils.joinPath(conflictLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.Conflict, path, requestHeaders, options); + + Flux reqObs = addPartitionKeyInformation(request, null, options).flux(); + return reqObs.flatMap(req -> { + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, Conflict.class)); + }); + + } catch (Exception e) { + logger.debug("Failure in deleting a Conflict due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> createUser(String databaseLink, User user, RequestOptions options) { + return ObservableHelper.inlineIfPossibleAsObs(() -> createUserInternal(databaseLink, user, options), this.resetSessionTokenRetryPolicy.getRequestPolicy()); + } + + private Flux> createUserInternal(String databaseLink, User user, RequestOptions options) { + try { + logger.debug("Creating a User. databaseLink [{}], user id [{}]", databaseLink, user.id()); + RxDocumentServiceRequest request = getUserRequest(databaseLink, user, options, OperationType.Create); + return this.create(request).map(response -> toResourceResponse(response, User.class)); + + } catch (Exception e) { + logger.debug("Failure in creating a User due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertUser(String databaseLink, User user, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertUserInternal(databaseLink, user, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> upsertUserInternal(String databaseLink, User user, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + try { + logger.debug("Upserting a User. databaseLink [{}], user id [{}]", databaseLink, user.id()); + RxDocumentServiceRequest request = getUserRequest(databaseLink, user, options, OperationType.Upsert); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.upsert(request).map(response -> toResourceResponse(response, User.class)); + + } catch (Exception e) { + logger.debug("Failure in upserting a User due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + private RxDocumentServiceRequest getUserRequest(String databaseLink, User user, RequestOptions options, + OperationType operationType) { + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + if (user == null) { + throw new IllegalArgumentException("user"); + } + + RxDocumentClientImpl.validateResource(user); + + String path = Utils.joinPath(databaseLink, Paths.USERS_PATH_SEGMENT); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, ResourceType.User, path, user, + requestHeaders, options); + + return request; + } + + @Override + public Flux> replaceUser(User user, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceUserInternal(user, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> replaceUserInternal(User user, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (user == null) { + throw new IllegalArgumentException("user"); + } + logger.debug("Replacing a User. user id [{}]", user.id()); + RxDocumentClientImpl.validateResource(user); + + String path = Utils.joinPath(user.selfLink(), null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.User, path, user, requestHeaders, options); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, User.class)); + + } catch (Exception e) { + logger.debug("Failure in replacing a User due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + + public Flux> deleteUser(String userLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deleteUserInternal(userLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deleteUserInternal(String userLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (StringUtils.isEmpty(userLink)) { + throw new IllegalArgumentException("userLink"); + } + logger.debug("Deleting a User. userLink [{}]", userLink); + String path = Utils.joinPath(userLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.User, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, User.class)); + + } catch (Exception e) { + logger.debug("Failure in deleting a User due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + @Override + public Flux> readUser(String userLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readUserInternal(userLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readUserInternal(String userLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(userLink)) { + throw new IllegalArgumentException("userLink"); + } + logger.debug("Reading a User. userLink [{}]", userLink); + String path = Utils.joinPath(userLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.User, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(response -> toResourceResponse(response, User.class)); + + } catch (Exception e) { + logger.debug("Failure in reading a User due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readUsers(String databaseLink, FeedOptions options) { + + if (StringUtils.isEmpty(databaseLink)) { + throw new IllegalArgumentException("databaseLink"); + } + + return readFeed(options, ResourceType.User, User.class, + Utils.joinPath(databaseLink, Paths.USERS_PATH_SEGMENT)); + } + + @Override + public Flux> queryUsers(String databaseLink, String query, FeedOptions options) { + return queryUsers(databaseLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryUsers(String databaseLink, SqlQuerySpec querySpec, + FeedOptions options) { + return createQuery(databaseLink, querySpec, options, User.class, ResourceType.User); + } + + @Override + public Flux> createPermission(String userLink, Permission permission, + RequestOptions options) { + return ObservableHelper.inlineIfPossibleAsObs(() -> createPermissionInternal(userLink, permission, options), this.resetSessionTokenRetryPolicy.getRequestPolicy()); + } + + private Flux> createPermissionInternal(String userLink, Permission permission, + RequestOptions options) { + + try { + logger.debug("Creating a Permission. userLink [{}], permission id [{}]", userLink, permission.id()); + RxDocumentServiceRequest request = getPermissionRequest(userLink, permission, options, + OperationType.Create); + return this.create(request).map(response -> toResourceResponse(response, Permission.class)); + + } catch (Exception e) { + logger.debug("Failure in creating a Permission due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> upsertPermission(String userLink, Permission permission, + RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> upsertPermissionInternal(userLink, permission, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> upsertPermissionInternal(String userLink, Permission permission, + RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + logger.debug("Upserting a Permission. userLink [{}], permission id [{}]", userLink, permission.id()); + RxDocumentServiceRequest request = getPermissionRequest(userLink, permission, options, + OperationType.Upsert); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.upsert(request).map(response -> toResourceResponse(response, Permission.class)); + + } catch (Exception e) { + logger.debug("Failure in upserting a Permission due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + private RxDocumentServiceRequest getPermissionRequest(String userLink, Permission permission, + RequestOptions options, OperationType operationType) { + if (StringUtils.isEmpty(userLink)) { + throw new IllegalArgumentException("userLink"); + } + if (permission == null) { + throw new IllegalArgumentException("permission"); + } + + RxDocumentClientImpl.validateResource(permission); + + String path = Utils.joinPath(userLink, Paths.PERMISSIONS_PATH_SEGMENT); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, ResourceType.Permission, path, + permission, requestHeaders, options); + + return request; + } + + @Override + public Flux> replacePermission(Permission permission, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> replacePermissionInternal(permission, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> replacePermissionInternal(Permission permission, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (permission == null) { + throw new IllegalArgumentException("permission"); + } + logger.debug("Replacing a Permission. permission id [{}]", permission.id()); + RxDocumentClientImpl.validateResource(permission); + + String path = Utils.joinPath(permission.selfLink(), null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.Permission, path, permission, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.replace(request).map(response -> toResourceResponse(response, Permission.class)); + + } catch (Exception e) { + logger.debug("Failure in replacing a Permission due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> deletePermission(String permissionLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> deletePermissionInternal(permissionLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> deletePermissionInternal(String permissionLink, RequestOptions options, + IDocumentClientRetryPolicy retryPolicyInstance) { + + try { + if (StringUtils.isEmpty(permissionLink)) { + throw new IllegalArgumentException("permissionLink"); + } + logger.debug("Deleting a Permission. permissionLink [{}]", permissionLink); + String path = Utils.joinPath(permissionLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Delete, + ResourceType.Permission, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.delete(request).map(response -> toResourceResponse(response, Permission.class)); + + } catch (Exception e) { + logger.debug("Failure in deleting a Permission due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readPermission(String permissionLink, RequestOptions options) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readPermissionInternal(permissionLink, options, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readPermissionInternal(String permissionLink, RequestOptions options, IDocumentClientRetryPolicy retryPolicyInstance ) { + try { + if (StringUtils.isEmpty(permissionLink)) { + throw new IllegalArgumentException("permissionLink"); + } + logger.debug("Reading a Permission. permissionLink [{}]", permissionLink); + String path = Utils.joinPath(permissionLink, null); + Map requestHeaders = getRequestHeaders(options); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Permission, path, requestHeaders, options); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + return this.read(request).map(response -> toResourceResponse(response, Permission.class)); + + } catch (Exception e) { + logger.debug("Failure in reading a Permission due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readPermissions(String userLink, FeedOptions options) { + + if (StringUtils.isEmpty(userLink)) { + throw new IllegalArgumentException("userLink"); + } + + return readFeed(options, ResourceType.Permission, Permission.class, + Utils.joinPath(userLink, Paths.PERMISSIONS_PATH_SEGMENT)); + } + + @Override + public Flux> queryPermissions(String userLink, String query, + FeedOptions options) { + return queryPermissions(userLink, new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryPermissions(String userLink, SqlQuerySpec querySpec, + FeedOptions options) { + return createQuery(userLink, querySpec, options, Permission.class, ResourceType.Permission); + } + + @Override + public Flux> replaceOffer(Offer offer) { + return ObservableHelper.inlineIfPossibleAsObs(() -> replaceOfferInternal(offer), this.resetSessionTokenRetryPolicy.getRequestPolicy()); + } + + private Flux> replaceOfferInternal(Offer offer) { + try { + if (offer == null) { + throw new IllegalArgumentException("offer"); + } + logger.debug("Replacing an Offer. offer id [{}]", offer.id()); + RxDocumentClientImpl.validateResource(offer); + + String path = Utils.joinPath(offer.selfLink(), null); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Replace, + ResourceType.Offer, path, offer, null, null); + return this.replace(request).map(response -> toResourceResponse(response, Offer.class)); + + } catch (Exception e) { + logger.debug("Failure in replacing an Offer due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readOffer(String offerLink) { + IDocumentClientRetryPolicy retryPolicyInstance = this.resetSessionTokenRetryPolicy.getRequestPolicy(); + return ObservableHelper.inlineIfPossibleAsObs(() -> readOfferInternal(offerLink, retryPolicyInstance), retryPolicyInstance); + } + + private Flux> readOfferInternal(String offerLink, IDocumentClientRetryPolicy retryPolicyInstance) { + try { + if (StringUtils.isEmpty(offerLink)) { + throw new IllegalArgumentException("offerLink"); + } + logger.debug("Reading an Offer. offerLink [{}]", offerLink); + String path = Utils.joinPath(offerLink, null); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.Offer, path, (HashMap)null, null); + + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + return this.read(request).map(response -> toResourceResponse(response, Offer.class)); + + } catch (Exception e) { + logger.debug("Failure in reading an Offer due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + @Override + public Flux> readOffers(FeedOptions options) { + return readFeed(options, ResourceType.Offer, Offer.class, + Utils.joinPath(Paths.OFFERS_PATH_SEGMENT, null)); + } + + private Flux> readFeedCollectionChild(FeedOptions options, ResourceType resourceType, + Class klass, String resourceLink) { + if (options == null) { + options = new FeedOptions(); + } + + int maxPageSize = options.maxItemCount() != null ? options.maxItemCount() : -1; + + final FeedOptions finalFeedOptions = options; + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(options.partitionKey()); + BiFunction createRequestFunc = (continuationToken, pageSize) -> { + Map requestHeaders = new HashMap<>(); + if (continuationToken != null) { + requestHeaders.put(HttpConstants.HttpHeaders.CONTINUATION, continuationToken); + } + requestHeaders.put(HttpConstants.HttpHeaders.PAGE_SIZE, Integer.toString(pageSize)); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.ReadFeed, + resourceType, resourceLink, requestHeaders, finalFeedOptions); + return request; + }; + + Function>> executeFunc = request -> { + return ObservableHelper.inlineIfPossibleAsObs(() -> { + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + Mono requestObs = this.addPartitionKeyInformation(request, null, requestOptions, collectionObs); + + return requestObs.flux().flatMap(req -> this.readFeed(req) + .map(response -> toFeedResponsePage(response, klass))); + }, this.resetSessionTokenRetryPolicy.getRequestPolicy()); + }; + + return Paginator.getPaginatedQueryResultAsObservable(options, createRequestFunc, executeFunc, klass, maxPageSize); + } + + private Flux> readFeed(FeedOptions options, ResourceType resourceType, Class klass, String resourceLink) { + if (options == null) { + options = new FeedOptions(); + } + + int maxPageSize = options.maxItemCount() != null ? options.maxItemCount() : -1; + final FeedOptions finalFeedOptions = options; + BiFunction createRequestFunc = (continuationToken, pageSize) -> { + Map requestHeaders = new HashMap<>(); + if (continuationToken != null) { + requestHeaders.put(HttpConstants.HttpHeaders.CONTINUATION, continuationToken); + } + requestHeaders.put(HttpConstants.HttpHeaders.PAGE_SIZE, Integer.toString(pageSize)); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.ReadFeed, + resourceType, resourceLink, requestHeaders, finalFeedOptions); + return request; + }; + + Function>> executeFunc = request -> { + return ObservableHelper.inlineIfPossibleAsObs(() -> readFeed(request).map(response -> toFeedResponsePage(response, klass)), + this.resetSessionTokenRetryPolicy.getRequestPolicy()); + }; + + return Paginator.getPaginatedQueryResultAsObservable(options, createRequestFunc, executeFunc, klass, maxPageSize); + } + + @Override + public Flux> queryOffers(String query, FeedOptions options) { + return queryOffers(new SqlQuerySpec(query), options); + } + + @Override + public Flux> queryOffers(SqlQuerySpec querySpec, FeedOptions options) { + return createQuery(null, querySpec, options, Offer.class, ResourceType.Offer); + } + + @Override + public Flux getDatabaseAccount() { + return ObservableHelper.inlineIfPossibleAsObs(() -> getDatabaseAccountInternal(), this.resetSessionTokenRetryPolicy.getRequestPolicy()); + } + + private Flux getDatabaseAccountInternal() { + try { + logger.debug("Getting Database Account"); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.DatabaseAccount, "", // path + (HashMap) null, + null); + return this.read(request).map(response -> toDatabaseAccount(response)); + + } catch (Exception e) { + logger.debug("Failure in getting Database Account due to [{}]", e.getMessage(), e); + return Flux.error(e); + } + } + + public Object getSession() { + return this.sessionContainer; + } + + public void setSession(Object sessionContainer) { + this.sessionContainer = (SessionContainer) sessionContainer; + } + + public RxPartitionKeyRangeCache getPartitionKeyRangeCache() { + return partitionKeyRangeCache; + } + + public Flux getDatabaseAccountFromEndpoint(URI endpoint) { + return Flux.defer(() -> { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.DatabaseAccount, "", null, (Object) null); + this.populateHeaders(request, HttpConstants.HttpMethods.GET); + + request.setEndpointOverride(endpoint); + return this.gatewayProxy.processMessage(request).doOnError(e -> { + String message = String.format("Failed to retrieve database account information. %s", + e.getCause() != null + ? e.getCause().toString() + : e.toString()); + logger.warn(message); + }).map(rsp -> rsp.getResource(DatabaseAccount.class)) + .doOnNext(databaseAccount -> { + this.useMultipleWriteLocations = this.connectionPolicy.usingMultipleWriteLocations() + && BridgeInternal.isEnableMultipleWriteLocations(databaseAccount); + }); + }); + } + + /** + * Certain requests must be routed through gateway even when the client connectivity mode is direct. + * + * @param request + * @return RxStoreModel + */ + private RxStoreModel getStoreProxy(RxDocumentServiceRequest request) { + // If a request is configured to always use GATEWAY mode(in some cases when targeting .NET Core) + // we return the GATEWAY store model + if (request.UseGatewayMode) { + return this.gatewayProxy; + } + + ResourceType resourceType = request.getResourceType(); + OperationType operationType = request.getOperationType(); + + if (resourceType == ResourceType.Offer || + resourceType.isScript() && operationType != OperationType.ExecuteJavaScript || + resourceType == ResourceType.PartitionKeyRange) { + return this.gatewayProxy; + } + + if (operationType == OperationType.Create + || operationType == OperationType.Upsert) { + if (resourceType == ResourceType.Database || + resourceType == ResourceType.User || + resourceType == ResourceType.DocumentCollection || + resourceType == ResourceType.Permission) { + return this.gatewayProxy; + } else { + return this.storeModel; + } + } else if (operationType == OperationType.Delete) { + if (resourceType == ResourceType.Database || + resourceType == ResourceType.User || + resourceType == ResourceType.DocumentCollection) { + return this.gatewayProxy; + } else { + return this.storeModel; + } + } else if (operationType == OperationType.Replace) { + if (resourceType == ResourceType.DocumentCollection) { + return this.gatewayProxy; + } else { + return this.storeModel; + } + } else if (operationType == OperationType.Read) { + if (resourceType == ResourceType.DocumentCollection) { + return this.gatewayProxy; + } else { + return this.storeModel; + } + } else { + if ((request.getOperationType() == OperationType.Query || request.getOperationType() == OperationType.SqlQuery) && + Utils.isCollectionChild(request.getResourceType())) { + if (request.getPartitionKeyRangeIdentity() == null) { + return this.gatewayProxy; + } + } + + return this.storeModel; + } + } + + @Override + public void close() { + logger.info("Shutting down ..."); + LifeCycleUtils.closeQuietly(this.globalEndpointManager); + LifeCycleUtils.closeQuietly(this.storeClientFactory); + + try { + this.reactorHttpClient.shutdown(); + } catch (Exception e) { + logger.warn("Failure in shutting down reactorHttpClient", e); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceRequest.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceRequest.java new file mode 100644 index 0000000000000..89577ae39c051 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceRequest.java @@ -0,0 +1,1049 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import reactor.core.publisher.Flux; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * This is core Transport/Connection agnostic request to the Azure Cosmos DB database service. + */ +public class RxDocumentServiceRequest { + private static final char PREFER_HEADER_SEPERATOR = ';'; + private static final String PREFER_HEADER_VALUE_FORMAT = "%s=%s"; + + public volatile boolean forcePartitionKeyRangeRefresh; + public volatile boolean forceCollectionRoutingMapRefresh; + private String resourceId; + private final ResourceType resourceType; + private final Map headers; + private volatile String continuation; + private boolean isMedia = false; + private final boolean isNameBased; + private final OperationType operationType; + private final String resourceAddress; + public volatile boolean forceNameCacheRefresh; + private volatile URI endpointOverride = null; + private final String activityId; + private volatile String resourceFullName; + + private volatile String originalSessionToken; + private volatile PartitionKeyRangeIdentity partitionKeyRangeIdentity; + private volatile Integer defaultReplicaIndex; + + public DocumentServiceRequestContext requestContext; + + private Flux contentObservable; + private byte[] byteContent; + + // NOTE: TODO: these fields are copied from .Net SDK + // some of these fields are missing from the main java sdk service request + // so it means most likely the corresponding features are also missing from the main sdk + // we need to wire this up. + public boolean UseGatewayMode; + + private volatile boolean isDisposed = false; + public volatile String entityId; + public volatile String queryString; + public volatile boolean isFeed; + public volatile AuthorizationTokenType authorizationTokenType; + public volatile Map properties; + + public boolean isReadOnlyRequest() { + return this.operationType == OperationType.Read + || this.operationType == OperationType.ReadFeed + || this.operationType == OperationType.Head + || this.operationType == OperationType.HeadFeed + || this.operationType == OperationType.Query + || this.operationType == OperationType.SqlQuery; + } + + public boolean isReadOnlyScript() { + String isReadOnlyScript = this.headers.get(HttpConstants.HttpHeaders.IS_READ_ONLY_SCRIPT); + if(StringUtils.isEmpty(isReadOnlyScript)) { + return false; + } else { + return this.operationType.equals(OperationType.ExecuteJavaScript) && isReadOnlyScript.equalsIgnoreCase(Boolean.TRUE.toString()); + } + } + + /** + * @param operationType the operation type. + * @param resourceIdOrFullName the request id or full name. + * @param resourceType the resource type. + * @param byteContent the byte content. + * @param headers the headers. + * @param isNameBased whether request is name based. + * @param authorizationTokenType the request authorizationTokenType. + */ + private RxDocumentServiceRequest(OperationType operationType, + String resourceIdOrFullName, + ResourceType resourceType, + byte[] byteContent, + Map headers, + boolean isNameBased, + AuthorizationTokenType authorizationTokenType) { + this.operationType = operationType; + this.forceNameCacheRefresh = false; + this.resourceType = resourceType; + this.byteContent = byteContent; + this.headers = headers != null ? headers : new HashMap<>(); + this.activityId = Utils.randomUUID().toString(); + this.isFeed = false; + this.isNameBased = isNameBased; + if (!isNameBased) { + this.resourceId = resourceIdOrFullName; + } + this.resourceAddress = resourceIdOrFullName; + this.authorizationTokenType = authorizationTokenType; + this.requestContext = new DocumentServiceRequestContext(); + if (StringUtils.isNotEmpty(this.headers.get(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID))) + this.partitionKeyRangeIdentity = PartitionKeyRangeIdentity.fromHeader(this.headers.get(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID)); + } + + /** + * Creates a AbstractDocumentServiceRequest + * + * @param operationType the operation type. + * @param resourceIdOrFullName the request id or full name. + * @param resourceType the resource type. + * @param path the path. + * @param headers the headers + */ + private RxDocumentServiceRequest(OperationType operationType, + String resourceIdOrFullName, + ResourceType resourceType, + String path, + Map headers) { + this.requestContext = new DocumentServiceRequestContext(); + this.operationType = operationType; + this.resourceType = resourceType; + this.requestContext.sessionToken = null; + this.headers = headers != null ? headers : new HashMap<>(); + this.activityId = Utils.randomUUID().toString(); + this.isFeed = false; + PathInfo pathInfo = new PathInfo(false, null, null, false); + if (StringUtils.isNotEmpty(path)) { + if (PathsHelper.tryParsePathSegments(path, pathInfo, null)) { + this.isNameBased = pathInfo.isNameBased; + this.isFeed = pathInfo.isFeed; + resourceIdOrFullName = pathInfo.resourceIdOrFullName; + if (!this.isNameBased) { + if (resourceType == ResourceType.Media) { + this.resourceId = getAttachmentIdFromMediaId(resourceIdOrFullName); + } else { + this.resourceId = resourceIdOrFullName; + } + + this.resourceAddress = resourceIdOrFullName; + + // throw exception when the address parsing fail + // do not parse address for offer resource + if (StringUtils.isNotEmpty(this.resourceId) && !ResourceId.tryParse(this.resourceId).getLeft() + && !resourceType.equals(ResourceType.Offer) && !resourceType.equals(ResourceType.Media) + && !resourceType.equals(ResourceType.MasterPartition) + && !resourceType.equals(ResourceType.ServerPartition) + && !resourceType.equals(ResourceType.DatabaseAccount) + && !resourceType.equals(ResourceType.RidRange)) { + throw new IllegalArgumentException( + String.format(RMResources.InvalidResourceUrlQuery, path, HttpConstants.QueryStrings.URL)); + } + } else { + this.resourceAddress = resourceIdOrFullName; + this.resourceId = null; + } + } else { + throw new IllegalArgumentException(RMResources.NotFound); + } + } else { + this.isNameBased = false; + this.resourceAddress = resourceIdOrFullName; + } + + if (StringUtils.isNotEmpty(this.headers.get(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID))) { + this.partitionKeyRangeIdentity = PartitionKeyRangeIdentity + .fromHeader(this.headers.get(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID)); + } + } + + /** + * Creates a DocumentServiceRequest + * + * @param resourceId the resource Id. + * @param resourceType the resource type. + * @param content the byte content observable\ + * @param contentObservable the byte content observable + * @param headers the request headers. + */ + private RxDocumentServiceRequest(OperationType operationType, + String resourceId, + ResourceType resourceType, + Flux contentObservable, + byte[] content, + String path, + Map headers, + AuthorizationTokenType authorizationTokenType) { + this( operationType, + resourceId, + resourceType, + path, + headers); + this.authorizationTokenType = authorizationTokenType; + this.byteContent = content; + this.contentObservable = contentObservable; + } + + /** + * Creates a DocumentServiceRequest with an HttpEntity. + * + * @param resourceType the resource type. + * @param path the relative URI path. + * @param contentObservable the byte content observable + * @param headers the request headers. + */ + private RxDocumentServiceRequest(OperationType operationType, + ResourceType resourceType, + String path, + Flux contentObservable, + Map headers, + AuthorizationTokenType authorizationTokenType) { + this(operationType, extractIdFromUri(path), resourceType, contentObservable, null, path, headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with an HttpEntity. + * + * @param resourceType the resource type. + * @param path the relative URI path. + * @param byteContent the byte content. + * @param headers the request headers. + */ + private RxDocumentServiceRequest(OperationType operationType, + ResourceType resourceType, + String path, + byte[] byteContent, + Map headers, + AuthorizationTokenType authorizationTokenType) { + this(operationType, extractIdFromUri(path), resourceType, null, byteContent, path, headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with an HttpEntity. + * + * @param resourceType the resource type. + * @param path the relative URI path. + * @param headers the request headers. + */ + private RxDocumentServiceRequest(OperationType operationType, + ResourceType resourceType, + String path, + Map headers, + AuthorizationTokenType authorizationTokenType) { + this(operationType, extractIdFromUri(path), resourceType, null , null, path, headers, authorizationTokenType); + } + + public void setContentBytes(byte[] bytes) { + this.byteContent = bytes; + } + + /** + * Creates a DocumentServiceRequest with a stream. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param content the content observable + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Flux content, + Map headers) { + return new RxDocumentServiceRequest(operation, resourceType, relativePath, content, headers, AuthorizationTokenType.PrimaryMasterKey); + } + + /** + * Creates a DocumentServiceRequest with a stream. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param content the content observable + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Flux content, + Map headers, + AuthorizationTokenType authorizationTokenType) { + return new RxDocumentServiceRequest(operation, resourceType, relativePath, content, headers, authorizationTokenType); + } + + /** Creates a DocumentServiceRequest with a stream. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param inputStream the input stream. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + InputStream inputStream, + Map headers) throws IOException { + Flux byteFlux = Flux.just(IOUtils.toByteArray(inputStream)); + return new RxDocumentServiceRequest(operation, resourceType, relativePath, byteFlux, headers, AuthorizationTokenType.PrimaryMasterKey); + } + + /** Creates a DocumentServiceRequest with a stream. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param inputStream the input stream. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + InputStream inputStream, + Map headers, + AuthorizationTokenType authorizationTokenType) throws IOException { + Flux byteFlux = Flux.just(IOUtils.toByteArray(inputStream)); + return new RxDocumentServiceRequest(operation, resourceType, relativePath, byteFlux, headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with a resource. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param resource the resource of the request. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Resource resource, + Map headers) { + return RxDocumentServiceRequest.create(operation, resourceType, relativePath, resource, headers, (RequestOptions)null); + } + + /** + * Creates a DocumentServiceRequest with a resource. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param resource the resource of the request. + * @param headers the request headers. + * @param options the request/feed/changeFeed options. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Resource resource, + Map headers, + Object options) { + + RxDocumentServiceRequest request = new RxDocumentServiceRequest(operation, resourceType, relativePath, + // TODO: this re-encodes, can we improve performance here? + resource.toJson().getBytes(StandardCharsets.UTF_8), headers, AuthorizationTokenType.PrimaryMasterKey); + request.properties = getProperties(options); + return request; + } + + /** + * Creates a DocumentServiceRequest with a query. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param query the query. + * @param headers the request headers. + * @param options the request/feed/changeFeed options. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + String query, + Map headers, + Object options) { + RxDocumentServiceRequest request = new RxDocumentServiceRequest(operation, resourceType, relativePath, + query.getBytes(StandardCharsets.UTF_8), headers, AuthorizationTokenType.PrimaryMasterKey); + request.properties = getProperties(options); + return request; + } + + /** + * Creates a DocumentServiceRequest with a query. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param query the query. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + String query, + Map headers, + AuthorizationTokenType authorizationTokenType) { + return new RxDocumentServiceRequest(operation, resourceType, relativePath, + query.getBytes(StandardCharsets.UTF_8), headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with a query. + * + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param querySpec the query. + * @param queryCompatibilityMode the QueryCompatibilityMode mode. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(ResourceType resourceType, + String relativePath, + SqlQuerySpec querySpec, + QueryCompatibilityMode queryCompatibilityMode, + Map headers) { + OperationType operation; + String queryText; + switch (queryCompatibilityMode) { + case SqlQuery: + if (querySpec.parameters() != null && querySpec.parameters().size() > 0) { + throw new IllegalArgumentException( + String.format("Unsupported argument in query compatibility mode '{%s}'", + queryCompatibilityMode.toString())); + } + + operation = OperationType.SqlQuery; + queryText = querySpec.queryText(); + break; + + case Default: + case Query: + default: + operation = OperationType.Query; + queryText = querySpec.toJson(); + break; + } + + Flux body = Flux.just(queryText).map(s -> StandardCharsets.UTF_8.encode(s).array()); + return new RxDocumentServiceRequest(operation, resourceType, relativePath, body, headers, AuthorizationTokenType.PrimaryMasterKey); + } + + /** + * Creates a DocumentServiceRequest without body. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Map headers) { + return RxDocumentServiceRequest.create(operation, resourceType, relativePath, headers, (RequestOptions)null); + } + + /** + * Creates a DocumentServiceRequest without body. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param headers the request headers. + * @param options the request/feed/changeFeed options. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Map headers, + Object options) { + RxDocumentServiceRequest request = new RxDocumentServiceRequest(operation, resourceType, relativePath, headers, AuthorizationTokenType.PrimaryMasterKey); + request.properties = getProperties(options); + return request; + } + + /** + * Creates a DocumentServiceRequest without body. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType, + String relativePath, + Map headers, + AuthorizationTokenType authorizationTokenType) { + return new RxDocumentServiceRequest(operation, resourceType, relativePath, headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest without body. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + Resource resource, + ResourceType resourceType, + String relativePath, + Map headers) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operation, resourceType, relativePath, resourceContent, headers, AuthorizationTokenType.PrimaryMasterKey); + } + + /** + * Creates a DocumentServiceRequest without body. + * + * @param operation the operation type. + * @param resourceType the resource type. + * @param relativePath the relative URI path. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + Resource resource, + ResourceType resourceType, + String relativePath, + Map headers, + AuthorizationTokenType authorizationTokenType) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operation, resourceType, relativePath, resourceContent, headers, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with a resourceId. + * + * @param operation the operation type. + * @param resourceId the resource id. + * @param resourceType the resource type. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + String resourceId, + ResourceType resourceType, + Map headers) { + return new RxDocumentServiceRequest(operation, resourceId,resourceType, null, headers, false, AuthorizationTokenType.PrimaryMasterKey) ; + } + + /** + * Creates a DocumentServiceRequest with a resourceId. + * + * @param operation the operation type. + * @param resourceId the resource id. + * @param resourceType the resource type. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + String resourceId, + ResourceType resourceType, + Map headers, + AuthorizationTokenType authorizationTokenType) { + return new RxDocumentServiceRequest(operation, resourceId, resourceType, null, headers, false, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with a resourceId. + * + * @param operation the operation type. + * @param resourceId the resource id. + * @param resourceType the resource type. + * @param headers the request headers. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + String resourceId, + ResourceType resourceType, + Resource resource, + Map headers) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operation, resourceId, resourceType, resourceContent, headers, false, AuthorizationTokenType.PrimaryMasterKey); + } + + /** + * Creates a DocumentServiceRequest with a resourceId. + * + * @param operation the operation type. + * @param resourceId the resource id. + * @param resourceType the resource type. + * @param headers the request headers. + * @param authorizationTokenType the request authorizationTokenType. + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + String resourceId, + ResourceType resourceType, + Resource resource, + Map headers, + AuthorizationTokenType authorizationTokenType) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operation, resourceId, resourceType, resourceContent, headers, false, authorizationTokenType); + } + + /** + * Creates a DocumentServiceRequest with operationType and resourceType + * @param operation the operation type + * @param resourceType the resource type + * @return the created document service request. + */ + public static RxDocumentServiceRequest create(OperationType operation, + ResourceType resourceType) { + return new RxDocumentServiceRequest(operation, null, resourceType, null, null); + } + + public static RxDocumentServiceRequest createFromName( + OperationType operationType, + String resourceFullName, + ResourceType resourceType) { + return new RxDocumentServiceRequest(operationType, + resourceFullName, + resourceType, + null, + new HashMap<>(), + true, + AuthorizationTokenType.PrimaryMasterKey + ); + } + + public static RxDocumentServiceRequest createFromName( + OperationType operationType, + String resourceFullName, + ResourceType resourceType, + AuthorizationTokenType authorizationTokenType) { + return new RxDocumentServiceRequest(operationType, + resourceFullName, + resourceType, + null, + new HashMap<>(), + true, + authorizationTokenType + ); + } + + public static RxDocumentServiceRequest createFromName( + OperationType operationType, + Resource resource, + String resourceFullName, + ResourceType resourceType) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operationType, + resourceFullName, + resourceType, + resourceContent, + new HashMap<>(), + true, + AuthorizationTokenType.PrimaryMasterKey + ); + } + + public static RxDocumentServiceRequest createFromName( + OperationType operationType, + Resource resource, + String resourceFullName, + ResourceType resourceType, + AuthorizationTokenType authorizationTokenType) { + byte[] resourceContent = resource.toJson().getBytes(StandardCharsets.UTF_8); + return new RxDocumentServiceRequest(operationType, + resourceFullName, + resourceType, + resourceContent, + new HashMap<>(), + true, + authorizationTokenType + ); + } + + private static String extractIdFromUri(String path) { + if (path.length() == 0) { + return path; + } + + if (path.charAt(path.length() - 1) != '/') { + path = path + '/'; + } + + if (path.charAt(0) != '/') { + path = '/' + path; + } + // This is a hack. We need a padding '=' so that path.split("/") + // returns even number of string pieces. + // TODO(pushi): Improve the code and remove the hack. + path = path + '='; + + // The path will be in the form of + // /[resourceType]/[resourceId]/ or + // /[resourceType]/[resourceId]/[resourceType]/ + // The result of split will be in the form of + // [[[resourceType], [resourceId] ... ,[resourceType], ""] + // In the first case, to extract the resourceId it will the element + // before last ( at length -2 ) and the type will before it + // ( at length -3 ) + // In the second case, to extract the resource type it will the element + // before last ( at length -2 ) + String[] pathParts = StringUtils.split(path, "/"); + if (pathParts.length % 2 == 0) { + // request in form /[resourceType]/[resourceId]/. + return pathParts[pathParts.length - 2]; + } else { + // request in form /[resourceType]/[resourceId]/[resourceType]/. + return pathParts[pathParts.length - 3]; + } + } + + static String getAttachmentIdFromMediaId(String mediaId) { + // '/' was replaced with '-'. + byte[] buffer = Utils.Base64Decoder.decode(mediaId.replace('-', '/').getBytes()); + + final int resoureIdLength = 20; + String attachmentId; + + if (buffer.length > resoureIdLength) { + // We are cuting off the storage index. + byte[] newBuffer = new byte[resoureIdLength]; + System.arraycopy(buffer, 0, newBuffer, 0, resoureIdLength); + attachmentId = Utils.encodeBase64String(newBuffer).replace('/', '-'); + } else { + attachmentId = mediaId; + } + + return attachmentId; + } + + /** + * Gets the resource id. + * + * @return the resource id. + */ + public String getResourceId() { + return this.resourceId; + } + + /** + * Sets the resource id. + * + */ + public void setResourceId(String resourceId) { + this.resourceId = resourceId; + } + + /** + * Gets the resource type. + * + * @return the resource type. + */ + public ResourceType getResourceType() { + return this.resourceType; + } + + /** + * Gets the request headers. + * + * @return the request headers. + */ + public Map getHeaders() { + return this.headers; + } + + /** + * Gets the continuation. + * + * @return the continuation. + */ + public String getContinuation() { + return this.continuation; + } + + public void setContinuation(String continuation) { + this.continuation = continuation; + } + + public boolean getIsMedia() { + return this.isMedia; + } + + public void setIsMedia(boolean isMedia) { + this.isMedia = isMedia; + } + + public boolean getIsNameBased() { + return this.isNameBased; + } + + public OperationType getOperationType() { + return this.operationType; + } + + public String getResourceAddress() { + return resourceAddress; + } + + public boolean isForceNameCacheRefresh() { + return forceNameCacheRefresh; + } + + public void setForceNameCacheRefresh(boolean forceNameCacheRefresh) { + this.forceNameCacheRefresh = forceNameCacheRefresh; + } + + public URI getEndpointOverride() { + return this.endpointOverride; + } + + public void setEndpointOverride(URI endpointOverride) { + this.endpointOverride = endpointOverride; + } + + public String getActivityId() { + return this.activityId; + } + + public PartitionKeyRangeIdentity getPartitionKeyRangeIdentity() { + return partitionKeyRangeIdentity; + } + + public void routeTo(PartitionKeyRangeIdentity partitionKeyRangeIdentity) { + this.setPartitionKeyRangeIdentity(partitionKeyRangeIdentity); + } + + public void setPartitionKeyRangeIdentity(PartitionKeyRangeIdentity partitionKeyRangeIdentity) { + this.partitionKeyRangeIdentity = partitionKeyRangeIdentity; + if (partitionKeyRangeIdentity != null) { + this.headers.put(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeIdentity.toHeader()); + } else { + this.headers.remove(HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID); + } + } + + public String getOriginalSessionToken() { + return originalSessionToken; + } + + public void setOriginalSessionToken(String originalSessionToken) { + this.originalSessionToken = originalSessionToken; + } + + public void setDefaultReplicaIndex(Integer defaultReplicaIndex) { + this.defaultReplicaIndex = defaultReplicaIndex; + } + + public Integer getDefaultReplicaIndex() { + return defaultReplicaIndex; + } + + public boolean isChangeFeedRequest() { + return this.headers.containsKey(HttpConstants.HttpHeaders.A_IM); + } + + public boolean isWritingToMaster() { + return operationType.isWriteOperation() && resourceType.isMasterResource(); + } + + public boolean isReadingFromMaster() { + if (resourceType == ResourceType.Offer || + resourceType == ResourceType.Database || + resourceType == ResourceType.User || + resourceType == ResourceType.Permission || + resourceType == ResourceType.Topology || + resourceType == ResourceType.DatabaseAccount || + resourceType == ResourceType.PartitionKeyRange || + (resourceType == ResourceType.DocumentCollection + && (operationType == OperationType.ReadFeed + || operationType == OperationType.Query + || operationType == OperationType.SqlQuery))) { + return true; + } + return false; + } + + public boolean isValidAddress(ResourceType resourceType) { + ResourceType resourceTypeToValidate = ResourceType.Unknown; + + if(resourceType != ResourceType.Unknown) { + resourceTypeToValidate = resourceType; + } else { + if(!this.isFeed) { + resourceTypeToValidate =this.resourceType; + } else { + if(this.resourceType == ResourceType.Database) { + return true; + } else if(this.resourceType == ResourceType.DocumentCollection || + this.resourceType == ResourceType.User) { + resourceTypeToValidate = ResourceType.Database; + } else if(this.resourceType == ResourceType.Permission) { + resourceTypeToValidate = ResourceType.User; + } else if(this.resourceType == ResourceType.Document || + this.resourceType == ResourceType.StoredProcedure || + this.resourceType == ResourceType.UserDefinedFunction || + this.resourceType == ResourceType.Trigger || + this.resourceType == ResourceType.Conflict || + this.resourceType == ResourceType.PartitionKeyRange) { + resourceTypeToValidate = ResourceType.DocumentCollection; + } else if(this.resourceType == ResourceType.Attachment) { + resourceTypeToValidate = ResourceType.Document; + } else { + return false; + } + } + } + + if (this.isNameBased) { + return PathsHelper.validateResourceFullName(resourceType != ResourceType.Unknown ? resourceType : resourceTypeToValidate, this.resourceAddress); + } else { + return PathsHelper.validateResourceId(resourceTypeToValidate, this.resourceId); + } + } + + public void addPreferHeader(String preferHeaderName, String preferHeaderValue) { + String headerToAdd = String.format(PREFER_HEADER_VALUE_FORMAT, preferHeaderName, preferHeaderValue); + String preferHeader = this.headers.get(HttpConstants.HttpHeaders.PREFER); + if(StringUtils.isNotEmpty(preferHeader)) { + preferHeader += PREFER_HEADER_SEPERATOR + headerToAdd; + } else { + preferHeader = headerToAdd; + } + this.headers.put(HttpConstants.HttpHeaders.PREFER, preferHeader); + } + + public static RxDocumentServiceRequest CreateFromResource(RxDocumentServiceRequest request, Resource modifiedResource) { + RxDocumentServiceRequest modifiedRequest; + if (!request.getIsNameBased()) { + modifiedRequest = RxDocumentServiceRequest.create(request.getOperationType(), + request.getResourceId(), + request.getResourceType(), + modifiedResource, + request.headers); + } else { + modifiedRequest = RxDocumentServiceRequest.createFromName(request.getOperationType(), + modifiedResource, + request.getResourceAddress(), + request.getResourceType()); + } + return modifiedRequest; + } + + public void clearRoutingHints() { + this.partitionKeyRangeIdentity = null; + this.requestContext.resolvedPartitionKeyRange = null; + } + + public Flux getContentObservable() { + return contentObservable; + } + + public byte[] getContent() { + return byteContent; + } + + public RxDocumentServiceRequest clone() { + RxDocumentServiceRequest rxDocumentServiceRequest = RxDocumentServiceRequest.create(this.getOperationType(), this.resourceId,this.getResourceType(),this.getHeaders()); + rxDocumentServiceRequest.setContentBytes(this.getContent()); + rxDocumentServiceRequest.setContinuation(this.getContinuation()); + rxDocumentServiceRequest.setDefaultReplicaIndex(this.getDefaultReplicaIndex()); + rxDocumentServiceRequest.setEndpointOverride(this.getEndpointOverride()); + rxDocumentServiceRequest.setForceNameCacheRefresh(this.isForceNameCacheRefresh()); + rxDocumentServiceRequest.setIsMedia(this.getIsMedia()); + rxDocumentServiceRequest.setOriginalSessionToken(this.getOriginalSessionToken()); + rxDocumentServiceRequest.setPartitionKeyRangeIdentity(this.getPartitionKeyRangeIdentity()); + rxDocumentServiceRequest.contentObservable = this.getContentObservable(); + rxDocumentServiceRequest.forceCollectionRoutingMapRefresh = this.forceCollectionRoutingMapRefresh; + rxDocumentServiceRequest.forcePartitionKeyRangeRefresh = this.forcePartitionKeyRangeRefresh; + rxDocumentServiceRequest.UseGatewayMode = this.UseGatewayMode; + rxDocumentServiceRequest.queryString = this.queryString; + rxDocumentServiceRequest.requestContext = this.requestContext; + return rxDocumentServiceRequest; + } + + public void Dispose() { + if (this.isDisposed) { + return; + } + + if (this.byteContent != null) { + this.byteContent = null; + } + + this.isDisposed = true; + } + + private static Map getProperties(Object options) { + if (options == null) { + return null; + } else if (options instanceof RequestOptions) { + return ((RequestOptions) options).getProperties(); + } else if (options instanceof FeedOptions) { + return ((FeedOptions) options).properties(); + } else if (options instanceof ChangeFeedOptions) { + return ((ChangeFeedOptions) options).properties(); + } else { + return null; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceResponse.java new file mode 100644 index 0000000000000..2485ce563e388 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxDocumentServiceResponse.java @@ -0,0 +1,212 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.directconnectivity.Address; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This is core Transport/Connection agnostic response for the Azure Cosmos DB database service. + */ +public class RxDocumentServiceResponse { + private final int statusCode; + private final Map headersMap; + private final StoreResponse storeResponse; + + public RxDocumentServiceResponse(StoreResponse response) { + String[] headerNames = response.getResponseHeaderNames(); + String[] headerValues = response.getResponseHeaderValues(); + + this.headersMap = new HashMap<>(headerNames.length); + + // Gets status code. + this.statusCode = response.getStatus(); + + // Extracts headers. + for (int i = 0; i < headerNames.length; i++) { + this.headersMap.put(headerNames[i], headerValues[i]); + } + + this.storeResponse = response; + } + + public static String getResourceKey(Class c) { + if (c.equals(Conflict.class)) { + return InternalConstants.ResourceKeys.CONFLICTS; + } else if (c.equals(Database.class)) { + return InternalConstants.ResourceKeys.DATABASES; + } else if (Document.class.isAssignableFrom(c)) { + return InternalConstants.ResourceKeys.DOCUMENTS; + } else if (c.equals(DocumentCollection.class)) { + return InternalConstants.ResourceKeys.DOCUMENT_COLLECTIONS; + } else if (c.equals(Offer.class)) { + return InternalConstants.ResourceKeys.OFFERS; + } else if (c.equals(Permission.class)) { + return InternalConstants.ResourceKeys.PERMISSIONS; + } else if (c.equals(Trigger.class)) { + return InternalConstants.ResourceKeys.TRIGGERS; + } else if (c.equals(StoredProcedure.class)) { + return InternalConstants.ResourceKeys.STOREDPROCEDURES; + } else if (c.equals(User.class)) { + return InternalConstants.ResourceKeys.USERS; + } else if (c.equals(UserDefinedFunction.class)) { + return InternalConstants.ResourceKeys.USER_DEFINED_FUNCTIONS; + } else if (c.equals(Address.class)) { + return InternalConstants.ResourceKeys.ADDRESSES; + } else if (c.equals(PartitionKeyRange.class)) { + return InternalConstants.ResourceKeys.PARTITION_KEY_RANGES; + } + + throw new IllegalArgumentException("c"); + } + + public int getStatusCode() { + return this.statusCode; + } + + public Map getResponseHeaders() { + return this.headersMap; + } + + public String getReponseBodyAsString() { + return this.storeResponse.getResponseBody(); + } + + public T getResource(Class c) { + String responseBody = this.getReponseBodyAsString(); + if (StringUtils.isEmpty(responseBody)) + return null; + + T resource = null; + try { + resource = c.getConstructor(String.class).newInstance(responseBody); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException + | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + if(PathsHelper.isPublicResource(resource)) { + BridgeInternal.setAltLink(resource, PathsHelper.generatePathForNameBased(resource, this.getOwnerFullName(),resource.id())); + } + + return resource; + } + + public List getQueryResponse(Class c) { + String responseBody = this.getReponseBodyAsString(); + if (responseBody == null) { + return new ArrayList(); + } + + JsonNode jobject = fromJson(responseBody); + String resourceKey = RxDocumentServiceResponse.getResourceKey(c); + ArrayNode jTokenArray = (ArrayNode) jobject.get(resourceKey); + + // Aggregate queries may return a nested array + ArrayNode innerArray; + while (jTokenArray != null && jTokenArray.size() == 1 && (innerArray = toArrayNode(jTokenArray.get(0))) != null) { + jTokenArray = innerArray; + } + + List queryResults = new ArrayList(); + + if (jTokenArray != null) { + for (int i = 0; i < jTokenArray.size(); ++i) { + JsonNode jToken = jTokenArray.get(i); + // Aggregate on single partition collection may return the aggregated value only + // In that case it needs to encapsulated in a special document + String resourceJson = jToken.isNumber() || jToken.isBoolean() + ? String.format("{\"%s\": %s}", Constants.Properties.AGGREGATE, jToken.asText()) + : toJson(jToken); + T resource = null; + try { + resource = c.getConstructor(String.class).newInstance(resourceJson); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { + throw new IllegalStateException("Failed to instantiate class object.", e); + } + + queryResults.add(resource); + } + } + + return queryResults; + } + + private ArrayNode toArrayNode(JsonNode n) { + if (n.isArray()) { + return (ArrayNode) n; + } else { + return null; + } + } + + private static JsonNode fromJson(String json){ + try { + return Utils.getSimpleObjectMapper().readTree(json); + } catch (IOException e) { + throw new IllegalStateException(String.format("Unable to parse JSON %s", json), e); + } + } + + private static String toJson(Object object){ + try { + return Utils.getSimpleObjectMapper().writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Can't serialize the object into the json string", e); + } + } + + private String getOwnerFullName() { + if (this.headersMap != null) { + return this.headersMap.get(HttpConstants.HttpHeaders.OWNER_FULL_NAME); + } + return null; + } + + public InputStream getContentStream() { + return this.storeResponse.getResponseStream(); + } + + CosmosResponseDiagnostics getCosmosResponseRequestDiagnosticStatistics() { + if (this.storeResponse == null) { + return null; + } + return this.storeResponse.getCosmosResponseDiagnostics(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxGatewayStoreModel.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxGatewayStoreModel.java new file mode 100644 index 0000000000000..a46f076a6a4cd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxGatewayStoreModel.java @@ -0,0 +1,521 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.Callable; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * Used internally to provide functionality to communicate and process response from GATEWAY in the Azure Cosmos DB database service. + */ +class RxGatewayStoreModel implements RxStoreModel { + + private final static int INITIAL_RESPONSE_BUFFER_SIZE = 1024; + private final Logger logger = LoggerFactory.getLogger(RxGatewayStoreModel.class); + private final Map defaultHeaders; + private final HttpClient httpClient; + private final QueryCompatibilityMode queryCompatibilityMode; + private final GlobalEndpointManager globalEndpointManager; + private ConsistencyLevel defaultConsistencyLevel; + private ISessionContainer sessionContainer; + + public RxGatewayStoreModel( + ISessionContainer sessionContainer, + ConsistencyLevel defaultConsistencyLevel, + QueryCompatibilityMode queryCompatibilityMode, + UserAgentContainer userAgentContainer, + GlobalEndpointManager globalEndpointManager, + HttpClient httpClient) { + this.defaultHeaders = new HashMap<>(); + this.defaultHeaders.put(HttpConstants.HttpHeaders.CACHE_CONTROL, + "no-cache"); + this.defaultHeaders.put(HttpConstants.HttpHeaders.VERSION, + HttpConstants.Versions.CURRENT_VERSION); + + if (userAgentContainer == null) { + userAgentContainer = new UserAgentContainer(); + } + + this.defaultHeaders.put(HttpConstants.HttpHeaders.USER_AGENT, userAgentContainer.getUserAgent()); + + if (defaultConsistencyLevel != null) { + this.defaultHeaders.put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, + defaultConsistencyLevel.toString()); + } + + this.defaultConsistencyLevel = defaultConsistencyLevel; + this.globalEndpointManager = globalEndpointManager; + this.queryCompatibilityMode = queryCompatibilityMode; + + this.httpClient = httpClient; + this.sessionContainer = sessionContainer; + } + + private Flux doCreate(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.POST); + } + + private Flux upsert(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.POST); + } + + private Flux read(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.GET); + } + + private Flux replace(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.PUT); + } + + private Flux delete(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.DELETE); + } + + private Flux execute(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.POST); + } + + private Flux readFeed(RxDocumentServiceRequest request) { + return this.performRequest(request, HttpMethod.GET); + } + + private Flux query(RxDocumentServiceRequest request) { + request.getHeaders().put(HttpConstants.HttpHeaders.IS_QUERY, "true"); + + switch (this.queryCompatibilityMode) { + case SqlQuery: + request.getHeaders().put(HttpConstants.HttpHeaders.CONTENT_TYPE, + RuntimeConstants.MediaTypes.SQL); + break; + case Default: + case Query: + default: + request.getHeaders().put(HttpConstants.HttpHeaders.CONTENT_TYPE, + RuntimeConstants.MediaTypes.QUERY_JSON); + break; + } + return this.performRequest(request, HttpMethod.POST); + } + + /** + * Given the request it creates an flux which upon subscription issues HTTP call and emits one RxDocumentServiceResponse. + * + * @param request + * @param method + * @return Flux + */ + public Flux performRequest(RxDocumentServiceRequest request, HttpMethod method) { + + try { + URI uri = getUri(request); + + HttpHeaders httpHeaders = this.getHttpRequestHeaders(request.getHeaders()); + + Flux byteBufObservable = Flux.empty(); + + if (request.getContentObservable() != null) { + byteBufObservable = request.getContentObservable().map(Unpooled::wrappedBuffer); + } else if (request.getContent() != null){ + byteBufObservable = Flux.just(Unpooled.wrappedBuffer(request.getContent())); + } + + + HttpRequest httpRequest = new HttpRequest(method, + uri, + uri.getPort(), + httpHeaders, + byteBufObservable); + + Mono httpResponseMono = this.httpClient.send(httpRequest); + + return toDocumentServiceResponse(httpResponseMono, request); + + } catch (Exception e) { + return Flux.error(e); + } + } + + private HttpHeaders getHttpRequestHeaders(Map headers) { + HttpHeaders httpHeaders = new HttpHeaders(this.defaultHeaders.size()); + // Add default headers. + for (Entry entry : this.defaultHeaders.entrySet()) { + if (!headers.containsKey(entry.getKey())) { + // populate default header only if there is no overwrite by the request header + httpHeaders.set(entry.getKey(), entry.getValue()); + } + } + + // Add override headers. + if (headers != null) { + for (Entry entry : headers.entrySet()) { + if (entry.getValue() == null) { + // netty doesn't allow setting null value in header + httpHeaders.set(entry.getKey(), ""); + } else { + httpHeaders.set(entry.getKey(), entry.getValue()); + } + } + } + return httpHeaders; + } + + private URI getUri(RxDocumentServiceRequest request) throws URISyntaxException { + URI rootUri = request.getEndpointOverride(); + if (rootUri == null) { + if (request.getIsMedia()) { + // For media read request, always use the write endpoint. + rootUri = this.globalEndpointManager.getWriteEndpoints().get(0).toURI(); + } else { + rootUri = this.globalEndpointManager.resolveServiceEndpoint(request).toURI(); + } + } + + String path = PathsHelper.generatePath(request.getResourceType(), request, request.isFeed); + if(request.getResourceType().equals(ResourceType.DatabaseAccount)) { + path = StringUtils.EMPTY; + } + + return new URI("https", + null, + rootUri.getHost(), + rootUri.getPort(), + ensureSlashPrefixed(path), + null, // Query string not used. + null); + } + + private String ensureSlashPrefixed(String path) { + if (path == null) { + return path; + } + + if (path.startsWith("/")) { + return path; + } + + return "/" + path; + } + + private Mono toString(Flux contentObservable) { + return contentObservable + .reduce( + new ByteArrayOutputStream(INITIAL_RESPONSE_BUFFER_SIZE), + (out, bb) -> { + try { + bb.readBytes(out, bb.readableBytes()); + return out; + } + catch (IOException e) { + throw new RuntimeException(e); + } + }) + .map(out -> new String(out.toByteArray(), StandardCharsets.UTF_8)); + } + + /** + * Transforms the reactor netty's client response Observable to RxDocumentServiceResponse Observable. + * + * + * Once the customer code subscribes to the observable returned by the CRUD APIs, + * the subscription goes up till it reaches the source reactor netty's observable, and at that point the HTTP invocation will be made. + * + * @param httpResponseMono + * @param request + * @return {@link Flux} + */ + private Flux toDocumentServiceResponse(Mono httpResponseMono, + RxDocumentServiceRequest request) { + + if (request.getIsMedia()) { + return httpResponseMono.flatMap(httpResponse -> { + + // header key/value pairs + HttpHeaders httpResponseHeaders = httpResponse.headers(); + int httpResponseStatus = httpResponse.statusCode(); + + Flux inputStreamObservable; + + if (request.getOperationType() == OperationType.Delete) { + // for delete we don't expect any body + inputStreamObservable = Flux.just(IOUtils.toInputStream("", StandardCharsets.UTF_8)); + } else { + // transforms the ByteBufFlux to Flux + inputStreamObservable = httpResponse + .body() + .flatMap(byteBuf -> + Flux.just(IOUtils.toInputStream(byteBuf.toString(StandardCharsets.UTF_8), StandardCharsets.UTF_8))); + } + + return inputStreamObservable + .flatMap(contentInputStream -> { + try { + // If there is any error in the header response this throws exception + // TODO: potential performance improvement: return Observable.error(exception) on failure instead of throwing Exception + validateOrThrow(request, + HttpResponseStatus.valueOf(httpResponseStatus), + httpResponseHeaders, + null, + contentInputStream); + + // transforms to Observable + StoreResponse rsp = new StoreResponse(httpResponseStatus, HttpUtils + .unescape(httpResponseHeaders.toMap().entrySet()), contentInputStream); + return Flux.just(rsp); + } catch (Exception e) { + return Flux.error(e); + } + }).single(); + + }).map(RxDocumentServiceResponse::new).flux(); + + } else { + return httpResponseMono.flatMap(httpResponse -> { + + // header key/value pairs + HttpHeaders httpResponseHeaders = httpResponse.headers(); + int httpResponseStatus = httpResponse.statusCode(); + + Flux contentObservable; + + if (request.getOperationType() == OperationType.Delete) { + // for delete we don't expect any body + contentObservable = Flux.just(StringUtils.EMPTY); + } else { + // transforms the ByteBufFlux to Flux + contentObservable = toString(httpResponse.body()).flux(); + } + + return contentObservable + .flatMap(content -> { + try { + // If there is any error in the header response this throws exception + // TODO: potential performance improvement: return Observable.error(exception) on failure instead of throwing Exception + validateOrThrow(request, HttpResponseStatus.valueOf(httpResponseStatus), httpResponseHeaders, content, null); + + // transforms to Observable + StoreResponse rsp = new StoreResponse(httpResponseStatus, + HttpUtils.unescape(httpResponseHeaders.toMap().entrySet()), + content); + return Flux.just(rsp); + } catch (Exception e) { + return Flux.error(e); + } + }).single(); + + }).map(RxDocumentServiceResponse::new) + .onErrorResume(throwable -> { + if (!(throwable instanceof Exception)) { + // fatal error + logger.error("Unexpected failure {}", throwable.getMessage(), throwable); + return Mono.error(throwable); + } + + Exception exception = (Exception) throwable; + if (!(exception instanceof CosmosClientException)) { + // wrap in CosmosClientException + logger.error("Network failure", exception); + CosmosClientException dce = BridgeInternal.createCosmosClientException(0, exception); + BridgeInternal.setRequestHeaders(dce, request.getHeaders()); + return Mono.error(dce); + } + + return Mono.error(exception); + }).flux(); + } + } + + private void validateOrThrow(RxDocumentServiceRequest request, HttpResponseStatus status, HttpHeaders headers, String body, + InputStream inputStream) throws CosmosClientException { + + int statusCode = status.code(); + + if (statusCode >= HttpConstants.StatusCodes.MINIMUM_STATUSCODE_AS_ERROR_GATEWAY) { + if (body == null && inputStream != null) { + try { + body = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + } catch (IOException e) { + logger.error("Failed to get content from the http response", e); + CosmosClientException dce = BridgeInternal.createCosmosClientException(0, e); + BridgeInternal.setRequestHeaders(dce, request.getHeaders()); + throw dce; + } finally { + IOUtils.closeQuietly(inputStream); + } + } + + String statusCodeString = status.reasonPhrase() != null + ? status.reasonPhrase().replace(" ", "") + : ""; + CosmosError cosmosError; + cosmosError = (StringUtils.isNotEmpty(body)) ? BridgeInternal.createCosmosError(body) : new CosmosError(); + cosmosError = new CosmosError(statusCodeString, + String.format("%s, StatusCode: %s", cosmosError.getMessage(), statusCodeString), + cosmosError.getPartitionedQueryExecutionInfo()); + + CosmosClientException dce = BridgeInternal.createCosmosClientException(statusCode, cosmosError, headers.toMap()); + BridgeInternal.setRequestHeaders(dce, request.getHeaders()); + throw dce; + } + } + + private Flux invokeAsyncInternal(RxDocumentServiceRequest request) { + switch (request.getOperationType()) { + case Create: + return this.doCreate(request); + case Upsert: + return this.upsert(request); + case Delete: + return this.delete(request); + case ExecuteJavaScript: + return this.execute(request); + case Read: + return this.read(request); + case ReadFeed: + return this.readFeed(request); + case Replace: + return this.replace(request); + case SqlQuery: + case Query: + return this.query(request); + default: + throw new IllegalStateException("Unknown operation type " + request.getOperationType()); + } + } + + private Flux invokeAsync(RxDocumentServiceRequest request) { + Callable> funcDelegate = () -> invokeAsyncInternal(request).single(); + return BackoffRetryUtility.executeRetry(funcDelegate, new WebExceptionRetryPolicy()).flux(); + } + + @Override + public Flux processMessage(RxDocumentServiceRequest request) { + this.applySessionToken(request); + + Flux responseObs = invokeAsync(request); + + return responseObs.onErrorResume( + e -> { + CosmosClientException dce = Utils.as(e, CosmosClientException.class); + + if (dce == null) { + logger.error("unexpected failure {}", e.getMessage(), e); + return Flux.error(e); + } + + if ((!ReplicatedResourceClientUtils.isMasterResource(request.getResourceType())) && + (dce.statusCode() == HttpConstants.StatusCodes.PRECONDITION_FAILED || + dce.statusCode() == HttpConstants.StatusCodes.CONFLICT || + ( + dce.statusCode() == HttpConstants.StatusCodes.NOTFOUND && + !Exceptions.isSubStatusCode(dce, + HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)))) { + this.captureSessionToken(request, dce.responseHeaders()); + } + + return Flux.error(dce); + } + ).map(response -> + { + this.captureSessionToken(request, response.getResponseHeaders()); + return response; + } + ); + } + + private void captureSessionToken(RxDocumentServiceRequest request, Map responseHeaders) { + if (request.getResourceType() == ResourceType.DocumentCollection && request.getOperationType() == OperationType.Delete) { + String resourceId; + if (request.getIsNameBased()) { + resourceId = responseHeaders.get(HttpConstants.HttpHeaders.OWNER_ID); + } else { + resourceId = request.getResourceId(); + } + this.sessionContainer.clearTokenByResourceId(resourceId); + } else { + this.sessionContainer.setSessionToken(request, responseHeaders); + } + } + + private void applySessionToken(RxDocumentServiceRequest request) { + Map headers = request.getHeaders(); + + if (headers != null && + !Strings.isNullOrEmpty(request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN))) { + if (ReplicatedResourceClientUtils.isMasterResource(request.getResourceType())) { + request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + return; //User is explicitly controlling the session. + } + + String requestConsistencyLevel = headers.get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL); + + boolean sessionConsistency = + this.defaultConsistencyLevel == ConsistencyLevel.SESSION || + (!Strings.isNullOrEmpty(requestConsistencyLevel) + && Strings.areEqual(requestConsistencyLevel, ConsistencyLevel.SESSION.toString())); + + if (!sessionConsistency || ReplicatedResourceClientUtils.isMasterResource(request.getResourceType())) { + return; // Only apply the session token in case of session consistency and when resource is not a master resource + } + + //Apply the ambient session. + String sessionToken = this.sessionContainer.resolveGlobalSessionToken(request); + + if (!Strings.isNullOrEmpty(sessionToken)) { + headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, sessionToken); + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxStoreModel.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxStoreModel.java new file mode 100644 index 0000000000000..38fae2f6c0ea7 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/RxStoreModel.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import reactor.core.publisher.Flux; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface RxStoreModel { + + /** + * Given the request, it returns an Observable of the response. + * + * The Observable upon subscription will execute the request and upon successful execution request returns a single {@link RxDocumentServiceResponse}. + * If the execution of the request fails it returns an error. + * + * @param request + * @return + */ + Flux processMessage(RxDocumentServiceRequest request); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionContainer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionContainer.java new file mode 100644 index 0000000000000..dc1f91bf57f22 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionContainer.java @@ -0,0 +1,313 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosClientException; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; + +/** + * Used internally to cache the collections' session tokens in the Azure Cosmos DB database service. + */ +public final class SessionContainer implements ISessionContainer { + private final Logger logger = LoggerFactory.getLogger(SessionContainer.class); + + /** + * SESSION token cache that maps collection ResourceID to session tokens + */ + private final ConcurrentHashMap> collectionResourceIdToSessionTokens = new ConcurrentHashMap<>(); + /** + * Collection ResourceID cache that maps collection name to collection ResourceID + * When collection name is provided instead of self-link, this is used in combination with + * collectionResourceIdToSessionTokens to retrieve the session token for the collection by name + */ + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock(); + private final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock(); + + private final ConcurrentHashMap collectionNameToCollectionResourceId = new ConcurrentHashMap<>(); + private final ConcurrentHashMap collectionResourceIdToCollectionName = new ConcurrentHashMap<>(); + private final String hostName; + + public SessionContainer(final String hostName) { + this.hostName = hostName; + } + + public String getHostName() { + return this.hostName; + } + + public String getSessionToken(String collectionLink) { + + PathInfo pathInfo = new PathInfo(false, null, null, false); + ConcurrentHashMap partitionKeyRangeIdToTokenMap = null; + if (PathsHelper.tryParsePathSegments(collectionLink, pathInfo, null)) { + Long UniqueDocumentCollectionId = null; + if (pathInfo.isNameBased) { + String collectionName = PathsHelper.getCollectionPath(pathInfo.resourceIdOrFullName); + UniqueDocumentCollectionId = this.collectionNameToCollectionResourceId.get(collectionName); + } else { + ResourceId resourceId = ResourceId.parse(pathInfo.resourceIdOrFullName); + if (resourceId.getDocumentCollection() != 0) { + UniqueDocumentCollectionId = resourceId.getUniqueDocumentCollectionId(); + } + } + + if (UniqueDocumentCollectionId != null) { + partitionKeyRangeIdToTokenMap = this.collectionResourceIdToSessionTokens.get(UniqueDocumentCollectionId); + } + } + + if (partitionKeyRangeIdToTokenMap == null) { + return StringUtils.EMPTY; + } + + return SessionContainer.getCombinedSessionToken(partitionKeyRangeIdToTokenMap); + } + + private ConcurrentHashMap getPartitionKeyRangeIdToTokenMap(RxDocumentServiceRequest request) { + return getPartitionKeyRangeIdToTokenMap(request.getIsNameBased(), request.getResourceId(), request.getResourceAddress()); + } + + private ConcurrentHashMap getPartitionKeyRangeIdToTokenMap(boolean isNameBased, String rId, String resourceAddress) { + ConcurrentHashMap rangeIdToTokenMap = null; + if (!isNameBased) { + if (!StringUtils.isEmpty(rId)) { + ResourceId resourceId = ResourceId.parse(rId); + if (resourceId.getDocumentCollection() != 0) { + rangeIdToTokenMap = + this.collectionResourceIdToSessionTokens.get(resourceId.getUniqueDocumentCollectionId()); + } + } + } else { + String collectionName = Utils.getCollectionName(resourceAddress); + if (!StringUtils.isEmpty(collectionName) && this.collectionNameToCollectionResourceId.containsKey(collectionName)) { + rangeIdToTokenMap = this.collectionResourceIdToSessionTokens.get( + this.collectionNameToCollectionResourceId.get(collectionName)); + } + } + return rangeIdToTokenMap; + } + + + public String resolveGlobalSessionToken(RxDocumentServiceRequest request) { + ConcurrentHashMap partitionKeyRangeIdToTokenMap = this.getPartitionKeyRangeIdToTokenMap(request); + if (partitionKeyRangeIdToTokenMap != null) { + return SessionContainer.getCombinedSessionToken(partitionKeyRangeIdToTokenMap); + } + + return StringUtils.EMPTY; + } + + @Override + public ISessionToken resolvePartitionLocalSessionToken(RxDocumentServiceRequest request, String partitionKeyRangeId) { + return SessionTokenHelper.resolvePartitionLocalSessionToken(request, + partitionKeyRangeId, + this.getPartitionKeyRangeIdToTokenMap(request)); + } + + @Override + public void clearTokenByCollectionFullName(String collectionFullName) { + if (!Strings.isNullOrEmpty(collectionFullName)) { + String collectionName = PathsHelper.getCollectionPath(collectionFullName); + this.writeLock.lock(); + try { + if (this.collectionNameToCollectionResourceId.containsKey(collectionName)) { + Long rid = this.collectionNameToCollectionResourceId.get(collectionName); + this.collectionResourceIdToSessionTokens.remove(rid); + this.collectionResourceIdToCollectionName.remove(rid); + this.collectionNameToCollectionResourceId.remove(collectionName); + } + } finally { + this.writeLock.unlock(); + } + } + } + + @Override + public void clearTokenByResourceId(String resourceId) { + if (!StringUtils.isEmpty(resourceId)) { + ResourceId resource = ResourceId.parse(resourceId); + if (resource.getDocumentCollection() != 0) { + Long rid = resource.getUniqueDocumentCollectionId(); + this.writeLock.lock(); + try { + if (this.collectionResourceIdToCollectionName.containsKey(rid)) { + String collectionName = this.collectionResourceIdToCollectionName.get(rid); + this.collectionResourceIdToSessionTokens.remove(rid); + this.collectionResourceIdToCollectionName.remove(rid); + this.collectionNameToCollectionResourceId.remove(collectionName); + } + } finally { + this.writeLock.unlock(); + } + } + } + } + + @Override + public void setSessionToken(RxDocumentServiceRequest request, Map responseHeaders) { + String token = responseHeaders.get(HttpConstants.HttpHeaders.SESSION_TOKEN); + + if (!Strings.isNullOrEmpty(token)) { + ValueHolder resourceId = ValueHolder.initialize(null); + ValueHolder collectionName = ValueHolder.initialize(null); + + if (shouldUpdateSessionToken(request, responseHeaders, resourceId, collectionName)) { + this.setSessionToken(resourceId.v, collectionName.v, token); + } + } + } + + @Override + public void setSessionToken(String collectionRid, String collectionFullName, Map responseHeaders) { + ResourceId resourceId = ResourceId.parse(collectionRid); + String collectionName = PathsHelper.getCollectionPath(collectionFullName); + String token = responseHeaders.get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (!Strings.isNullOrEmpty(token)) { + this.setSessionToken(resourceId, collectionName, token); + } + } + + private void setSessionToken(ResourceId resourceId, String collectionName, String token) { + String partitionKeyRangeId; + ISessionToken parsedSessionToken; + + String[] tokenParts = StringUtils.split(token, ':'); + partitionKeyRangeId = tokenParts[0]; + parsedSessionToken = SessionTokenHelper.parse(tokenParts[1]); + + logger.trace("UPDATE SESSION token {} {} {}", resourceId.getUniqueDocumentCollectionId(), collectionName, parsedSessionToken); + + boolean isKnownCollection; + + this.readLock.lock(); + try { + isKnownCollection = this.collectionNameToCollectionResourceId.containsKey(collectionName) && + this.collectionResourceIdToCollectionName.containsKey(resourceId.getUniqueDocumentCollectionId()) && + this.collectionNameToCollectionResourceId.get(collectionName) == resourceId.getUniqueDocumentCollectionId() && + this.collectionResourceIdToCollectionName.get(resourceId.getUniqueDocumentCollectionId()).equals(collectionName); + if (isKnownCollection) { + this.addSessionToken(resourceId, partitionKeyRangeId, parsedSessionToken); + } + } finally { + this.readLock.unlock(); + } + + if (!isKnownCollection) { + this.writeLock.lock(); + try { + if (collectionName != null && resourceId.getUniqueDocumentCollectionId() != 0) { + this.collectionNameToCollectionResourceId.compute(collectionName, (k, v) -> resourceId.getUniqueDocumentCollectionId()); + this.collectionResourceIdToCollectionName.compute(resourceId.getUniqueDocumentCollectionId(), (k, v) -> collectionName); + } + addSessionToken(resourceId, partitionKeyRangeId, parsedSessionToken); + } finally { + this.writeLock.unlock(); + } + } + } + + private void addSessionToken(ResourceId resourceId, String partitionKeyRangeId, ISessionToken parsedSessionToken) { + this.collectionResourceIdToSessionTokens.compute( + resourceId.getUniqueDocumentCollectionId(), (k, existingTokens) -> { + if (existingTokens == null) { + ConcurrentHashMap tokens = new ConcurrentHashMap<>(); + tokens.put(partitionKeyRangeId, parsedSessionToken); + return tokens; + } + + existingTokens.merge(partitionKeyRangeId, parsedSessionToken, (existingSessionTokens, newSessionToken) -> { + try { + if (existingSessionTokens == null) { + return newSessionToken; + } + + return existingSessionTokens.merge(newSessionToken); + } catch (CosmosClientException e) { + throw new IllegalStateException(e); + } + }); + + return existingTokens; + } + ); + } + + private static String getCombinedSessionToken(ConcurrentHashMap tokens) { + StringBuilder result = new StringBuilder(); + if (tokens != null) { + for (Iterator> iterator = tokens.entrySet().iterator(); iterator.hasNext(); ) { + Entry entry = iterator.next(); + result = result.append(entry.getKey()).append(":").append(entry.getValue().convertToString()); + if (iterator.hasNext()) { + result = result.append(","); + } + } + } + + return result.toString(); + } + + private static boolean shouldUpdateSessionToken( + RxDocumentServiceRequest request, + Map responseHeaders, + ValueHolder resourceId, + ValueHolder collectionName) { + resourceId.v = null; + String ownerFullName = responseHeaders.get(HttpConstants.HttpHeaders.OWNER_FULL_NAME); + if (Strings.isNullOrEmpty(ownerFullName)) ownerFullName = request.getResourceAddress(); + + collectionName.v = PathsHelper.getCollectionPath(ownerFullName); + String resourceIdString; + + if (!request.getIsNameBased()) { + resourceIdString = request.getResourceId(); + } else { + resourceIdString = responseHeaders.get(HttpConstants.HttpHeaders.OWNER_ID); + if (Strings.isNullOrEmpty(resourceIdString)) resourceIdString = request.getResourceId(); + } + + if (!Strings.isNullOrEmpty(resourceIdString)) { + resourceId.v = ResourceId.parse(resourceIdString); + + if (resourceId.v.getDocumentCollection() != 0 && + collectionName != null && + !ReplicatedResourceClientUtils.isReadingFromMaster(request.getResourceType(), request.getOperationType())) { + return true; + } + } + + return false; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionTokenHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionTokenHelper.java new file mode 100644 index 0000000000000..5926de23533e4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/SessionTokenHelper.java @@ -0,0 +1,183 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.InternalServerErrorException; +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; + +/** + * Used internally to provides helper functions to work with session tokens in the Azure Cosmos DB database service. + */ +public class SessionTokenHelper { + + public static void setOriginalSessionToken(RxDocumentServiceRequest request, String originalSessionToken) { + if (request == null) { + throw new IllegalArgumentException("request is null"); + } + + if (originalSessionToken == null) { + request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } else { + request.getHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, originalSessionToken); + } + } + + public static void setPartitionLocalSessionToken(RxDocumentServiceRequest request, ISessionContainer sessionContainer) throws CosmosClientException { + String originalSessionToken = request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + String partitionKeyRangeId = request.requestContext.resolvedPartitionKeyRange.id(); + + + if (Strings.isNullOrEmpty(partitionKeyRangeId)) { + // AddressCache/address resolution didn't produce partition key range id. + // In this case it is a bug. + throw new InternalServerErrorException(RMResources.PartitionKeyRangeIdAbsentInContext); + } + + if (StringUtils.isNotEmpty(originalSessionToken)) { + ISessionToken sessionToken = getLocalSessionToken(request, originalSessionToken, partitionKeyRangeId); + request.requestContext.sessionToken = sessionToken; + } else { + // use ambient session token. + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, partitionKeyRangeId); + request.requestContext.sessionToken = sessionToken; + } + + if (request.requestContext.sessionToken == null) { + request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } else { + request.getHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, + String.format("%1s:%2s", partitionKeyRangeId, request.requestContext.sessionToken.convertToString())); + } + } + + private static ISessionToken getLocalSessionToken( + RxDocumentServiceRequest request, + String globalSessionToken, + String partitionKeyRangeId) throws CosmosClientException { + + if (partitionKeyRangeId == null || partitionKeyRangeId.isEmpty()) { + // AddressCache/address resolution didn't produce partition key range id. + // In this case it is a bug. + throw new IllegalStateException("Partition key range Id is absent in the context."); + } + + // Convert global session token to local - there's no point in sending global token over the wire to the backend. + // Global session token is comma separated array of : pairs. For example: + // 2:425344,748:2341234,99:42344 + // Local session token is single : pair. + // Backend only cares about pair which relates to the range owned by the partition. + String[] localTokens = StringUtils.split(globalSessionToken, ","); + Set partitionKeyRangeSet = new HashSet<>(); + partitionKeyRangeSet.add(partitionKeyRangeId); + + ISessionToken highestSessionToken = null; + + if (request.requestContext.resolvedPartitionKeyRange != null && request.requestContext.resolvedPartitionKeyRange.getParents() != null) { + partitionKeyRangeSet.addAll(request.requestContext.resolvedPartitionKeyRange.getParents()); + } + + for (String localToken : localTokens) { + String[] items = StringUtils.split(localToken, ":"); + if (items.length != 2) { + throw new BadRequestException(String.format(RMResources.InvalidSessionToken, partitionKeyRangeId)); + } + + ISessionToken parsedSessionToken = SessionTokenHelper.parse(items[1]); + + if (partitionKeyRangeSet.contains(items[0])) { + + if (highestSessionToken == null) { + highestSessionToken = parsedSessionToken; + } else { + highestSessionToken = highestSessionToken.merge(parsedSessionToken); + } + + } + } + + return highestSessionToken; + } + + static ISessionToken resolvePartitionLocalSessionToken(RxDocumentServiceRequest request, + String partitionKeyRangeId, + ConcurrentHashMap rangeIdToTokenMap) { + if (rangeIdToTokenMap != null) { + if (rangeIdToTokenMap.containsKey(partitionKeyRangeId)) { + return rangeIdToTokenMap.get(partitionKeyRangeId); + } else { + Collection parents = request.requestContext.resolvedPartitionKeyRange.getParents(); + if (parents != null) { + List parentsList = new ArrayList<>(parents); + for (int i = parentsList.size() - 1; i >= 0; i--) { + String parentId = parentsList.get(i); + if (rangeIdToTokenMap.containsKey(parentId)) { + return rangeIdToTokenMap.get(parentId); + } + } + } + } + } + + return null; + } + + public static ISessionToken parse(String sessionToken) { + ValueHolder partitionKeyRangeSessionToken = ValueHolder.initialize(null); + + if (SessionTokenHelper.tryParse(sessionToken, partitionKeyRangeSessionToken)) { + return partitionKeyRangeSessionToken.v; + } else { + throw new RuntimeException(new BadRequestException(String.format(RMResources.InvalidSessionToken, sessionToken))); + } + } + + static boolean tryParse(String sessionToken, ValueHolder parsedSessionToken) { + parsedSessionToken.v = null; + if (!Strings.isNullOrEmpty(sessionToken)) { + String[] sessionTokenSegments = StringUtils.split(sessionToken,":"); + return VectorSessionToken.tryCreate(sessionTokenSegments[sessionTokenSegments.length - 1], parsedSessionToken); + } else { + return false; + } + } + + public static void validateAndRemoveSessionToken(RxDocumentServiceRequest request) throws CosmosClientException { + String sessionToken = request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (!Strings.isNullOrEmpty(sessionToken)) { + getLocalSessionToken(request, sessionToken, StringUtils.EMPTY); + request.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedure.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedure.java new file mode 100644 index 0000000000000..59e60d6594be4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedure.java @@ -0,0 +1,82 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; + +/** + * Represents a stored procedure in the Azure Cosmos DB database service. + *

    + * Cosmos DB allows stored procedures to be executed in the storage tier, directly against a document collection. The + * script gets executed under ACID transactions on the primary storage partition of the specified collection. For + * additional details, refer to the server-side JavaScript API documentation. + */ +public class StoredProcedure extends Resource { + + /** + * Constructor. + */ + public StoredProcedure() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the stored procedure. + */ + public StoredProcedure(String jsonString) { + super(jsonString); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current stored procedure + */ + public StoredProcedure id(String id){ + super.id(id); + return this; + } + + /** + * Get the body of the stored procedure. + * + * @return the body of the stored procedure. + */ + public String getBody() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the stored procedure. + * + * @param body the body of the stored procedure. + */ + public void setBody(String body) { + BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedureResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedureResponse.java new file mode 100644 index 0000000000000..7ccac84529036 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/StoredProcedureResponse.java @@ -0,0 +1,154 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +/** + * Represents the response returned from a stored procedure in the Azure Cosmos DB database service. + * Wraps the response body and headers. + */ +public final class StoredProcedureResponse { + private final static Logger logger = LoggerFactory.getLogger(StoredProcedureResponse.class); + private final RxDocumentServiceResponse response; + + /** + * Constructs StoredProcedureResponse. + * + * @param response the document service response. + */ + public StoredProcedureResponse(RxDocumentServiceResponse response) { + this.response = response; + } + + /** + * Gets the Activity ID of the request. + * + * @return the activity id. + */ + public String getActivityId() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.ACTIVITY_ID); + } + + /** + * Gets the token for use with session consistency requests. + * + * @return the session token. + */ + public String getSessionToken() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + + /** + * Gets the request completion status code. + * + * @return the status code. + */ + public int getStatusCode() { + return this.response.getStatusCode(); + } + + /** + * Gets the maximum size limit for this entity (in megabytes (MB) for server resources and in count for master + * resources). + * + * @return the max resource quota. + */ + public String getMaxResourceQuota() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.MAX_RESOURCE_QUOTA); + } + + /** + * Gets the current size of this entity (in megabytes (MB) for server resources and in count for master resources) + * + * @return the current resource quota usage. + */ + public String getCurrentResourceQuotaUsage() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.CURRENT_RESOURCE_QUOTA_USAGE); + } + + /** + * Gets the number of normalized requests charged. + * + * @return the request charge. + */ + public double getRequestCharge() { + String value = this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.REQUEST_CHARGE); + try { + return Double.valueOf(value); + } catch (NumberFormatException e) { + logger.warn("INVALID x-ms-request-charge value {}.", value); + return 0; + } + } + + /** + * Gets the headers associated with the response. + * + * @return the response headers. + */ + public Map getResponseHeaders() { + return this.response.getResponseHeaders(); + } + + /** + * Gets the response of a stored procedure, serialized into a document. + * + * @return the response as a document. + */ + public Document getResponseAsDocument() { + return this.response.getResource(Document.class); + } + + /** + * Gets the response of a stored procedure as a string. + * + * @return the response as a string. + */ + public String getResponseAsString() { + return this.response.getReponseBodyAsString(); + } + + /** + * Gets the output from stored procedure console.log() statements. + * + * @return the output string from the stored procedure console.log() statements. + */ + public String getScriptLog() { + return this.response.getResponseHeaders().get(HttpConstants.HttpHeaders.SCRIPT_LOG_RESULTS); + } + + /** + * Gets the request diagnostic statics for execution of stored procedure. + * + * @return request diagnostic statistics for execution of stored procedure. + */ + public CosmosResponseDiagnostics getCosmosResponseDiagnostics() { + return this.response.getCosmosResponseRequestDiagnosticStatistics(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Strings.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Strings.java new file mode 100644 index 0000000000000..7f03efc4d0e2c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Strings.java @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import org.apache.commons.lang3.StringUtils; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class Strings { + public static final String Emtpy = ""; + + public static boolean isNullOrWhiteSpace(String str) { + return StringUtils.isEmpty(str) || StringUtils.isWhitespace(str); + } + public static boolean isNullOrEmpty(String str) { + return StringUtils.isEmpty(str); + } + + public static String toString(boolean value) { + return Boolean.toString(value); + } + + public static String toString(int value) { + return Integer.toString(value); + } + + public static boolean areEqual(String str1, String str2) { + return StringUtils.equals(str1, str2); + } + + public static boolean areEqualIgnoreCase(String str1, String str2) { + return StringUtils.equalsIgnoreCase(str1, str2); + } + + public static boolean containsIgnoreCase(String str1, String str2) { + return StringUtils.containsIgnoreCase(str1, str2); + } + + public static int compare(String str1, String str2) { + return StringUtils.compare(str1, str2); + } + + public static String toCamelCase(String str) { + if (isNullOrEmpty(str)) { + return str; + } + + return str.substring(0, 1).toUpperCase() + str.substring(1, str.length()).toLowerCase(); + } + + public static String fromCamelCaseToUpperCase(String str) { + if (str == null) { + return null; + } + + StringBuilder result = new StringBuilder(str); + + int i = 1; + while (i < result.length()) { + if (Character.isUpperCase(result.charAt(i))) { + result.insert(i, '_'); + i += 2; + } else { + result.replace(i, i + 1, Character.toString(Character.toUpperCase(result.charAt(i)))); + i ++; + } + } + + return result.toString(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/TestConfigurations.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/TestConfigurations.java new file mode 100644 index 0000000000000..ce78c7d99d395 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/TestConfigurations.java @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.google.common.base.Strings; +import org.apache.commons.lang3.StringUtils; + +/** + * Contains the configurations for tests. + * + * For running tests, you can pass a customized endpoint configuration in one of the following + * ways: + *

      + *
    • -DACCOUNT_KEY="[your-key]" -ACCOUNT_HOST="[your-endpoint]" as JVM + * command-line option.
    • + *
    • You can set ACCOUNT_KEY and ACCOUNT_HOST as environment variables.
    • + *
    + * + * If none of the above is set, emulator endpoint will be used. + */ +public final class TestConfigurations { + // REPLACE MASTER_KEY and HOST with values from your Azure Cosmos DB account. + // The default values are credentials of the local emulator, which are not used in any production environment. + // + public static String MASTER_KEY = + System.getProperty("ACCOUNT_KEY", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_KEY")), + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==")); + + public static String HOST = + System.getProperty("ACCOUNT_HOST", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_HOST")), + "https://localhost:443/")); + + public static String CONSISTENCY = + System.getProperty("ACCOUNT_CONSISTENCY", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("ACCOUNT_CONSISTENCY")), "Strong")); + + public static String PREFERRED_LOCATIONS = + System.getProperty("PREFERRED_LOCATIONS", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("PREFERRED_LOCATIONS")), null)); + + public static String MAX_RETRY_LIMIT = + System.getProperty("MAX_RETRY_LIMIT", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("MAX_RETRY_LIMIT")), + "2")); + + public static String DESIRED_CONSISTENCIES = + System.getProperty("DESIRED_CONSISTENCIES", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("DESIRED_CONSISTENCIES")), + null)); + + public static String PROTOCOLS = + System.getProperty("PROTOCOLS", + StringUtils.defaultString(Strings.emptyToNull( + System.getenv().get("PROTOCOLS")), + null)); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Trigger.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Trigger.java new file mode 100644 index 0000000000000..7916cffa1c8ab --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Trigger.java @@ -0,0 +1,125 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import org.apache.commons.lang3.StringUtils; + +/** + * Represents a trigger in the Azure Cosmos DB database service. + *

    + * Cosmos DB supports pre and post triggers defined in JavaScript to be executed on creates, updates and deletes. For + * additional details, refer to the server-side JavaScript API documentation. + */ +public class Trigger extends Resource { + + /** + * Constructor. + */ + public Trigger() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the trigger. + */ + public Trigger(String jsonString) { + super(jsonString); + } + + /** + * Get the body of the trigger. + * + * @return the body of the trigger. + */ + public String getBody() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the trigger. + * + * @param body the body of the trigger. + */ + public void setBody(String body) { + BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + } + + /** + * Get the type of the trigger. + * + * @return the trigger type. + */ + public TriggerType getTriggerType() { + TriggerType result = TriggerType.PRE; + try { + result = TriggerType.valueOf( + StringUtils.upperCase(super.getString(Constants.Properties.TRIGGER_TYPE))); + } catch (IllegalArgumentException e) { + // ignore the exception and return the default + this.getLogger().warn("INVALID triggerType value {}.", super.getString(Constants.Properties.TRIGGER_TYPE)); + } + return result; + } + + /** + * Set the type of the resource. + * + * @param triggerType the trigger type. + */ + public void setTriggerType(TriggerType triggerType) { + BridgeInternal.setProperty(this, Constants.Properties.TRIGGER_TYPE, triggerType.toString()); + } + + /** + * Get the operation type of the trigger. + * + * @return the trigger operation. + */ + public TriggerOperation getTriggerOperation() { + TriggerOperation result = TriggerOperation.CREATE; + try { + result = TriggerOperation.valueOf( + StringUtils.upperCase(super.getString(Constants.Properties.TRIGGER_OPERATION))); + } catch (IllegalArgumentException e) { + // ignore the exception and return the default + this.getLogger().warn("INVALID triggerOperation value {}.", super.getString(Constants.Properties.TRIGGER_OPERATION)); + } + return result; + } + + /** + * Set the operation type of the trigger. + * + * @param triggerOperation the trigger operation. + */ + public void setTriggerOperation(TriggerOperation triggerOperation) { + BridgeInternal.setProperty(this, Constants.Properties.TRIGGER_OPERATION, triggerOperation.toString()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Undefined.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Undefined.java new file mode 100644 index 0000000000000..82bdf0cb88b42 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Undefined.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.JsonSerializable; + +/** + * Represents the 'Undefined' partition key in the Azure Cosmos DB database service. + */ +public class Undefined extends JsonSerializable { + + private final static Undefined value = new Undefined(); + + /** + * Constructor. CREATE a new instance of the Undefined object. + */ + private Undefined() { + } + + /** + * Returns the singleton value of Undefined. + * + * @return the Undefined value + */ + public static Undefined Value() { + return value; + } + + /** + * Returns the string representation of Undfined. + */ + public String toString() { + return "{}"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/User.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/User.java new file mode 100644 index 0000000000000..3a5fc9974857a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/User.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; + +/** + * Represents a database user in the Azure Cosmos DB database service. + */ +public class User extends Resource { + + /** + * Initialize a user object. + */ + public User() { + super(); + } + + /** + * Initialize a user object from json string. + * + * @param jsonString the json string that represents the database user. + */ + public User(String jsonString) { + super(jsonString); + } + + /** + * Sets the id + * @param id the name of the resource. + * @return the current instance of User + */ + public User id(String id){ + super.id(id); + return this; + } + + /** + * Gets the self-link of the permissions associated with the user. + * + * @return the permissions link. + */ + public String getPermissionsLink() { + String selfLink = this.selfLink(); + if (selfLink.endsWith("/")) { + return selfLink + super.getString(Constants.Properties.PERMISSIONS_LINK); + } else { + return selfLink + "/" + super.getString(Constants.Properties.PERMISSIONS_LINK); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserAgentContainer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserAgentContainer.java new file mode 100644 index 0000000000000..5266b26fba984 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserAgentContainer.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +/** + * Used internally. The user agent object, which is used to track the version of the Java SDK of the Azure Cosmos DB database service. + */ +public class UserAgentContainer { + + private static final int MAX_SUFFIX_LENGTH = 64; + private final String baseUserAgent; + private String suffix; + private String userAgent; + + private UserAgentContainer(String sdkName, String sdkVersion) { + this.baseUserAgent = Utils.getUserAgent(sdkName, sdkVersion); + this.suffix = ""; + this.userAgent = baseUserAgent; + } + + public UserAgentContainer() { + this(HttpConstants.Versions.SDK_NAME, HttpConstants.Versions.SDK_VERSION); + } + + public String getSuffix() { + return this.suffix; + } + + public void setSuffix(String suffix) { + if (suffix.length() > MAX_SUFFIX_LENGTH) { + suffix = suffix.substring(0, MAX_SUFFIX_LENGTH); + } + + this.suffix = suffix; + this.userAgent = baseUserAgent.concat(this.suffix); + } + + public String getUserAgent() { + return this.userAgent; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserDefinedFunction.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserDefinedFunction.java new file mode 100644 index 0000000000000..30bd5c7f67089 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/UserDefinedFunction.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; + +/** + * Represents a user defined function in the Azure Cosmos DB database service. + *

    + * Cosmos DB supports JavaScript UDFs which can be used inside queries, stored procedures and triggers. For additional + * details, refer to the server-side JavaScript API documentation. + */ +public class UserDefinedFunction extends Resource { + + /** + * Constructor. + */ + public UserDefinedFunction() { + super(); + } + + /** + * Constructor. + * + * @param jsonString the json string that represents the user defined function. + */ + public UserDefinedFunction(String jsonString) { + super(jsonString); + } + + /** + * Get the body of the user defined function. + * + * @return the body. + */ + public String getBody() { + return super.getString(Constants.Properties.BODY); + } + + /** + * Set the body of the user defined function. + * + * @param body the body. + */ + public void setBody(String body) { + BridgeInternal.setProperty(this, Constants.Properties.BODY, body); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Utils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Utils.java new file mode 100644 index 0000000000000..843ea904d1a4f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/Utils.java @@ -0,0 +1,575 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.ConsistencyLevel; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.uuid.EthernetAddress; +import com.fasterxml.uuid.Generators; +import com.fasterxml.uuid.impl.TimeBasedGenerator; +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class Utils { + private static final ZoneId GMT_ZONE_ID = ZoneId.of("GMT"); + public static final Base64.Encoder Base64Encoder = Base64.getEncoder(); + public static final Base64.Decoder Base64Decoder = Base64.getDecoder(); + + private static final ObjectMapper simpleObjectMapper = new ObjectMapper(); + private static final TimeBasedGenerator TimeUUIDGegerator = + Generators.timeBasedGenerator(EthernetAddress.constructMulticastAddress()); + + // NOTE DateTimeFormatter.RFC_1123_DATE_TIME cannot be used. + // because cosmos db rfc1123 validation requires two digits for day. + // so Thu, 04 Jan 2018 00:30:37 GMT is accepted by the cosmos db service, + // but Thu, 4 Jan 2018 00:30:37 GMT is not. + // Therefore, we need a custom date time formatter. + private static final DateTimeFormatter RFC_1123_DATE_TIME = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + + static { + Utils.simpleObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + Utils.simpleObjectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + Utils.simpleObjectMapper.configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true); + Utils.simpleObjectMapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + } + + public static byte[] getUTF8Bytes(String str) throws UnsupportedEncodingException { + return str.getBytes("UTF-8"); + } + + public static String encodeBase64String(byte[] binaryData) { + String encodedString = Base64Encoder.encodeToString(binaryData); + + if (encodedString.endsWith("\r\n")) { + encodedString = encodedString.substring(0, encodedString.length() - 2); + } + return encodedString; + } + + /** + * Checks whether the specified link is Name based or not + * + * @param link the link to analyze. + * @return true or false + */ + public static boolean isNameBased(String link) { + if (StringUtils.isEmpty(link)) { + return false; + } + + // trimming the leading "/" + if (link.startsWith("/") && link.length() > 1) { + link = link.substring(1); + } + + // Splitting the link(separated by "/") into parts + String[] parts = StringUtils.split(link, "/"); + + // First part should be "dbs" + if (parts.length == 0 || StringUtils.isEmpty(parts[0]) + || !parts[0].equalsIgnoreCase(Paths.DATABASES_PATH_SEGMENT)) { + return false; + } + + // The second part is the database id(ResourceID or Name) and cannot be + // empty + if (parts.length < 2 || StringUtils.isEmpty(parts[1])) { + return false; + } + + // Either ResourceID or database name + String databaseID = parts[1]; + + // Length of databaseID(in case of ResourceID) is always 8 + if (databaseID.length() != 8) { + return true; + } + + // Decoding the databaseID + byte[] buffer = ResourceId.fromBase64String(databaseID); + + // Length of decoded buffer(in case of ResourceID) is always 4 + if (buffer.length != 4) { + return true; + } + + return false; + } + + /** + * Checks whether the specified link is a Database Self Link or a Database + * ID based link + * + * @param link the link to analyze. + * @return true or false + */ + public static boolean isDatabaseLink(String link) { + if (StringUtils.isEmpty(link)) { + return false; + } + + // trimming the leading and trailing "/" from the input string + link = trimBeginningAndEndingSlashes(link); + + // Splitting the link(separated by "/") into parts + String[] parts = StringUtils.split(link, "/"); + + if (parts.length != 2) { + return false; + } + + // First part should be "dbs" + if (StringUtils.isEmpty(parts[0]) || !parts[0].equalsIgnoreCase(Paths.DATABASES_PATH_SEGMENT)) { + return false; + } + + // The second part is the database id(ResourceID or Name) and cannot be + // empty + if (StringUtils.isEmpty(parts[1])) { + return false; + } + + return true; + } + + /** + * Checks whether the specified path segment is a resource type + * + * @param resourcePathSegment the path segment to analyze. + * @return true or false + */ + public static boolean IsResourceType(String resourcePathSegment) { + if (StringUtils.isEmpty(resourcePathSegment)) { + return false; + } + + switch (resourcePathSegment.toLowerCase()) { + case Paths.ATTACHMENTS_PATH_SEGMENT: + case Paths.COLLECTIONS_PATH_SEGMENT: + case Paths.DATABASES_PATH_SEGMENT: + case Paths.PERMISSIONS_PATH_SEGMENT: + case Paths.USERS_PATH_SEGMENT: + case Paths.DOCUMENTS_PATH_SEGMENT: + case Paths.STORED_PROCEDURES_PATH_SEGMENT: + case Paths.TRIGGERS_PATH_SEGMENT: + case Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT: + case Paths.CONFLICTS_PATH_SEGMENT: + case Paths.PARTITION_KEY_RANGES_PATH_SEGMENT: + return true; + + default: + return false; + } + } + + /** + * Joins the specified paths by appropriately padding them with '/' + * + * @param path1 the first path segment to join. + * @param path2 the second path segment to join. + * @return the concatenated path with '/' + */ + public static String joinPath(String path1, String path2) { + path1 = trimBeginningAndEndingSlashes(path1); + String result = "/" + path1 + "/"; + + if (!StringUtils.isEmpty(path2)) { + path2 = trimBeginningAndEndingSlashes(path2); + result += path2 + "/"; + } + + return result; + } + + /** + * Trims the beginning and ending '/' from the given path + * + * @param path the path to trim for beginning and ending slashes + * @return the path without beginning and ending '/' + */ + public static String trimBeginningAndEndingSlashes(String path) { + if(path == null) { + return null; + } + + if (path.startsWith("/")) { + path = path.substring(1); + } + + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + + return path; + } + + public static Map paramEncode(Map queryParams) { + // TODO: this is not performant revisit + HashMap map = new HashMap<>(); + for(Map.Entry paramEntry: queryParams.entrySet()) { + try { + map.put(paramEntry.getKey(), URLEncoder.encode(paramEntry.getValue(), "UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException(e); + } + } + return map; + } + + public static String createQuery(Map queryParameters) { + if (queryParameters == null) + return ""; + StringBuilder queryString = new StringBuilder(); + for (Map.Entry nameValuePair : queryParameters.entrySet()) { + String key = nameValuePair.getKey(); + String value = nameValuePair.getValue(); + if (key != null && !key.isEmpty()) { + if (queryString.length() > 0) { + queryString.append(RuntimeConstants.Separators.Query[1]); + } + queryString.append(key); + if (value != null) { + queryString.append(RuntimeConstants.Separators.Query[2]); + queryString.append(value); + } + } + } + return queryString.toString(); + } + + public static URL setQuery(String urlString, String query) { + + if (urlString == null) + throw new IllegalStateException("urlString parameter can't be null."); + query = Utils.removeLeadingQuestionMark(query); + try { + if (query != null && !query.isEmpty()) { + return new URI(Utils.addTrailingSlash(urlString) + RuntimeConstants.Separators.Query[0] + query) + .toURL(); + } else { + return new URI(Utils.addTrailingSlash(urlString)).toURL(); + } + } catch (MalformedURLException e) { + throw new IllegalStateException("Uri is invalid: ", e); + } catch (URISyntaxException e) { + throw new IllegalStateException("Uri is invalid: ", e); + } + } + + /** + * Given the full path to a resource, extract the collection path. + * + * @param resourceFullName the full path to the resource. + * @return the path of the collection in which the resource is. + */ + public static String getCollectionName(String resourceFullName) { + if (resourceFullName != null) { + resourceFullName = Utils.trimBeginningAndEndingSlashes(resourceFullName); + + int slashCount = 0; + for (int i = 0; i < resourceFullName.length(); i++) { + if (resourceFullName.charAt(i) == '/') { + slashCount++; + if (slashCount == 4) { + return resourceFullName.substring(0, i); + } + } + } + } + return resourceFullName; + } + + public static Boolean isCollectionPartitioned(DocumentCollection collection) { + if (collection == null) { + throw new IllegalArgumentException("collection"); + } + + return collection.getPartitionKey() != null + && collection.getPartitionKey().paths() != null + && collection.getPartitionKey().paths().size() > 0; + } + + public static boolean isCollectionChild(ResourceType type) { + return type == ResourceType.Document || type == ResourceType.Attachment || type == ResourceType.Conflict + || type == ResourceType.StoredProcedure || type == ResourceType.Trigger || type == ResourceType.UserDefinedFunction; + } + + public static boolean isWriteOperation(OperationType operationType) { + return operationType == OperationType.Create || operationType == OperationType.Upsert || operationType == OperationType.Delete || operationType == OperationType.Replace + || operationType == OperationType.ExecuteJavaScript; + } + + public static boolean isFeedRequest(OperationType requestOperationType) { + return requestOperationType == OperationType.Create || + requestOperationType == OperationType.Upsert || + requestOperationType == OperationType.ReadFeed || + requestOperationType == OperationType.Query || + requestOperationType == OperationType.SqlQuery || + requestOperationType == OperationType.HeadFeed; + } + + private static String addTrailingSlash(String path) { + if (path == null || path.isEmpty()) + path = new String(RuntimeConstants.Separators.Url); + else if (path.charAt(path.length() - 1) != RuntimeConstants.Separators.Url[0]) + path = path + RuntimeConstants.Separators.Url[0]; + + return path; + } + + private static String removeLeadingQuestionMark(String path) { + if (path == null || path.isEmpty()) + return path; + + if (path.charAt(0) == RuntimeConstants.Separators.Query[0]) + return path.substring(1); + + return path; + } + + public static boolean isValidConsistency(ConsistencyLevel backendConsistency, + ConsistencyLevel desiredConsistency) { + switch (backendConsistency) { + case STRONG: + return desiredConsistency == ConsistencyLevel.STRONG || + desiredConsistency == ConsistencyLevel.BOUNDED_STALENESS || + desiredConsistency == ConsistencyLevel.SESSION || + desiredConsistency == ConsistencyLevel.EVENTUAL || + desiredConsistency == ConsistencyLevel.CONSISTENT_PREFIX; + + case BOUNDED_STALENESS: + return desiredConsistency == ConsistencyLevel.BOUNDED_STALENESS || + desiredConsistency == ConsistencyLevel.SESSION || + desiredConsistency == ConsistencyLevel.EVENTUAL || + desiredConsistency == ConsistencyLevel.CONSISTENT_PREFIX; + + case SESSION: + case EVENTUAL: + case CONSISTENT_PREFIX: + return desiredConsistency == ConsistencyLevel.SESSION || + desiredConsistency == ConsistencyLevel.EVENTUAL || + desiredConsistency == ConsistencyLevel.CONSISTENT_PREFIX; + + default: + throw new IllegalArgumentException("backendConsistency"); + } + } + + public static String getUserAgent(String sdkName, String sdkVersion) { + String osName = System.getProperty("os.name"); + if (osName == null) { + osName = "Unknown"; + } + osName = osName.replaceAll("\\s", ""); + String userAgent = String.format("%s/%s JRE/%s %s/%s", + osName, + System.getProperty("os.version"), + System.getProperty("java.version"), + sdkName, + sdkVersion); + return userAgent; + } + + public static ObjectMapper getSimpleObjectMapper() { + return Utils.simpleObjectMapper; + } + + /** + * Returns Current Time in RFC 1123 format, e.g, + * Fri, 01 Dec 2017 19:22:30 GMT. + * + * @return an instance of STRING + */ + public static String nowAsRFC1123() { + ZonedDateTime now = ZonedDateTime.now(GMT_ZONE_ID); + return Utils.RFC_1123_DATE_TIME.format(now); + } + + public static UUID randomUUID() { + return TimeUUIDGegerator.generate(); + } + + public static String zonedDateTimeAsUTCRFC1123(OffsetDateTime offsetDateTime){ + return Utils.RFC_1123_DATE_TIME.format(offsetDateTime.atZoneSameInstant(GMT_ZONE_ID)); + } + + public static int getValueOrDefault(Integer val, int defaultValue) { + return val != null ? val.intValue() : defaultValue; + } + + public static void checkStateOrThrow(boolean value, String argumentName, String message) throws IllegalArgumentException { + + IllegalArgumentException t = checkStateOrReturnException(value, argumentName, message); + if (t != null) { + throw t; + } + } + + public static void checkNotNullOrThrow(Object val, String argumentName, String message) throws NullPointerException { + + NullPointerException t = checkNotNullOrReturnException(val, argumentName, message); + if (t != null) { + throw t; + } + } + + public static void checkStateOrThrow(boolean value, String argumentName, String messageTemplate, Object... messageTemplateParams) throws IllegalArgumentException { + IllegalArgumentException t = checkStateOrReturnException(value, argumentName, argumentName, messageTemplateParams); + if (t != null) { + throw t; + } + } + + public static IllegalArgumentException checkStateOrReturnException(boolean value, String argumentName, String message) { + + if (value) { + return null; + } + + return new IllegalArgumentException(String.format("argumentName: %s, message: %s", argumentName, message)); + } + + public static IllegalArgumentException checkStateOrReturnException(boolean value, String argumentName, String messageTemplate, Object... messageTemplateParams) { + if (value) { + return null; + } + + return new IllegalArgumentException(String.format("argumentName: %s, message: %s", argumentName, String.format(messageTemplate, messageTemplateParams))); + } + + private static NullPointerException checkNotNullOrReturnException(Object val, String argumentName, String messageTemplate, Object... messageTemplateParams) { + if (val != null) { + return null; + } + + return new NullPointerException(String.format("argumentName: %s, message: %s", argumentName, String.format(messageTemplate, messageTemplateParams))); + } + + public static BadRequestException checkRequestOrReturnException(boolean value, String argumentName, String message) { + + if (value) { + return null; + } + + return new BadRequestException(String.format("argumentName: %s, message: %s", argumentName, message)); + } + + public static BadRequestException checkRequestOrReturnException(boolean value, String argumentName, String messageTemplate, Object... messageTemplateParams) { + if (value) { + return null; + } + + return new BadRequestException(String.format("argumentName: %s, message: %s", argumentName, String.format(messageTemplate, messageTemplateParams))); + } + + @SuppressWarnings("unchecked") + public static O as(I i, Class klass) { + if (i == null) { + return null; + } + + if (klass.isInstance(i)) { + return (O) i; + } else { + return null; + } + } + + @SuppressWarnings("unchecked") + public static List immutableListOf() { + return Collections.EMPTY_LIST; + } + + public static List immutableListOf(V v1) { + List list = new ArrayList<>(); + list.add(v1); + return Collections.unmodifiableList(list); + } + + public static MapimmutableMapOf() { + return Collections.emptyMap(); + } + + public static MapimmutableMapOf(K k1, V v1) { + Map map = new HashMap(); + map.put(k1, v1); + map = Collections.unmodifiableMap(map); + return map; + } + + public static V firstOrDefault(List list) { + return list.size() > 0? list.get(0) : null ; + } + + public static class ValueHolder { + + public ValueHolder() { + } + + public ValueHolder(V v) { + this.v = v; + } + public V v; + + public static ValueHolder initialize(T v) { + return new ValueHolder(v); + } + } + + public static boolean tryGetValue(Map dictionary, K key, ValueHolder holder) { + // doesn't work for dictionary with null value + holder.v = dictionary.get(key); + return holder.v != null; + } + + public static boolean tryRemove(Map dictionary, K key, ValueHolder holder) { + // doesn't work for dictionary with null value + holder.v = dictionary.remove(key); + return holder.v != null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/VectorSessionToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/VectorSessionToken.java new file mode 100644 index 0000000000000..a55959f8465bf --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/VectorSessionToken.java @@ -0,0 +1,320 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.InternalServerErrorException; +import org.apache.commons.collections4.map.UnmodifiableMap; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; + +/** + * Models vector clock bases session token. SESSION token has the following format: + * {Version}#{GlobalLSN}#{RegionId1}={LocalLsn1}#{RegionId2}={LocalLsn2}....#{RegionIdN}={LocalLsnN} + * 'Version' captures the configuration number of the partition which returned this session token. + * 'Version' is incremented everytime topology of the partition is updated (say due to Add/Remove/Failover). + * * The choice of separators '#' and '=' is important. Separators ';' and ',' are used to delimit + * per-partitionKeyRange session token + * session + * + * We make assumption that instances of this class are immutable (read only after they are constructed), so if you want to change + * this behaviour please review all of its uses and make sure that mutability doesn't break anything. + */ +public class VectorSessionToken implements ISessionToken { + private final static Logger logger = LoggerFactory.getLogger(VectorSessionToken.class); + private final static char SegmentSeparator = '#'; + private final static char RegionProgressSeparator = '='; + + private final long version; + private final long globalLsn; + private final UnmodifiableMap localLsnByRegion; + private final String sessionToken; + + private VectorSessionToken(long version, long globalLsn, UnmodifiableMap localLsnByRegion) { + this(version, globalLsn, localLsnByRegion, null); + } + + private VectorSessionToken(long version, long globalLsn, UnmodifiableMap localLsnByRegion, String sessionToken) { + this.version = version; + this.globalLsn = globalLsn; + this.localLsnByRegion = localLsnByRegion; + if (sessionToken == null) { + String regionProgress = String.join( + Character.toString(VectorSessionToken.SegmentSeparator), + localLsnByRegion. + entrySet() + .stream() + .map(kvp -> new StringBuilder().append(kvp.getKey()).append(VectorSessionToken.RegionProgressSeparator).append(kvp.getValue())) + .collect(Collectors.toList())); + + if (Strings.isNullOrEmpty(regionProgress)) { + StringBuilder sb = new StringBuilder(); + sb.append(this.version) + .append(VectorSessionToken.SegmentSeparator) + .append(this.globalLsn); + this.sessionToken = sb.toString(); + } else { + StringBuilder sb = new StringBuilder(); + sb.append(this.version) + .append(VectorSessionToken.SegmentSeparator) + .append(this.globalLsn) + .append(VectorSessionToken.SegmentSeparator) + .append(regionProgress); + this.sessionToken = sb.toString(); + } + } else { + this.sessionToken = sessionToken; + } + } + + public static boolean tryCreate(String sessionToken, ValueHolder parsedSessionToken) { + ValueHolder versionHolder = ValueHolder.initialize(-1l); + ValueHolder globalLsnHolder = ValueHolder.initialize(-1l); + + ValueHolder> localLsnByRegion = ValueHolder.initialize(null); + + if (VectorSessionToken.tryParseSessionToken( + sessionToken, + versionHolder, + globalLsnHolder, + localLsnByRegion)) { + parsedSessionToken.v = new VectorSessionToken(versionHolder.v, globalLsnHolder.v, localLsnByRegion.v, sessionToken); + return true; + } else { + return false; + } + } + + public long getLSN() { + return this.globalLsn; + } + + @Override + public boolean equals(Object obj) { + VectorSessionToken other = Utils.as(obj, VectorSessionToken.class); + + if (other == null) { + return false; + } + + return this.version == other.version + && this.globalLsn == other.globalLsn + && this.areRegionProgressEqual(other.localLsnByRegion); + } + + public boolean isValid(ISessionToken otherSessionToken) throws CosmosClientException { + VectorSessionToken other = Utils.as(otherSessionToken, VectorSessionToken.class); + + if (other == null) { + throw new IllegalArgumentException("otherSessionToken"); + } + + if (other.version < this.version || other.globalLsn < this.globalLsn) { + return false; + } + + if (other.version == this.version && other.localLsnByRegion.size() != this.localLsnByRegion.size()) { + throw new InternalServerErrorException( + String.format(RMResources.InvalidRegionsInSessionToken, this.sessionToken, other.sessionToken)); + } + + for (Map.Entry kvp : other.localLsnByRegion.entrySet()) { + Integer regionId = kvp.getKey(); + long otherLocalLsn = kvp.getValue(); + ValueHolder localLsn = ValueHolder.initialize(-1l); + + + if (!Utils.tryGetValue(this.localLsnByRegion, regionId, localLsn)) { + // Region mismatch: other session token has progress for a region which is missing in this session token + // Region mismatch can be ignored only if this session token version is smaller than other session token version + if (this.version == other.version) { + throw new InternalServerErrorException( + String.format(RMResources.InvalidRegionsInSessionToken, this.sessionToken, other.sessionToken)); + } else { + // ignore missing region as other session token version > this session token version + } + } else { + // region is present in both session tokens. + if (otherLocalLsn < localLsn.v) { + return false; + } + } + } + + return true; + } + + // Merge is commutative operation, so a.Merge(b).Equals(b.Merge(a)) + public ISessionToken merge(ISessionToken obj) throws CosmosClientException { + VectorSessionToken other = Utils.as(obj, VectorSessionToken.class); + + if (other == null) { + throw new IllegalArgumentException("obj"); + } + + if (this.version == other.version && this.localLsnByRegion.size() != other.localLsnByRegion.size()) { + throw new InternalServerErrorException( + String.format(RMResources.InvalidRegionsInSessionToken, this.sessionToken, other.sessionToken)); + } + + VectorSessionToken sessionTokenWithHigherVersion; + VectorSessionToken sessionTokenWithLowerVersion; + + if (this.version < other.version) { + sessionTokenWithLowerVersion = this; + sessionTokenWithHigherVersion = other; + } else { + sessionTokenWithLowerVersion = other; + sessionTokenWithHigherVersion = this; + } + + Map highestLocalLsnByRegion = new HashMap<>(); + + for (Map.Entry kvp : sessionTokenWithHigherVersion.localLsnByRegion.entrySet()) { + Integer regionId = kvp.getKey(); + + long localLsn1 = kvp.getValue(); + ValueHolder localLsn2 = ValueHolder.initialize(-1l); + + if (Utils.tryGetValue(sessionTokenWithLowerVersion.localLsnByRegion, regionId, localLsn2)) { + highestLocalLsnByRegion.put(regionId, Math.max(localLsn1, localLsn2.v)); + } else if (this.version == other.version) { + throw new InternalServerErrorException( + String.format(RMResources.InvalidRegionsInSessionToken, this.sessionToken, other.sessionToken)); + } else { + highestLocalLsnByRegion.put(regionId, localLsn1); + } + } + + return new VectorSessionToken( + Math.max(this.version, other.version), + Math.max(this.globalLsn, other.globalLsn), + (UnmodifiableMap) UnmodifiableMap.unmodifiableMap(highestLocalLsnByRegion)); + } + + public String convertToString() { + return this.sessionToken; + } + + private boolean areRegionProgressEqual(UnmodifiableMap other) { + if (this.localLsnByRegion.size() != other.size()) { + return false; + } + + for (Map.Entry kvp : this.localLsnByRegion.entrySet()) { + Integer regionId = kvp.getKey(); + ValueHolder localLsn1 = ValueHolder.initialize(kvp.getValue()); + ValueHolder localLsn2 = ValueHolder.initialize(-1l); + + if (Utils.tryGetValue(other, regionId, localLsn2)) { + if (ObjectUtils.notEqual(localLsn1.v, localLsn2.v)) { + return false; + } + } + } + + return true; + } + + private static boolean tryParseSessionToken( + String sessionToken, + ValueHolder version, + ValueHolder globalLsn, + ValueHolder> localLsnByRegion) { + version.v = 0L; + localLsnByRegion.v = null; + globalLsn.v = -1L; + + if (Strings.isNullOrEmpty(sessionToken)) { + logger.warn("SESSION token is empty"); + return false; + } + + String[] segments = StringUtils.split(sessionToken, VectorSessionToken.SegmentSeparator); + + if (segments.length < 2) { + return false; + } + + if (!tryParseLong(segments[0], version) + || !tryParseLong(segments[1], globalLsn)) { + logger.warn("Unexpected session token version number '{}' OR global lsn '{}'.", segments[0], segments[1]); + return false; + } + + Map lsnByRegion = new HashMap<>(); + + for (int i = 2; i < segments.length; i++) { + String regionSegment = segments[i]; + + String[] regionIdWithLsn = StringUtils.split(regionSegment, VectorSessionToken.RegionProgressSeparator); + + if (regionIdWithLsn.length != 2) { + logger.warn("Unexpected region progress segment length '{}' in session token.", regionIdWithLsn.length); + return false; + } + + ValueHolder regionId = ValueHolder.initialize(0); + ValueHolder localLsn = ValueHolder.initialize(-1l); + + if (!tryParseInt(regionIdWithLsn[0], regionId) + || !tryParseLong(regionIdWithLsn[1], localLsn)) { + logger.warn("Unexpected region progress '{}' for region '{}' in session token.", regionIdWithLsn[0], regionIdWithLsn[1]); + return false; + } + + lsnByRegion.put(regionId.v, localLsn.v); + } + + localLsnByRegion.v = (UnmodifiableMap) UnmodifiableMap.unmodifiableMap(lsnByRegion); + return true; + } + + private static boolean tryParseLong(String str, ValueHolder value) { + try { + value.v = Long.parseLong(str); + return true; + } catch (Exception e) { + return false; + } + } + + private static boolean tryParseInt(String str, ValueHolder value) { + try { + value.v = Integer.parseInt(str); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/WebExceptionRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/WebExceptionRetryPolicy.java new file mode 100644 index 0000000000000..f48f280481c06 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/WebExceptionRetryPolicy.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.WebExceptionUtility; +import org.apache.commons.lang3.time.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +public class WebExceptionRetryPolicy implements IRetryPolicy { + private final static Logger logger = LoggerFactory.getLogger(WebExceptionRetryPolicy.class); + + // total wait time in seconds to retry. should be max of primary reconfigrations/replication wait duration etc + private final static int waitTimeInSeconds = 30; + private final static int initialBackoffSeconds = 1; + private final static int backoffMultiplier = 2; + + private StopWatch durationTimer = new StopWatch(); + private int attemptCount = 1; + // Don't penalise first retry with delay. + private int currentBackoffSeconds = WebExceptionRetryPolicy.initialBackoffSeconds; + + public WebExceptionRetryPolicy() { + durationTimer.start(); + } + + + @Override + public Mono shouldRetry(Exception exception) { + Duration backoffTime = Duration.ofSeconds(0); + + if (!WebExceptionUtility.isWebExceptionRetriable(exception)) { + // Have caller propagate original exception. + this.durationTimer.stop(); + return Mono.just(ShouldRetryResult.noRetry()); + } + + // Don't penalise first retry with delay. + if (attemptCount++ > 1) { + int remainingSeconds = WebExceptionRetryPolicy.waitTimeInSeconds - Math.toIntExact(this.durationTimer.getTime(TimeUnit.SECONDS)); + if (remainingSeconds <= 0) { + this.durationTimer.stop(); + return Mono.just(ShouldRetryResult.noRetry()); + } + + backoffTime = Duration.ofSeconds(Math.min(this.currentBackoffSeconds, remainingSeconds)); + this.currentBackoffSeconds *= WebExceptionRetryPolicy.backoffMultiplier; + } + + logger.warn("Received retriable web exception, will retry", exception); + + return Mono.just(ShouldRetryResult.retryAfter(backoffTime)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncCache.java new file mode 100644 index 0000000000000..668ae4428b981 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncCache.java @@ -0,0 +1,157 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; + +public class AsyncCache { + + private final Logger logger = LoggerFactory.getLogger(AsyncCache.class); + private final ConcurrentHashMap> values = new ConcurrentHashMap<>(); + + private final IEqualityComparer equalityComparer; + + public AsyncCache(IEqualityComparer equalityComparer) { + this.equalityComparer = equalityComparer; + } + + public AsyncCache() { + this((value1, value2) -> { + if (value1 == value2) + return true; + if (value1 == null || value2 == null) + return false; + return value1.equals(value2); + }); + } + + public void set(TKey key, TValue value) { + logger.debug("set cache[{}]={}", key, value); + values.put(key, new AsyncLazy<>(value)); + } + + /** + * Gets value corresponding to key + * + *

    + * If another initialization function is already running, new initialization function will not be started. + * The result will be result of currently running initialization function. + *

    + * + *

    + * If previous initialization function is successfully completed - value returned by it will be returned unless + * it is equal to obsoleteValue, in which case new initialization function will be started. + *

    + *

    + * If previous initialization function failed - new one will be launched. + *

    + * + * @param key Key for which to get a value. + * @param obsoleteValue Value which is obsolete and needs to be refreshed. + * @param singleValueInitFunc Initialization function. + * @return Cached value or value returned by initialization function. + */ + public Mono getAsync( + TKey key, + TValue obsoleteValue, + Callable> singleValueInitFunc) { + + AsyncLazy initialLazyValue = values.get(key); + if (initialLazyValue != null) { + + logger.debug("cache[{}] exists", key); + return initialLazyValue.single().flux().flatMap(value -> { + + if (!equalityComparer.areEqual(value, obsoleteValue)) { + logger.debug("Returning cache[{}] as it is different from obsoleteValue", key); + return Flux.just(value); + } + + logger.debug("cache[{}] result value is obsolete ({}), computing new value", key, obsoleteValue); + AsyncLazy asyncLazy = new AsyncLazy<>(singleValueInitFunc); + AsyncLazy actualValue = values.merge(key, asyncLazy, + (lazyValue1, lazyValue2) -> lazyValue1 == initialLazyValue ? lazyValue2 : lazyValue1); + return actualValue.single().flux(); + + }, err -> { + + logger.debug("cache[{}] resulted in error {}, computing new value", key, err); + AsyncLazy asyncLazy = new AsyncLazy<>(singleValueInitFunc); + AsyncLazy resultAsyncLazy = values.merge(key, asyncLazy, + (lazyValue1, lazyValu2) -> lazyValue1 == initialLazyValue ? lazyValu2 : lazyValue1); + return resultAsyncLazy.single().flux(); + + }, Flux::empty).single(); + } + + logger.debug("cache[{}] doesn't exist, computing new value", key); + AsyncLazy asyncLazy = new AsyncLazy<>(singleValueInitFunc); + AsyncLazy resultAsyncLazy = values.merge(key, asyncLazy, + (lazyValue1, lazyValu2) -> lazyValue1 == initialLazyValue ? lazyValu2 : lazyValue1); + return resultAsyncLazy.single(); + } + + public void remove(TKey key) { + values.remove(key); + } + + /** + * Remove value from cache and return it if present + * @param key + * @return Value if present, default value if not present + */ + public Mono removeAsync(TKey key) { + AsyncLazy lazy = values.remove(key); + return lazy.single(); + // TODO: .Net returns default value on failure of single why? + } + + public void clear() { + this.values.clear(); + } + + /** + * Forces refresh of the cached item if it is not being refreshed at the moment. + * @param key + * @param singleValueInitFunc + */ + public void refresh( + TKey key, + Callable> singleValueInitFunc) { + logger.debug("refreshing cache[{}]", key); + AsyncLazy initialLazyValue = values.get(key); + if (initialLazyValue != null && (initialLazyValue.isSucceeded() || initialLazyValue.isFaulted())) { + AsyncLazy newLazyValue = new AsyncLazy<>(singleValueInitFunc); + + // UPDATE the new task in the cache, + values.merge(key, newLazyValue, + (lazyValue1, lazyValu2) -> lazyValue1 == initialLazyValue ? lazyValu2 : lazyValue1); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncLazy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncLazy.java new file mode 100644 index 0000000000000..234c7b25b982e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/AsyncLazy.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; + +class AsyncLazy { + + private final static Logger logger = LoggerFactory.getLogger(AsyncLazy.class); + + private final Mono single; + + private volatile boolean succeeded; + private volatile boolean failed; + + public AsyncLazy(Callable> func) { + this(Mono.defer(() -> { + logger.debug("using Function> {}", func); + try { + return func.call(); + } catch (Exception e) { + return Mono.error(e); + } + })); + } + + public AsyncLazy(TValue value) { + this.single = Mono.just(value); + this.succeeded = true; + this.failed = false; + } + + private AsyncLazy(Mono single) { + logger.debug("constructor"); + this.single = single + .doOnSuccess(v -> this.succeeded = true) + .doOnError(e -> this.failed = true) + .cache(); + } + + public Mono single() { + return single; + } + + public boolean isSucceeded() { + return succeeded; + } + + public boolean isFaulted() { + return failed; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IEqualityComparer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IEqualityComparer.java new file mode 100644 index 0000000000000..3b77b00d96bbc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IEqualityComparer.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +interface IEqualityComparer { + boolean areEqual(TValue v1, TValue v2); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IPartitionKeyRangeCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IPartitionKeyRangeCache.java new file mode 100644 index 0000000000000..07d99280dff9e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/IPartitionKeyRangeCache.java @@ -0,0 +1,50 @@ +/** + * The MIT License (MIT) + * Copyright (c) 2017 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import com.azure.data.cosmos.internal.ICollectionRoutingMapCache; +import com.azure.data.cosmos.internal.IRoutingMapProvider; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.Range; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * + */ +public interface IPartitionKeyRangeCache extends IRoutingMapProvider, ICollectionRoutingMapCache { + + Mono tryLookupAsync(String collectionRid, CollectionRoutingMap previousValue, Map properties); + + Mono> tryGetOverlappingRangesAsync(String collectionRid, Range range, boolean forceRefresh, + Map properties); + + Mono tryGetPartitionKeyRangeByIdAsync(String collectionResourceId, String partitionKeyRangeId, boolean forceRefresh, + Map properties); + + Mono tryGetRangeByPartitionKeyRangeId(String collectionRid, String partitionKeyRangeId, Map properties); + +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxClientCollectionCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxClientCollectionCache.java new file mode 100644 index 0000000000000..565d218954242 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxClientCollectionCache.java @@ -0,0 +1,121 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.internal.AuthorizationTokenType; +import com.azure.data.cosmos.internal.ClearingSessionContainerClientRetryPolicy; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.IRetryPolicyFactory; +import com.azure.data.cosmos.internal.ObservableHelper; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.RxStoreModel; +import com.azure.data.cosmos.internal.Utils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; + +/** + * Caches collection information. + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class RxClientCollectionCache extends RxCollectionCache { + + private RxStoreModel storeModel; + private final IAuthorizationTokenProvider tokenProvider; + private final IRetryPolicyFactory retryPolicy; + private final ISessionContainer sessionContainer; + + public RxClientCollectionCache(ISessionContainer sessionContainer, + RxStoreModel storeModel, + IAuthorizationTokenProvider tokenProvider, + IRetryPolicyFactory retryPolicy) { + this.storeModel = storeModel; + this.tokenProvider = tokenProvider; + this.retryPolicy = retryPolicy; + this.sessionContainer = sessionContainer; + } + + protected Mono getByRidAsync(String collectionRid, Map properties) { + IDocumentClientRetryPolicy retryPolicyInstance = new ClearingSessionContainerClientRetryPolicy(this.sessionContainer, this.retryPolicy.getRequestPolicy()); + return ObservableHelper.inlineIfPossible( + () -> this.readCollectionAsync(PathsHelper.generatePath(ResourceType.DocumentCollection, collectionRid, false), retryPolicyInstance, properties) + , retryPolicyInstance); + } + + protected Mono getByNameAsync(String resourceAddress, Map properties) { + IDocumentClientRetryPolicy retryPolicyInstance = new ClearingSessionContainerClientRetryPolicy(this.sessionContainer, this.retryPolicy.getRequestPolicy()); + return ObservableHelper.inlineIfPossible( + () -> this.readCollectionAsync(resourceAddress, retryPolicyInstance, properties), + retryPolicyInstance); + } + + private Mono readCollectionAsync(String collectionLink, IDocumentClientRetryPolicy retryPolicyInstance, Map properties) { + + String path = Utils.joinPath(collectionLink, null); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + path, + new HashMap<>()); + + request.getHeaders().put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + + String resourceName = request.getResourceAddress(); + String authorizationToken = tokenProvider.getUserAuthorizationToken( + resourceName, + request.getResourceType(), + HttpConstants.HttpMethods.GET, + request.getHeaders(), + AuthorizationTokenType.PrimaryMasterKey, + properties); + + try { + authorizationToken = URLEncoder.encode(authorizationToken, "UTF-8"); + } catch (UnsupportedEncodingException e) { + return Mono.error(new IllegalStateException("Failed to encode authtoken.", e)); + } + request.getHeaders().put(HttpConstants.HttpHeaders.AUTHORIZATION, authorizationToken); + + if (retryPolicyInstance != null){ + retryPolicyInstance.onBeforeSendRequest(request); + } + + Flux responseObs = this.storeModel.processMessage(request); + return responseObs.map(response -> BridgeInternal.toResourceResponse(response, DocumentCollection.class) + .getResource()).single(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxCollectionCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxCollectionCache.java new file mode 100644 index 0000000000000..1a3d510a81915 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxCollectionCache.java @@ -0,0 +1,209 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceId; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import org.apache.commons.lang3.StringUtils; +import reactor.core.publisher.Mono; + +import java.util.Map; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public abstract class RxCollectionCache { + + private final AsyncCache collectionInfoByNameCache; + private final AsyncCache collectionInfoByIdCache; + + protected RxCollectionCache() { + this.collectionInfoByNameCache = new AsyncCache<>(new CollectionRidComparer()); + this.collectionInfoByIdCache = new AsyncCache<>(new CollectionRidComparer()); + } + + /** + * Resolves a request to a collection in a sticky manner. + * Unless request.ForceNameCacheRefresh is equal to true, it will return the same collection. + * @param request Request to resolve. + * @return an instance of Single<DocumentCollection> + */ + public Mono resolveCollectionAsync( + RxDocumentServiceRequest request) { + // Mono Void to represent only terminal events specifically complete and error + Mono init = null; + if (request.getIsNameBased()) { + if (request.isForceNameCacheRefresh()) { + Mono mono = this.refreshAsync(request); + init = mono.then(Mono.fromRunnable(() -> request.setForceNameCacheRefresh(false))); + } + + Mono collectionInfoObs = this.resolveByPartitionKeyRangeIdentityAsync( + request.getPartitionKeyRangeIdentity(), request.properties); + + if (init != null) { + collectionInfoObs = init.then(collectionInfoObs); + } + + return collectionInfoObs.flatMap(Mono::just).switchIfEmpty(Mono.defer(() -> { + if (request.requestContext.resolvedCollectionRid == null) { + + Mono collectionInfoRes = this.resolveByNameAsync(request.getResourceAddress(), request.properties); + + return collectionInfoRes.flatMap(collection -> { + // TODO: how to async log this? + // logger.debug( + // "Mapped resourceName {} to resourceId {}.", + // request.getResourceAddress(), + // collectionInfo.resourceId()); + + request.setResourceId(collection.resourceId()); + request.requestContext.resolvedCollectionRid = collection.resourceId(); + return Mono.just(collection); + + }); + } else { + return this.resolveByRidAsync(request.requestContext.resolvedCollectionRid, request.properties); + } + })); + } else { + return resolveByPartitionKeyRangeIdentityAsync(request.getPartitionKeyRangeIdentity(),request.properties) + .flatMap(Mono::just).switchIfEmpty(this.resolveByRidAsync(request.getResourceAddress(), request.properties)); + } + } + + /** + * This method is only used in retry policy as it doesn't have request handy. + * @param resourceAddress + */ + public void refresh(String resourceAddress, Map properties) { + if (PathsHelper.isNameBased(resourceAddress)) { + String resourceFullName = PathsHelper.getCollectionPath(resourceAddress); + + this.collectionInfoByNameCache.refresh( + resourceFullName, + () -> { + Mono collectionObs = this.getByNameAsync(resourceFullName, properties); + return collectionObs.doOnSuccess(collection -> this.collectionInfoByIdCache.set(collection.resourceId(), collection)); + }); + } + } + + protected abstract Mono getByRidAsync(String collectionRid, Map properties); + + protected abstract Mono getByNameAsync(String resourceAddress, Map properties); + + private Mono resolveByPartitionKeyRangeIdentityAsync(PartitionKeyRangeIdentity partitionKeyRangeIdentity, Map properties) { + // if request is targeted at specific partition using x-ms-documentd-partitionkeyrangeid header, + // which contains value ",", then resolve to collection rid in this header. + if (partitionKeyRangeIdentity != null && partitionKeyRangeIdentity.getCollectionRid() != null) { + return this.resolveByRidAsync(partitionKeyRangeIdentity.getCollectionRid(), properties) + .onErrorResume(e -> { + if (e instanceof NotFoundException) { + // This is signal to the upper logic either to refresh + // collection cache and retry. + return Mono.error(new InvalidPartitionException(RMResources.InvalidDocumentCollection)); + } + return Mono.error(e); + + }); + } + return Mono.empty(); + } + + private Mono resolveByRidAsync( + String resourceId, Map properties) { + + ResourceId resourceIdParsed = ResourceId.parse(resourceId); + String collectionResourceId = resourceIdParsed.getDocumentCollectionId().toString(); + + return this.collectionInfoByIdCache.getAsync( + collectionResourceId, + null, + () -> this.getByRidAsync(collectionResourceId, properties)); + } + + private Mono resolveByNameAsync( + String resourceAddress, Map properties) { + + String resourceFullName = PathsHelper.getCollectionPath(resourceAddress); + + return this.collectionInfoByNameCache.getAsync( + resourceFullName, + null, + () -> { + Mono collectionObs = this.getByNameAsync(resourceFullName, properties); + return collectionObs.doOnSuccess(collection -> this.collectionInfoByIdCache.set(collection.resourceId(), collection)); + }); + } + + private Mono refreshAsync(RxDocumentServiceRequest request) { + // TODO System.Diagnostics.Debug.Assert(request.IsNameBased); + + String resourceFullName = PathsHelper.getCollectionPath(request.getResourceAddress()); + Mono mono; + + if (request.requestContext.resolvedCollectionRid != null) { + // Here we will issue backend call only if cache wasn't already refreshed (if whatever is there corresponds to previously resolved collection rid). + DocumentCollection obsoleteValue = new DocumentCollection(); + obsoleteValue.resourceId(request.requestContext.resolvedCollectionRid); + + mono = this.collectionInfoByNameCache.getAsync( + resourceFullName, + obsoleteValue, + () -> { + Mono collectionObs = this.getByNameAsync(resourceFullName, request.properties); + return collectionObs.doOnSuccess(collection -> { + this.collectionInfoByIdCache.set(collection.resourceId(), collection); + }); + }).then(); + } else { + // In case of ForceRefresh directive coming from client, there will be no ResolvedCollectionRid, so we + // need to refresh unconditionally. + mono = Mono.fromRunnable(() -> this.refresh(request.getResourceAddress(), request.properties)); + } + + return mono.doOnSuccess(aVoid -> request.requestContext.resolvedCollectionRid = null); + } + + private class CollectionRidComparer implements IEqualityComparer { + public boolean areEqual(DocumentCollection left, DocumentCollection right) { + if (left == null && right == null) { + return true; + } + + if ((left == null) ^ (right == null)) { + return false; + } + + return StringUtils.equals(left.resourceId(), right.resourceId()); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxPartitionKeyRangeCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxPartitionKeyRangeCache.java new file mode 100644 index 0000000000000..c52fdd85ce0f5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/caches/RxPartitionKeyRangeCache.java @@ -0,0 +1,230 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.IServerIdentity; +import com.azure.data.cosmos.internal.routing.InMemoryCollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.Range; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + **/ +public class RxPartitionKeyRangeCache implements IPartitionKeyRangeCache { + private final Logger logger = LoggerFactory.getLogger(RxPartitionKeyRangeCache.class); + + private final AsyncCache routingMapCache; + private final AsyncDocumentClient client; + private final RxCollectionCache collectionCache; + + public RxPartitionKeyRangeCache(AsyncDocumentClient client, RxCollectionCache collectionCache) { + this.routingMapCache = new AsyncCache<>(); + this.client = client; + this.collectionCache = collectionCache; + } + + /* (non-Javadoc) + * @see IPartitionKeyRangeCache#tryLookupAsync(java.lang.STRING, com.azure.data.cosmos.internal.routing.CollectionRoutingMap) + */ + @Override + public Mono tryLookupAsync(String collectionRid, CollectionRoutingMap previousValue, Map properties) { + return routingMapCache.getAsync( + collectionRid, + previousValue, + () -> getRoutingMapForCollectionAsync(collectionRid, previousValue, properties)) + .onErrorResume(err -> { + logger.debug("tryLookupAsync on collectionRid {} encountered failure", collectionRid, err); + CosmosClientException dce = Utils.as(err, CosmosClientException.class); + if (dce != null && Exceptions.isStatusCode(dce, HttpConstants.StatusCodes.NOTFOUND)) { + return Mono.empty(); + } + + return Mono.error(err); + }); + } + + @Override + public Mono tryLookupAsync(String collectionRid, CollectionRoutingMap previousValue, boolean forceRefreshCollectionRoutingMap, + Map properties) { + return tryLookupAsync(collectionRid, previousValue, properties); + } + + /* (non-Javadoc) + * @see IPartitionKeyRangeCache#tryGetOverlappingRangesAsync(java.lang.STRING, com.azure.data.cosmos.internal.routing.RANGE, boolean) + */ + @Override + public Mono> tryGetOverlappingRangesAsync(String collectionRid, Range range, boolean forceRefresh, + Map properties) { + + Mono routingMapObs = tryLookupAsync(collectionRid, null, properties); + + return routingMapObs.flatMap(routingMap -> { + if (forceRefresh) { + logger.debug("tryGetOverlappingRangesAsync with forceRefresh on collectionRid {}", collectionRid); + return tryLookupAsync(collectionRid, routingMap, properties); + } + + return Mono.just(routingMap); + }).switchIfEmpty(Mono.empty()).map(routingMap -> routingMap.getOverlappingRanges(range)).switchIfEmpty(Mono.defer(() -> { + logger.debug("Routing Map Null for collection: {} for range: {}, forceRefresh:{}", collectionRid, range.toString(), forceRefresh); + return Mono.empty(); + })); + } + + /* (non-Javadoc) + * @see IPartitionKeyRangeCache#tryGetPartitionKeyRangeByIdAsync(java.lang.STRING, java.lang.STRING, boolean) + */ + @Override + public Mono tryGetPartitionKeyRangeByIdAsync(String collectionResourceId, String partitionKeyRangeId, + boolean forceRefresh, Map properties) { + + Mono routingMapObs = tryLookupAsync(collectionResourceId, null, properties); + + return routingMapObs.flatMap(routingMap -> { + if (forceRefresh && routingMap != null) { + return tryLookupAsync(collectionResourceId, routingMap, properties); + } + return Mono.justOrEmpty(routingMap); + + }).switchIfEmpty(Mono.defer(Mono::empty)).map(routingMap -> routingMap.getRangeByPartitionKeyRangeId(partitionKeyRangeId)).switchIfEmpty(Mono.defer(() -> { + logger.debug("Routing Map Null for collection: {}, PartitionKeyRangeId: {}, forceRefresh:{}", collectionResourceId, partitionKeyRangeId, forceRefresh); + return null; + })); + } + + /* (non-Javadoc) + * @see IPartitionKeyRangeCache#tryGetRangeByPartitionKeyRangeId(java.lang.STRING, java.lang.STRING) + */ + @Override + public Mono tryGetRangeByPartitionKeyRangeId(String collectionRid, String partitionKeyRangeId, Map properties) { + Mono routingMapObs = routingMapCache.getAsync( + collectionRid, + null, + () -> getRoutingMapForCollectionAsync(collectionRid, null, properties)); + + return routingMapObs.map(routingMap -> routingMap.getRangeByPartitionKeyRangeId(partitionKeyRangeId)) + .onErrorResume(err -> { + CosmosClientException dce = Utils.as(err, CosmosClientException.class); + logger.debug("tryGetRangeByPartitionKeyRangeId on collectionRid {} and partitionKeyRangeId {} encountered failure", + collectionRid, partitionKeyRangeId, err); + + if (dce != null && Exceptions.isStatusCode(dce, HttpConstants.StatusCodes.NOTFOUND)) { + return Mono.empty(); + } + + return Mono.error(dce); + }); + } + + private Mono getRoutingMapForCollectionAsync( + String collectionRid, + CollectionRoutingMap previousRoutingMap, + Map properties) { + + // TODO: NOTE: main java code doesn't do anything in regard to the previous routing map + // .Net code instead of using DocumentClient controls sending request and receiving requests here + + // here we stick to what main java sdk does, investigate later. + + Mono> rangesObs = getPartitionKeyRange(collectionRid, false, properties); + + return rangesObs.flatMap(ranges -> { + + List> rangesTuples = + ranges.stream().map(range -> new ImmutablePair<>(range, (IServerIdentity) null)).collect(Collectors.toList()); + + + CollectionRoutingMap routingMap; + if (previousRoutingMap == null) + { + // Splits could have happened during change feed query and we might have a mix of gone and new ranges. + Set goneRanges = new HashSet<>(ranges.stream().flatMap(range -> CollectionUtils.emptyIfNull(range.getParents()).stream()).collect(Collectors.toSet())); + + routingMap = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap( + rangesTuples.stream().filter(tuple -> !goneRanges.contains(tuple.left.id())).collect(Collectors.toList()), + collectionRid); + } + else + { + routingMap = previousRoutingMap.tryCombine(rangesTuples); + } + + if (routingMap == null) + { + // RANGE information either doesn't exist or is not complete. + return Mono.error(new NotFoundException(String.format("GetRoutingMapForCollectionAsync(collectionRid: {%s}), RANGE information either doesn't exist or is not complete.", collectionRid))); + } + + return Mono.just(routingMap); + }); + } + + private Mono> getPartitionKeyRange(String collectionRid, boolean forceRefresh, Map properties) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + OperationType.ReadFeed, + collectionRid, + ResourceType.PartitionKeyRange, + null + ); //this request doesn't actually go to server + + request.requestContext.resolvedCollectionRid = collectionRid; + Mono collectionObs = collectionCache.resolveCollectionAsync(request); + + return collectionObs.flatMap(coll -> { + + FeedOptions feedOptions = new FeedOptions(); + if (properties != null) { + feedOptions.properties(properties); + } + return client.readPartitionKeyRanges(coll.selfLink(), feedOptions) + // maxConcurrent = 1 to makes it in the right order + .flatMap(p -> Flux.fromIterable(p.results()), 1).collectList(); + }); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Bootstrapper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Bootstrapper.java new file mode 100644 index 0000000000000..1ebd65c2160bf --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Bootstrapper.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Bootstrapping interface. + */ +public interface Bootstrapper { + /** + * It initializes the bootstrapping. + * + * @return a deferred computation of this call. + */ + Mono initialize(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationToken.java new file mode 100644 index 0000000000000..cf5ff3eddd2b4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationToken.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * Propagates notification that operations should be canceled.. + */ +public class CancellationToken { + private final CancellationTokenSource tokenSource; + + public CancellationToken(CancellationTokenSource source) { + this.tokenSource = source; + } + + /** + * @return true if the cancellation was requested from the source. + */ + public boolean isCancellationRequested() { + return tokenSource.isCancellationRequested(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationTokenSource.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationTokenSource.java new file mode 100644 index 0000000000000..7cb363ca3a96a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CancellationTokenSource.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import java.io.Closeable; +import java.io.IOException; + +/** + * Signals to a {@link CancellationToken} that it should be canceled.. + */ +public class CancellationTokenSource implements Closeable { + + private volatile boolean tokenSourceClosed; + private volatile boolean cancellationRequested; + + public CancellationTokenSource() { + this.tokenSourceClosed = false; + this.cancellationRequested = false; + } + + public synchronized boolean isCancellationRequested() { + if (tokenSourceClosed) { + throw new IllegalStateException("Object already closed"); + } + + return this.cancellationRequested; + } + + public CancellationToken getToken() { + return new CancellationToken(this); + } + + public synchronized void cancel() { + this.cancellationRequested = true; + } + + @Override + public synchronized void close() throws IOException { + if (tokenSourceClosed) return; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedContextClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedContextClient.java new file mode 100644 index 0000000000000..f715a440fcb61 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedContextClient.java @@ -0,0 +1,164 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerResponse; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseRequestOptions; +import com.azure.data.cosmos.CosmosDatabaseResponse; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URI; + +/** + * The interface that captures the APIs required to handle change feed processing logic. + */ +public interface ChangeFeedContextClient { + /** + * Reads the feed (sequence) of {@link PartitionKeyRange} for a database account from the Azure Cosmos DB service as an asynchronous operation. + * + * @param partitionKeyRangesOrCollectionLink the link of the resources to be read, or owner collection link, SelfLink or AltLink. E.g. /dbs/db_rid/colls/coll_rid/pkranges. + * @param feedOptions the options for the request; it can be set as null. + * @return an an {@link Flux} containing one or several feed response pages of the obtained items or an error. + */ + Flux> readPartitionKeyRangeFeed(String partitionKeyRangesOrCollectionLink, FeedOptions feedOptions); + + /** + * Method to create a change feed query for documents. + * + * @param collectionLink Specifies the collection to read documents from. + * @param feedOptions The options for processing the query results feed. + * @return an {@link Flux} containing one or several feed response pages of the obtained items or an error. + */ + Flux> createDocumentChangeFeedQuery(CosmosContainer collectionLink, ChangeFeedOptions feedOptions); + + /** + * Reads a database. + * + * @param database a reference to the database. + * @param options the {@link CosmosContainerRequestOptions} for this request; it can be set as null. + * @return an {@link Mono} containing the single cosmos database response with the read database or an error. + */ + Mono readDatabase(CosmosDatabase database, CosmosDatabaseRequestOptions options); + + /** + * Reads a {@link CosmosContainer}. + * + * @param containerLink a reference to the container. + * @param options the {@link CosmosContainerRequestOptions} for this request; it can be set as null. + * @return an {@link Mono} containing the single cosmos container response with the read container or an error. + */ + Mono readContainer(CosmosContainer containerLink, CosmosContainerRequestOptions options); + + /** + * Creates a {@link CosmosItem}. + * + * @param containerLink the reference to the parent container. + * @param document the document represented as a POJO or Document object. + * @param options the request options. + * @param disableAutomaticIdGeneration the flag for disabling automatic id generation. + * @return an {@link Mono} containing the single resource response with the created cosmos item or an error. + */ + Mono createItem(CosmosContainer containerLink, Object document, CosmosItemRequestOptions options, + boolean disableAutomaticIdGeneration); + + /** + * DELETE a {@link CosmosItem}. + * + * @param itemLink the item reference. + * @param options the request options. + * @return an {@link Mono} containing the cosmos item resource response with the deleted item or an error. + */ + Mono deleteItem(CosmosItem itemLink, CosmosItemRequestOptions options); + + /** + * Replaces a {@link CosmosItem}. + * + * @param itemLink the item reference. + * @param document the document represented as a POJO or Document object. + * @param options the request options. + * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. + */ + Mono replaceItem(CosmosItem itemLink, Object document, CosmosItemRequestOptions options); + + /** + * Reads a {@link CosmosItem} + * + * @param itemLink the item reference. + * @param options the request options. + * @return an {@link Mono} containing the cosmos item resource response with the read item or an error. + */ + Mono readItem(CosmosItem itemLink, CosmosItemRequestOptions options); + + /** + * Query for items in a document container. + * + * @param containerLink the reference to the parent container. + * @param querySpec the SQL query specification. + * @param options the feed options. + * @return an {@link Flux} containing one or several feed response pages of the obtained items or an error. + */ + Flux> queryItems(CosmosContainer containerLink, SqlQuerySpec querySpec, FeedOptions options); + + /** + * @return the Cosmos client's service endpoint. + */ + URI getServiceEndpoint(); + + /** + * Reads and returns the container properties. + * + * @param containerLink a reference to the container. + * @param options the {@link CosmosContainerRequestOptions} for this request; it can be set as null. + * @return an {@link Mono} containing the read container properties. + */ + Mono readContainerSettings(CosmosContainer containerLink, CosmosContainerRequestOptions options); + + /** + * @return the Cosmos container client. + */ + CosmosContainer getContainerClient(); + + /** + * @return the Cosmos database client. + */ + CosmosDatabase getDatabaseClient(); + + /** + * Closes the document client instance and cleans up the resources. + */ + void close(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserver.java new file mode 100644 index 0000000000000..b360c22b4c44d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserver.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosItemProperties; + +import java.util.List; + +/** + * The interface used to deliver change events to document feed observers. + */ +public interface ChangeFeedObserver { + /** + * This is called when change feed observer is opened. + * + * @param context the context specifying partition for this observer, etc. + */ + void open(ChangeFeedObserverContext context); + + /** + * This is called when change feed observer is closed. + * + * @param context the context specifying partition for this observer, etc. + * @param reason the reason the observer is closed. + */ + void close(ChangeFeedObserverContext context, ChangeFeedObserverCloseReason reason); + + /** + * This is called when document changes are available on change feed. + * + * @param context the context specifying partition for this observer, etc. + * @param docs the documents changed. + */ + void processChanges(ChangeFeedObserverContext context, List docs); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverCloseReason.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverCloseReason.java new file mode 100644 index 0000000000000..4b2ef51483b51 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverCloseReason.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * The reason for the {@link ChangeFeedObserver} to close. + */ +public enum ChangeFeedObserverCloseReason { + /** + * UNKNOWN failure. This should never be sent to observers. + */ + UNKNOWN, + + /** + * The ChangeFeedEventProcessor is shutting down. + */ + SHUTDOWN, + + /** + * The resource, such as database or collection was removed. + */ + RESOURCE_GONE, + + /** + * Lease was lost due to expiration or load-balancing. + */ + LEASE_LOST, + + /** + * ChangeFeedObserver threw an exception. + */ + OBSERVER_ERROR, + + /** + * The lease is gone. This can be due to partition split. + */ + LEASE_GONE, +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverContext.java new file mode 100644 index 0000000000000..15d18034a8e2a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverContext.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedResponse; +import reactor.core.publisher.Mono; + +/** + * Represents the context passed to {@link ChangeFeedObserver} events. + */ +public interface ChangeFeedObserverContext { + + /** + * Gets the id of the partition for the current event. + * + * @return the id of the partition for the current event. + */ + String getPartitionKeyRangeId(); + + /** + * Gets the response from the underlying call. + * + * @return the response from the underlying call. + */ + FeedResponse getFeedResponse(); + + /** + * Checkpoints progress of a stream. This method is valid only if manual checkpoint was configured. + *

    + * Client may accept multiple change feed batches to process in parallel. + * Once first N document processing was finished the client can call checkpoint on the last completed batches in the row. + * In case of automatic checkpointing this is method throws. + * + * @return a representation of the deferred computation of this call. + */ + Mono checkpoint(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverFactory.java new file mode 100644 index 0000000000000..b87929bd4a1cc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ChangeFeedObserverFactory.java @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * Factory class used to create instance(s) of {@link ChangeFeedObserver}. + */ +public interface ChangeFeedObserverFactory { + /** + * Creates an instance of a {@link ChangeFeedObserver}. + * + * @return an instance of a {@link ChangeFeedObserver}. + */ + ChangeFeedObserver createObserver(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CheckpointFrequency.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CheckpointFrequency.java new file mode 100644 index 0000000000000..e6ab9a3e83eee --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/CheckpointFrequency.java @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import java.time.Duration; + +/** + * Specifies the frequency of lease event. The event will trigger when either of conditions is satisfied. + */ +public class CheckpointFrequency { + private boolean explicitCheckpoint; + private int processedDocumentCount; + private Duration timeInterval; + + public CheckpointFrequency() { + this.explicitCheckpoint = false; + // DEFAULT to always checkpoint after processing each feed batch. + processedDocumentCount = 0; + timeInterval = null; + } + + /** + * Gets a value indicating whether explicit check-pointing is enabled. + *

    + * By default false. Setting to true means changefeed host will never checkpoint and client code needs to explicitly + * checkpoint via {@link PartitionCheckpointer} + * + * @return a value indicating whether explicit check-pointing is enabled. + */ + public boolean isExplicitCheckpoint() { + return explicitCheckpoint; + } + + /** + * Gets the value that specifies to checkpoint every specified number of docs. + * + * @return the value that specifies to checkpoint every specified number of docs. + */ + public int getProcessedDocumentCount() { + return this.processedDocumentCount; + } + + /** + * Gets the value that specifies to checkpoint every specified time interval. + * + * @return the value that specifies to checkpoint every specified time interval. + */ + public Duration getTimeInterval() { + return this.timeInterval; + } + + /** + * Sets a value indicating explicit check-pointing is enabled. + * + * @return current {@link CheckpointFrequency}. + */ + public CheckpointFrequency withExplicitCheckpoint() { + this.explicitCheckpoint = true; + return this; + } + + /** + * Sets a value indicating explicit checkpointing is disabled. + * + * @return current {@link CheckpointFrequency}. + */ + public CheckpointFrequency withoutExplicitCheckpoint() { + this.explicitCheckpoint = false; + return this; + } + + /** + * Sets the value that specifies to checkpoint every specified number of docs. + * + * @param processedDocumentCount the value that specifies to checkpoint every specified number of docs. + * @return current {@link CheckpointFrequency}. + */ + public CheckpointFrequency withProcessedDocumentCount(int processedDocumentCount) { + this.processedDocumentCount = processedDocumentCount; + return this; + } + + /** + * Sets the value that specifies to checkpoint every specified time interval. + * + * @param timeInterval the value that specifies to checkpoint every specified time interval. + * @return current {@link CheckpointFrequency}. + */ + public CheckpointFrequency withTimeInterval(Duration timeInterval) { + this.timeInterval = timeInterval; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitor.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitor.java new file mode 100644 index 0000000000000..f5c99caeea8d6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitor.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * A strategy for handling the situation when the change feed processor is not able to acquire lease due to unknown reasons. + */ +public interface HealthMonitor { + /** + * A logic to handle that exceptional situation. + * + * @param record the monitoring record. + * @return a representation of the deferred computation of this call. + */ + Mono inspect(HealthMonitoringRecord record); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitoringRecord.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitoringRecord.java new file mode 100644 index 0000000000000..c0aadd7660feb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/HealthMonitoringRecord.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * A record used in the health monitoring. + */ +public class HealthMonitoringRecord { + public final HealthSeverity severity; + public final MonitoredOperation operation; + public final Lease lease; + public final Throwable throwable; + + /** + * Initializes a new instance of the {@link HealthMonitoringRecord} class. + * + * @param severity the health severity level. + * @param operation the operation. + * @param lease the lease. + * @param throwable the exception. + */ + public HealthMonitoringRecord(HealthSeverity severity, MonitoredOperation operation, Lease lease, Throwable throwable) { + if (lease == null) throw new IllegalArgumentException("lease"); + this.severity = severity; + this.operation = operation; + this.lease = lease; + this.throwable = throwable; + } + + /** + * @return the severity of this monitoring record. + */ + public HealthSeverity getSeverity() { + return this.severity; + } + + /** + * The health severity level. + */ + public enum HealthSeverity { + /** + * Critical level. + */ + CRITICAL(10), + + /** + * Error level. + */ + ERROR(20), + + /** + * Information level. + */ + INFORMATIONAL(30); + + public final int value; + + HealthSeverity(int value){ + this.value = value; + } + } + + /** + * The health monitoring phase. + */ + public enum MonitoredOperation { + /** + * A phase when the instance tries to acquire the lease. + */ + ACQUIRE_LEASE, + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Lease.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Lease.java new file mode 100644 index 0000000000000..178dd354080d4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/Lease.java @@ -0,0 +1,142 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.ChangeFeedProcessor; + +import java.time.ZonedDateTime; +import java.util.Map; + +/** + * Represents a lease that is persisted as a document in the lease collection. + *

    + * Leases are used to: + * Keep track of the {@link ChangeFeedProcessor} progress for a particular Partition Key RANGE. + * Distribute load between different instances of {@link ChangeFeedProcessor}. + * Ensure reliable recovery for cases when an instance of {@link ChangeFeedProcessor} gets disconnected, hangs or crashes. + */ +public interface Lease { + /** + * Gets the partition associated with the lease. + * + * @return the partition associated with the lease. + */ + String getLeaseToken(); + + /** + * Gets the host name owner of the lease. + * + *

    + * The Owner keeps track which {@link ChangeFeedProcessor} is currently processing that Partition Key RANGE. + * + * @return the host name owner of the lease. + */ + String getOwner(); + + /** + * Gets the timestamp of the lease. + * + * @return the timestamp of the lease. + */ + String getTimestamp(); + + /** + * Gets the continuation token used to determine the last processed point of the Change Feed. + * + * @return the continuation token used to determine the last processed point of the Change Feed. + */ + String getContinuationToken(); + + /** + * Sets the continuation token used to determine the last processed point of the Change Feed. + * + * + * @param continuationToken the continuation token used to determine the last processed point of the Change Feed. + */ + void setContinuationToken(String continuationToken); + + /** + * Gets the lease ID. + * + * @return the lease ID. + */ + String getId(); + + /** + * Gets the concurrency token. + * + * @return the concurrency token. + */ + String getConcurrencyToken(); + + /** + * Gets the custom lease item which can be managed from {@link PartitionLoadBalancingStrategy}. + * + * @return the custom lease item. + */ + Map getProperties(); + + /** + * Sets the host name owner of the lease. + * + *

    + * The Owner keeps track which {@link ChangeFeedProcessor} is currently processing that Partition Key RANGE. + * + * @param owner the host name owner of the lease. + */ + void setOwner(String owner); + + /** + * Sets the timestamp of the lease. + * + *

    + * The timestamp is used to determine lease expiration. + * + * @param timestamp the timestamp of the lease. + */ + void setTimestamp(ZonedDateTime timestamp); + + /** + * Sets the lease ID. + * + * + * @param id the lease ID. + */ + void setId(String id); + + /** + * Sets the concurrency token. + * + * + * @param concurrencyToken the concurrency token. + */ + void setConcurrencyToken(String concurrencyToken); + + /** + * Sets the custom lease item which can be managed from {@link PartitionLoadBalancingStrategy}. + * + * + * @param properties the custom lease item. + */ + void setProperties(Map properties); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseCheckpointer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseCheckpointer.java new file mode 100644 index 0000000000000..da413ca2bdefd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseCheckpointer.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface for check-pointing the lease. + */ +public interface LeaseCheckpointer { + /** + * Check-points the lease. + *

    + * Throws LeaseLostException if other host acquired the lease or lease was deleted. + * + * @param lease the lease to renew. + * @param continuationToken the continuation token. + * @return the updated renewed lease. + */ + Mono checkpoint(Lease lease, String continuationToken); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseContainer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseContainer.java new file mode 100644 index 0000000000000..be77084431c3d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseContainer.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Flux; + +/** + * Represents operations to get leases from lease store.. + */ +public interface LeaseContainer { + /** + * @return all leases. + */ + Flux getAllLeases(); + + /** + * @return all leases owned by the current host. + */ + Flux getOwnedLeases(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseManager.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseManager.java new file mode 100644 index 0000000000000..342213d20d075 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseManager.java @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.internal.changefeed.exceptions.LeaseLostException; +import reactor.core.publisher.Mono; + +/** + * It defines a way to perform operations with {@link Lease}. + */ +public interface LeaseManager { + /** + * Checks whether the lease exists and creates it if it does not exist. + * + * @param leaseToken the lease token to work with. + * @param continuationToken the continuation token if it exists. + * @return the lease. + */ + Mono createLeaseIfNotExist(String leaseToken, String continuationToken); + + /** + * Deletes the lease. + * + * @param lease the lease to delete. + * @return a deferred computation of this call. + */ + Mono delete(Lease lease); + + /** + * Acquires ownership of the lease. + * It can throw {@link LeaseLostException} if other host acquired concurrently the lease. + * + * @param lease the lease to acquire. + * @return the updated lease. + */ + Mono acquire(Lease lease); + + /** + * It releases ownership of the lease. + * It can throw {@link LeaseLostException} if other host acquired the lease. + * + * @param lease the lease to acquire. + * @return a deferred computation of this call. + */ + Mono release(Lease lease); + + /** + * Renew the lease; leases are periodically renewed to prevent expiration. + * It can throw {@link LeaseLostException} if other host acquired the lease. + * + * @param lease the lease to renew. + * @return the updated lease. + */ + Mono renew(Lease lease); + + /** + * REPLACE item from the specified lease. + * It can throw {@link LeaseLostException} if other host acquired the lease. + * + * @param leaseToUpdatePropertiesFrom the new item. + * @return updated lease. + */ + Mono updateProperties(Lease leaseToUpdatePropertiesFrom); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseRenewer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseRenewer.java new file mode 100644 index 0000000000000..07795e34f8131 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseRenewer.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface for the lease renewer. + */ +public interface LeaseRenewer { + /** + * Starts the lease renewer. + * + * @param cancellationToken the token used for canceling the workload. + * @return a deferred operation of this call. + */ + Mono run(CancellationToken cancellationToken); + + /** + * @return the inner exception if any, otherwise null. + */ + RuntimeException getResultException(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStore.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStore.java new file mode 100644 index 0000000000000..b443127de135b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStore.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Represents the lease store container to deal with initialization/cleanup of leases + * for particular monitoring collection and lease container prefix. + */ +public interface LeaseStore { + + /** + * @return true if the lease store is initialized. + */ + Mono isInitialized(); + + /** + * Mark the store as initialized. + * + * @return a deferred computation of this operation call. + */ + Mono markInitialized(); + + /** + * Places a lock on the lease store for initialization. Only one process may own the store for the lock time. + * + * @param lockExpirationTime the time for the lock to expire. + * @return true if the lock was acquired, false otherwise. + */ + Mono acquireInitializationLock(Duration lockExpirationTime); + + /** + * Releases the lock one the lease store for initialization. + * + * @return true if the lock was acquired and was released, false if the lock was not acquired. + */ + Mono releaseInitializationLock(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManager.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManager.java new file mode 100644 index 0000000000000..75f06ef593fd2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManager.java @@ -0,0 +1,153 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.internal.changefeed.implementation.LeaseStoreManagerImpl; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Defines an interface for operations with {@link Lease}. + */ +public interface LeaseStoreManager extends LeaseContainer, LeaseManager, LeaseStore, LeaseCheckpointer +{ + /** + * Provides flexible way to build lease manager constructor parameters. + * For the actual creation of lease manager instance, delegates to lease manager factory. + */ + interface LeaseStoreManagerBuilderDefinition { + LeaseStoreManagerBuilderDefinition leaseContextClient(ChangeFeedContextClient leaseContextClient); + + LeaseStoreManagerBuilderDefinition leasePrefix(String leasePrefix); + + LeaseStoreManagerBuilderDefinition leaseCollectionLink(CosmosContainer leaseCollectionLink); + + LeaseStoreManagerBuilderDefinition requestOptionsFactory(RequestOptionsFactory requestOptionsFactory); + + LeaseStoreManagerBuilderDefinition hostName(String hostName); + + Mono build(); + } + + static LeaseStoreManagerBuilderDefinition Builder() { + return new LeaseStoreManagerImpl(); + } + + /** + * @return List of all leases. + */ + Flux getAllLeases(); + + /** + * @return all leases owned by the current host. + */ + Flux getOwnedLeases(); + + /** + * Checks whether the lease exists and creates it if it does not exist. + * + * @param leaseToken the partition to work on. + * @param continuationToken the continuation token if it exists. + * @return the lease. + */ + Mono createLeaseIfNotExist(String leaseToken, String continuationToken); + + /** + * DELETE the lease. + * + * @param lease the lease to remove. + * @return a representation of the deferred computation of this call. + */ + Mono delete(Lease lease); + + /** + * Acquire ownership of the lease. + * + * @param lease the Lease to acquire. + * @return the updated acquired lease. + */ + Mono acquire(Lease lease); + + /** + * Release ownership of the lease. + * + * @param lease the lease to acquire. + * @return a representation of the deferred computation of this call. + */ + Mono release(Lease lease); + + /** + * Renew the lease. Leases are periodically renewed to prevent expiration. + * + * @param lease the Lease to renew. + * @return the updated renewed lease. + */ + Mono renew(Lease lease); + + /** + * REPLACE item from the specified lease. + * + * @param leaseToUpdatePropertiesFrom the Lease containing new item. + * @return the updated lease. + */ + Mono updateProperties(Lease leaseToUpdatePropertiesFrom); + + /** + * Checkpoint the lease. + * + * @param lease the Lease to renew. + * @param continuationToken the continuation token. + * @return the updated renewed lease. + */ + Mono checkpoint(Lease lease, String continuationToken); + + /** + * @return true if the lease store is initialized. + */ + Mono isInitialized(); + + /** + * Mark the store as initialized. + * + * @return true if marked as initialized. + */ + Mono markInitialized(); + + /** + * Places a lock on the lease store for initialization. Only one process may own the store for the lock time. + * + * @param lockExpirationTime the time for the lock to expire. + * @return true if the lock was acquired, false otherwise. + */ + Mono acquireInitializationLock(Duration lockExpirationTime); + + /** + * Releases the lock one the lease store for initialization. + * + * @return true if the lock was acquired and was relesed, false if the lock was not acquired. + */ + Mono releaseInitializationLock(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManagerSettings.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManagerSettings.java new file mode 100644 index 0000000000000..8c892d4d4d440 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/LeaseStoreManagerSettings.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosContainer; + +/** + * Captures LeaseStoreManager properties. + */ +public class LeaseStoreManagerSettings { + String containerNamePrefix; + + CosmosContainer leaseCollectionLink; + + String hostName; + + public String getContainerNamePrefix() { + return this.containerNamePrefix; + } + + public LeaseStoreManagerSettings withContainerNamePrefix(String containerNamePrefix) { + this.containerNamePrefix = containerNamePrefix; + return this; + } + + public CosmosContainer getLeaseCollectionLink() { + return this.leaseCollectionLink; + } + + public LeaseStoreManagerSettings withLeaseCollectionLink(CosmosContainer collectionLink) { + this.leaseCollectionLink = collectionLink; + return this; + } + + public String getHostName() { + return this.hostName; + } + + public LeaseStoreManagerSettings withHostName(String hostName) { + this.hostName = hostName; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionCheckpointer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionCheckpointer.java new file mode 100644 index 0000000000000..62abcd75e7d16 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionCheckpointer.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Checkpoint the given partition up to the given continuation token. + */ +public interface PartitionCheckpointer { + /** + * Checkpoints the given partition up to the given continuation token. + * + * @param сontinuationToken the continuation token. + * @return a deferred operation of this call. + */ + Mono checkpointPartition(String сontinuationToken); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionController.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionController.java new file mode 100644 index 0000000000000..8e30828ad016b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionController.java @@ -0,0 +1,51 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface for the partition controller. + */ +public interface PartitionController { + /** + * Add or update lease item. + * + * @return a representation of the deferred computation of this call. + */ + Mono addOrUpdateLease(Lease lease); + + /** + * Initialize and start the partition controller thread. + * + * @return a representation of the deferred computation of this call. + */ + Mono initialize(); + + /** + * Shutdown partition controller thread. + * + * @return a representation of the deferred computation of this call. + */ + Mono shutdown(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancer.java new file mode 100644 index 0000000000000..4d580d67bbbe5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancer.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface for a partition load balancer. + */ +public interface PartitionLoadBalancer { + /** + * Starts the load balancer. + * + * @return a representation of the deferred computation of this call. + */ + Mono start(); + + /** + * Stops the load balancer. + * + * @return a representation of the deferred computation of this call. + */ + Mono stop(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancingStrategy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancingStrategy.java new file mode 100644 index 0000000000000..b8ad4f05fec68 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionLoadBalancingStrategy.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.ChangeFeedProcessorOptions; + +import java.util.List; + +/** + * A strategy defines which leases should be taken by the current host in a certain moment. + *

    + * It can set new {@link Lease} properties() for all returned leases if needed, including currently owned leases. + * Example + *

    + * {@code
    + *  public class CustomStrategy : PartitionLoadBalancingStrategy
    + *  {
    + *      private STRING hostName;
    + *      private STRING hostVersion;
    + *      private Duration leaseExpirationInterval;
    + *
    + *      private final STRING VersionPropertyKey = "version";
    + *
    + *      public List selectLeasesToTake(List allLeases)
    + *      {
    + *          var takenLeases = this.findLeasesToTake(allLeases);
    + *          foreach (var lease in takenLeases)
    + *          {
    + *              lease.Properties[VersionPropertyKey] = this.hostVersion;
    + *          }
    + *
    + *          return takenLeases;
    + *      }
    + *
    + *      private List findLeasesToTake(List allLeases)
    + *      {
    + *          List takenLeases = new List();
    + *          foreach (var lease in allLeases)
    + *          {
    + *              if (string.IsNullOrWhiteSpace(lease.Owner) || this.IsExpired(lease))
    + *              {
    + *                  takenLeases.Add(lease);
    + *              }
    + *
    + *              if (lease.Owner != this.hostName)
    + *              {
    + *                  var ownerVersion = lease.Properties[VersionPropertyKey];
    + *                  if (ownerVersion < this.hostVersion)
    + *                  {
    + *                      takenLeases.Add(lease);
    + *                  }
    + *
    + *                  // more logic for leases owned by other hosts
    + *              }
    + *          }
    + *
    + *          return takenLeases;
    + *      }
    + *
    + *      private boolean isExpired(Lease lease)
    + *      {
    + *          return lease.Timestamp.ToUniversalTime() + this.leaseExpirationInterval < DateTime.UtcNow;
    + *      }
    + *  } * }
    + * 
    + * + */ +public interface PartitionLoadBalancingStrategy { + /** + * Select leases that should be taken for processing. + * This method will be called periodically with {@link ChangeFeedProcessorOptions} leaseAcquireInterval(). + + * @param allLeases ALL leases. + * @return Leases that should be taken for processing by this host. + */ + List selectLeasesToTake(List allLeases); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionManager.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionManager.java new file mode 100644 index 0000000000000..a82f07e70b2bc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionManager.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface PartitionManager. + */ +public interface PartitionManager { + /** + * starts the partition manager. + * + * @return a representation of the deferred computation of this call. + */ + Mono start(); + + /** + * Stops the partition manager. + * + * @return a representation of the deferred computation of this call. + */ + Mono stop(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessor.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessor.java new file mode 100644 index 0000000000000..5f0a7b54ca584 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessor.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Provides an API to run continious processing on a single partition of some resource. + *

    + * Created by {@link PartitionProcessorFactory}.create() after some lease is acquired by the current host. + * Processing can perform the following tasks in a loop: + * 1. READ some data from the resource partition. + * 2. Handle possible problems with the read. + * 3. Pass the obtained data to an observer by calling {@link ChangeFeedObserver}.processChangesAsync{} with the context {@link ChangeFeedObserverContext}. + */ +public interface PartitionProcessor { + /** + * Perform partition processing. + * + * @param cancellationToken the cancellation token. + * @return a representation of the deferred computation of this call. + */ + Mono run(CancellationToken cancellationToken); + + /** + * @return the inner exception if any, otherwise null. + */ + RuntimeException getResultException(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessorFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessorFactory.java new file mode 100644 index 0000000000000..23f1e357e2e22 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionProcessorFactory.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * Factory class used to create instance(s) of {@link PartitionProcessor}. + */ +public interface PartitionProcessorFactory { + /** + * Creates an instance of a {@link PartitionProcessor}. + * + * @param lease the lease to be used for partition processing. + * @param changeFeedObserver the observer instace to be used. + * @return an instance of {@link PartitionProcessor}. + */ + PartitionProcessor create(Lease lease, ChangeFeedObserver changeFeedObserver); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisor.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisor.java new file mode 100644 index 0000000000000..49a934d8bdf4d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisor.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Mono; + +/** + * Interface for the partition supervisor. + */ +public interface PartitionSupervisor { + /** + * Runs the task. + * + * @param cancellationToken the cancellation token. + * @return a deferred operation of this call. + */ + Mono run(CancellationToken cancellationToken); + + /** + * @return the inner exception if any, otherwise null. + */ + RuntimeException getResultException(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisorFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisorFactory.java new file mode 100644 index 0000000000000..3dfffb012078c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSupervisorFactory.java @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * Interface for the partition supervisor factory. + */ +public interface PartitionSupervisorFactory { + /** + * + * @param lease the lease. + * @return an instance of {@link PartitionSupervisor}. + */ + PartitionSupervisor create(Lease lease); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSynchronizer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSynchronizer.java new file mode 100644 index 0000000000000..fdd24569726ea --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/PartitionSynchronizer.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * READ DocDB partitions and create leases if they do not exist. + */ +public interface PartitionSynchronizer { + /** + * Creates missing leases. + * + * @return a deferred computation of this operation. + */ + Mono createMissingLeases(); + + /** + * Handles partition slip. + * + * @param lease the lease. + * @return the split partition documents. + */ + Flux splitPartition(Lease lease); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ProcessorSettings.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ProcessorSettings.java new file mode 100644 index 0000000000000..9a9463f5c72cf --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ProcessorSettings.java @@ -0,0 +1,116 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosContainer; + +import java.time.Duration; +import java.time.OffsetDateTime; + +/** + * Implementation for the partition processor properties. + */ +public class ProcessorSettings { + private CosmosContainer collectionSelfLink; + private String partitionKeyRangeId; + private Integer maxItemCount; + private Duration feedPollDelay; + private String startContinuation; + private OffsetDateTime startTime; +// private STRING sessionToken; + + public CosmosContainer getCollectionSelfLink() { + return this.collectionSelfLink; + } + + public ProcessorSettings withCollectionLink(CosmosContainer collectionLink) { + this.collectionSelfLink = collectionLink; + return this; + } + + public String getPartitionKeyRangeId() { + return this.partitionKeyRangeId; + } + + public ProcessorSettings withPartitionKeyRangeId(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + return this; + } + + public int getMaxItemCount() { + return this.maxItemCount; + } + + public ProcessorSettings withMaxItemCount(int maxItemCount) { + this.maxItemCount = maxItemCount; + return this; + } + + public Duration getFeedPollDelay() { + return this.feedPollDelay; + } + + public ProcessorSettings withFeedPollDelay(Duration feedPollDelay) { + this.feedPollDelay = feedPollDelay; + return this; + } + + public String getStartContinuation() { + return this.startContinuation; + } + + public ProcessorSettings withStartContinuation(String startContinuation) { + this.startContinuation = startContinuation; + return this; + } + + private boolean startFromBeginning; + + public boolean isStartFromBeginning() { + return this.startFromBeginning; + } + + public ProcessorSettings withStartFromBeginning(boolean startFromBeginning) { + this.startFromBeginning = startFromBeginning; + return this; + } + + public OffsetDateTime getStartTime() { + return this.startTime; + } + + public ProcessorSettings withStartTime(OffsetDateTime startTime) { + this.startTime = startTime; + return this; + } + + // This is not currently supported in Java implementation. +// public STRING sessionToken() { +// return this.sessionToken; +// } +// +// public ProcessorSettings sessionToken(STRING sessionToken) { +// this.sessionToken = sessionToken; +// return this; +// } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingPartitionWork.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingPartitionWork.java new file mode 100644 index 0000000000000..ec348e16d1911 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingPartitionWork.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +/** + * Interface for remaining partition work. + */ +public interface RemainingPartitionWork { + /** + * @return the partition key range ID for which the remaining work is calculated. + */ + String getPartitionKeyRangeId(); + + /** + * @return the ammount of documents remaining to be processed. + */ + long getRemainingWork(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingWorkEstimator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingWorkEstimator.java new file mode 100644 index 0000000000000..95ceb66be6517 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RemainingWorkEstimator.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Used to estimate the pending work remaining to be read in the Change Feed. Calculates the sum of pending work + * based on the difference between the latest status of the feed and the status of each existing lease. + */ +public interface RemainingWorkEstimator { + /** + * Calculates an estimate of the pending work remaining to be read in the Change Feed in amount of documents in the whole collection. + * + * @return an estimation of pending work in amount of documents. + */ + Mono estimatedRemainingWork(); + + /** + * Calculates an estimate of the pending work remaining to be read in the Change Feed in amount of documents per partition. + * + * @return an estimation of pending work in amount of documents per partitions. + */ + Flux estimatedRemainingWorkPerPartition(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RequestOptionsFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RequestOptionsFactory.java new file mode 100644 index 0000000000000..7db485a8a3351 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/RequestOptionsFactory.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.FeedOptions; + +/** + * Defines request options for lease requests to use with {@link LeaseStoreManager}. + */ +public interface RequestOptionsFactory { + + CosmosItemRequestOptions createRequestOptions(Lease lease); + + FeedOptions createFeedOptions(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLease.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLease.java new file mode 100644 index 0000000000000..3cd2f125039b1 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLease.java @@ -0,0 +1,244 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.Constants; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +//import com.azure.data.cosmos.internal.changefeed.internal.Constants; + +/** + * Document service lease. + */ +public class ServiceItemLease implements Lease { + private static final ZonedDateTime UNIX_START_TIME = ZonedDateTime.parse("1970-01-01T00:00:00.0Z[UTC]"); + + // TODO: add JSON annotations and rename the item. + private String id; + private String _etag; + private String LeaseToken; + private String Owner; + private String ContinuationToken; + + private Map properties; + private String timestamp; // ExplicitTimestamp + private String _ts; + + public ServiceItemLease() { + ZonedDateTime currentTime = ZonedDateTime.now(ZoneId.of("UTC")); + this.timestamp = currentTime.toString(); + this._ts = String.valueOf(currentTime.getSecond()); + this.properties = new HashMap<>(); + } + + public ServiceItemLease(ServiceItemLease other) + { + this.id = other.id; + this._etag = other._etag; + this.LeaseToken = other.LeaseToken; + this.Owner = other.Owner; + this.ContinuationToken = other.ContinuationToken; + this.properties = other.properties; + this.timestamp = other.timestamp; + this._ts = other._ts; + } + + @Override + public String getId() { + return this.id; + } + + public ServiceItemLease withId(String id) { + this.id = id; + return this; + } + + @JsonIgnore + public String getEtag() { + return this._etag; + } + + public ServiceItemLease withEtag(String etag) { + this._etag = etag; + return this; + } + + @JsonProperty("LeaseToken") + public String getLeaseToken() { + return this.LeaseToken; + } + + public ServiceItemLease withLeaseToken(String leaseToken) { + this.LeaseToken = leaseToken; + return this; + } + + @JsonProperty("Owner") + @Override + public String getOwner() { + return this.Owner; + } + + public ServiceItemLease withOwner(String owner) { + this.Owner = owner; + return this; + } + + @JsonProperty("ContinuationToken") + @Override + public String getContinuationToken() { + return this.ContinuationToken; + } + + @Override + public void setContinuationToken(String continuationToken) { + this.withContinuationToken(continuationToken); + } + + public ServiceItemLease withContinuationToken(String continuationToken) { + this.ContinuationToken = continuationToken; + return this; + } + + @Override + public Map getProperties() { + return this.properties; + } + + @Override + public void setOwner(String owner) { + this.withOwner(owner); + } + + @Override + public void setTimestamp(ZonedDateTime timestamp) { + this.withTimestamp(timestamp); + } + + public void setTimestamp(Date date) { + this.withTimestamp(date.toInstant().atZone(ZoneId.systemDefault())); + } + + public void setTimestamp(Date date, ZoneId zoneId) { + this.withTimestamp(date.toInstant().atZone(zoneId)); + } + + @Override + public void setId(String id) { + this.withId(id); + } + + @Override + public void setConcurrencyToken(String concurrencyToken) { + this.withEtag(concurrencyToken); + } + + public ServiceItemLease withConcurrencyToken(String concurrencyToken) { + return this.withEtag(concurrencyToken); + } + + @Override + public void setProperties(Map properties) { + this.withProperties(properties); + } + + public ServiceItemLease withProperties(Map properties) { + this.properties = properties; + return this; + } + + @JsonIgnore + public String getTs() { + return this._ts; + } + + public ServiceItemLease withTs(String ts) { + this._ts = ts; + return this; + } + + @JsonProperty("timestamp") + @Override + public String getTimestamp() { + if (this.timestamp == null) { + return UNIX_START_TIME.plusSeconds(Long.parseLong(this.getTs())).toString(); + } + return this.timestamp; + } + + public ServiceItemLease withTimestamp(ZonedDateTime timestamp) { + this.timestamp = timestamp.toString(); + return this; + } + + @JsonIgnore + public String getExplicitTimestamp() { + return this.timestamp; + } + + @JsonIgnore + @Override + public String getConcurrencyToken() { + return this.getEtag(); + } + + public static ServiceItemLease fromDocument(Document document) { + return new ServiceItemLease() + .withId(document.id()) + .withEtag(document.etag()) + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)) + .withOwner(document.getString("Owner")) + .withLeaseToken(document.getString("LeaseToken")) + .withContinuationToken(document.getString("ContinuationToken")); + } + + public static ServiceItemLease fromDocument(CosmosItemProperties document) { + return new ServiceItemLease() + .withId(document.id()) + .withEtag(document.etag()) + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)) + .withOwner(document.getString("Owner")) + .withLeaseToken(document.getString("LeaseToken")) + .withContinuationToken(document.getString("ContinuationToken")); + } + + @Override + public String toString() { + return String.format( + "%s Owner='%s' Continuation=%s Timestamp(local)=%s Timestamp(server)=%s", + this.getId(), + this.getOwner(), + this.getContinuationToken(), + this.getTimestamp(), + UNIX_START_TIME.plusSeconds(Long.parseLong(this.getTs()))); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLeaseUpdater.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLeaseUpdater.java new file mode 100644 index 0000000000000..92f6da3d26818 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/ServiceItemLeaseUpdater.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed; + +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import reactor.core.publisher.Mono; + +import java.util.function.Function; + +/** + * Interface for service lease updater. + */ +public interface ServiceItemLeaseUpdater { + Mono updateLease(Lease cachedLease, CosmosItem itemLink, CosmosItemRequestOptions requestOptions, Function updateLease); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/LeaseLostException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/LeaseLostException.java new file mode 100644 index 0000000000000..126e27bfdaceb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/LeaseLostException.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +import com.azure.data.cosmos.internal.changefeed.Lease; + +/** + * Exception occurred when lease is lost, that would typically happen when it is taken by another host. + * Other cases: communication failure, number of retries reached, lease not found. + */ +public class LeaseLostException extends RuntimeException { + private static final String DEFAULT_MESSAGE = "The lease was lost."; + + private Lease lease; + private boolean isGone; + + /** + * Initializes a new instance of the @link LeaseLostException} class. + */ + public LeaseLostException() + { + } + + /** + * Initializes a new instance of the @link LeaseLostException} class using the specified lease. + * + * @param lease an instance of a lost lease. + */ + public LeaseLostException(Lease lease) + { + super(DEFAULT_MESSAGE); + this.lease = lease; + } + + /** + * Initializes a new instance of the @link LeaseLostException} class using error message. + * + * @param message the exception error message. + */ + public LeaseLostException(String message) + { + super(message); + } + + /** + * Initializes a new instance of the @link LeaseLostException} class using error message and inner exception. + * + * @param message the exception error message. + * @param innerException the inner exception. + * + */ + public LeaseLostException(String message, Exception innerException) + { + super(message, innerException.getCause()); + } + + /** + * Initializes a new instance of the @link LeaseLostException} class using the specified lease, inner exception, + * and a flag indicating whether lease is gone.. + * + * @param lease an instance of a lost lease. + * @param innerException the inner exception. + * @param isGone true if lease doesn't exist. + */ + public LeaseLostException(Lease lease, Exception innerException, boolean isGone) + { + super(DEFAULT_MESSAGE, innerException.getCause()); + this.lease = lease; + this.isGone = isGone; + } + + /** + * Gets the lost lease. + * + * @return the lost lease. + */ + public Lease getLease() { + return this.lease; + } + + /** + * Gets a value indicating whether lease doesn't exist. + * + * @return true if lease is gone. + */ + public boolean isGone() { + return this.isGone; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/ObserverException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/ObserverException.java new file mode 100644 index 0000000000000..fd052ec2b4845 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/ObserverException.java @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +/** + * Exception occurred when an operation in a ChangeFeedObserver is running and throws by user code. + */ +public class ObserverException extends RuntimeException { + private static final String DefaultMessage = "Exception has been thrown by the Observer."; + + /** + * Initializes a new instance of the {@link ObserverException} class using the specified internal exception. + * + * @param originalException {@link Exception} thrown by the user code. + */ + public ObserverException(Exception originalException) { + super(DefaultMessage, originalException.getCause()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionException.java new file mode 100644 index 0000000000000..5a4f543a83884 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionException.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +/** + * General exception occurred during partition processing. + */ +public class PartitionException extends RuntimeException { + private String lastContinuation; + + /** + * Initializes a new instance of the {@link PartitionException} class using error message and last continuation token. + * @param message the exception error message. + * @param lastContinuation the request continuation token. + */ + public PartitionException(String message, String lastContinuation) { + super(message); + this.lastContinuation = lastContinuation; + } + + /** + * Initializes a new instance of the {@link PartitionException} class using error message, the last continuation + * token and the inner exception. + * + * @param message the exception error message. + * @param lastContinuation the request continuation token. + * @param innerException the inner exception. + */ + public PartitionException(String message, String lastContinuation, Exception innerException) { + super(message, innerException.getCause()); + this.lastContinuation = lastContinuation; + } + + /** + * Gets the value of request continuation token. + * + * @return the value of request continuation token. + */ + public String getLastContinuation() { + return this.lastContinuation; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionNotFoundException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionNotFoundException.java new file mode 100644 index 0000000000000..9205bfffc5e81 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionNotFoundException.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +/** + * Exception occurred when partition wasn't found. + */ +public class PartitionNotFoundException extends PartitionException { + + /** + * Initializes a new instance of the {@link PartitionNotFoundException} class using error message and last continuation token. + * @param message the exception error message. + * @param lastContinuation the request continuation token. + */ + public PartitionNotFoundException(String message, String lastContinuation) { + super(message, lastContinuation); + } + + /** + * Initializes a new instance of the {@link PartitionNotFoundException} class using error message, the last continuation + * token and the inner exception. + * + * @param message the exception error message. + * @param lastContinuation the request continuation token. + * @param innerException the inner exception. + */ + public PartitionNotFoundException(String message, String lastContinuation, Exception innerException) { + super(message, lastContinuation, innerException); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionSplitException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionSplitException.java new file mode 100644 index 0000000000000..9b9d5be037bd1 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/PartitionSplitException.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +/** + * Exception occurred during partition split. + */ +public class PartitionSplitException extends PartitionException { + /** + * Initializes a new instance of the {@link PartitionSplitException} class using error message and last continuation token. + * @param message the exception error message. + * @param lastContinuation the request continuation token. + */ + public PartitionSplitException(String message, String lastContinuation) { + super(message, lastContinuation); + } + + /** + * Initializes a new instance of the {@link PartitionSplitException} class using error message, the last continuation + * token and the inner exception. + * + * @param message the exception error message. + * @param lastContinuation the request continuation token. + * @param innerException the inner exception. + */ + public PartitionSplitException(String message, String lastContinuation, Exception innerException) { + super(message, lastContinuation, innerException); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/TaskCancelledException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/TaskCancelledException.java new file mode 100644 index 0000000000000..affa262512545 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/exceptions/TaskCancelledException.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.exceptions; + +/** + * Exception occurred when an operation in a ChangeFeedObserver was canceled. + */ +public class TaskCancelledException extends RuntimeException { + private static final String DefaultMessage = "Operations were canceled."; + + /** + * Initializes a new instance of the {@link TaskCancelledException} class. + */ + public TaskCancelledException() { + super(DefaultMessage); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/AutoCheckpointer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/AutoCheckpointer.java new file mode 100644 index 0000000000000..ebe5b71241160 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/AutoCheckpointer.java @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverCloseReason; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import com.azure.data.cosmos.internal.changefeed.CheckpointFrequency; + +import java.time.Duration; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; + +/** + * Auto check-pointer implementation for {@link ChangeFeedObserver}. + */ +class AutoCheckpointer implements ChangeFeedObserver { + private final CheckpointFrequency checkpointFrequency; + private final ChangeFeedObserver observer; + private int processedDocCount; + private ZonedDateTime lastCheckpointTime; + + public AutoCheckpointer(CheckpointFrequency checkpointFrequency, ChangeFeedObserver observer) { + if (checkpointFrequency == null) throw new IllegalArgumentException("checkpointFrequency"); + if (observer == null) throw new IllegalArgumentException("observer"); + + this.checkpointFrequency = checkpointFrequency; + this.observer = observer; + this.lastCheckpointTime = ZonedDateTime.now(ZoneId.of("UTC")); + } + + @Override + public void open(ChangeFeedObserverContext context) { + this.observer.open(context); + } + + @Override + public void close(ChangeFeedObserverContext context, ChangeFeedObserverCloseReason reason) { + this.observer.close(context, reason); + } + + @Override + public void processChanges(ChangeFeedObserverContext context, List docs) { + this.observer.processChanges(context, docs); + this.processedDocCount ++; + + if (this.isCheckpointNeeded()) { + context.checkpoint().block(); + this.processedDocCount = 0; + this.lastCheckpointTime = ZonedDateTime.now(ZoneId.of("UTC")); + } + } + + private boolean isCheckpointNeeded() { + if (this.checkpointFrequency.getProcessedDocumentCount() == 0 && this.checkpointFrequency.getTimeInterval() == null) { + return true; + } + + if (this.processedDocCount >= this.checkpointFrequency.getProcessedDocumentCount()) { + return true; + } + + Duration delta = Duration.between(this.lastCheckpointTime, ZonedDateTime.now(ZoneId.of("UTC"))); + + if (delta.compareTo(this.checkpointFrequency.getTimeInterval()) >= 0) { + return true; + } + + return false; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/BootstrapperImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/BootstrapperImpl.java new file mode 100644 index 0000000000000..701071019dead --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/BootstrapperImpl.java @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.Bootstrapper; +import com.azure.data.cosmos.internal.changefeed.LeaseStore; +import com.azure.data.cosmos.internal.changefeed.PartitionSynchronizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Implementation for the bootstrapping interface. + */ +class BootstrapperImpl implements Bootstrapper { + private final Logger logger = LoggerFactory.getLogger(BootstrapperImpl.class); + private final PartitionSynchronizer synchronizer; + private final LeaseStore leaseStore; + private final Duration lockTime; + private final Duration sleepTime; + + public BootstrapperImpl(PartitionSynchronizer synchronizer, LeaseStore leaseStore, Duration lockTime, Duration sleepTime) + { + if (synchronizer == null) throw new IllegalArgumentException("synchronizer"); + if (leaseStore == null) throw new IllegalArgumentException("leaseStore"); + if (lockTime == null || lockTime.isNegative() || lockTime.isZero()) throw new IllegalArgumentException("lockTime should be non-null and positive"); + if (sleepTime == null || sleepTime.isNegative() || sleepTime.isZero()) throw new IllegalArgumentException("sleepTime should be non-null and positive"); + + this.synchronizer = synchronizer; + this.leaseStore = leaseStore; + this.lockTime = lockTime; + this.sleepTime = sleepTime; + } + + @Override + public Mono initialize() { + BootstrapperImpl self = this; + + return Mono.fromRunnable( () -> { + while (true) { + boolean initialized = self.leaseStore.isInitialized().block(); + + if (initialized) break; + + boolean isLockAcquired = self.leaseStore.acquireInitializationLock(self.lockTime).block(); + + try { + if (!isLockAcquired) { + logger.info("Another instance is initializing the store"); + try { + Thread.sleep(self.sleepTime.toMillis()); + } catch (InterruptedException ex) { + logger.warn("Unexpected exception caught", ex); + } + continue; + } + + logger.info("Initializing the store"); + self.synchronizer.createMissingLeases().block(); + self.leaseStore.markInitialized().block(); + + } catch (RuntimeException ex) { + break; + } finally { + if (isLockAcquired) { + self.leaseStore.releaseInitializationLock().block(); + } + } + } + + logger.info("The store is initialized"); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedContextClientImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedContextClientImpl.java new file mode 100644 index 0000000000000..9d98c6da6fadb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedContextClientImpl.java @@ -0,0 +1,176 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerResponse; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseRequestOptions; +import com.azure.data.cosmos.CosmosDatabaseResponse; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Scheduler; +import reactor.core.scheduler.Schedulers; + +import java.net.URI; + +import static com.azure.data.cosmos.CosmosBridgeInternal.getContextClient; + +/** + * Implementation for ChangeFeedDocumentClient. + */ +public class ChangeFeedContextClientImpl implements ChangeFeedContextClient { + private final AsyncDocumentClient documentClient; + private final CosmosContainer cosmosContainer; + private Scheduler rxScheduler; + + /** + * Initializes a new instance of the {@link ChangeFeedContextClient} interface. + * @param cosmosContainer existing client. + */ + public ChangeFeedContextClientImpl(CosmosContainer cosmosContainer) + { + if (cosmosContainer == null) { + throw new IllegalArgumentException("cosmosContainer"); + } + + this.cosmosContainer = cosmosContainer; + this.documentClient = getContextClient(cosmosContainer); + this.rxScheduler = Schedulers.elastic(); + } + + /** + * Initializes a new instance of the {@link ChangeFeedContextClient} interface. + * @param cosmosContainer existing client. + * @param rxScheduler the RX Java scheduler to observe on. + */ + public ChangeFeedContextClientImpl(CosmosContainer cosmosContainer, Scheduler rxScheduler) + { + if (cosmosContainer == null) { + throw new IllegalArgumentException("cosmosContainer"); + } + + this.cosmosContainer = cosmosContainer; + this.documentClient = getContextClient(cosmosContainer); + this.rxScheduler = rxScheduler; + + } + + @Override + public Flux> readPartitionKeyRangeFeed(String partitionKeyRangesOrCollectionLink, FeedOptions feedOptions) { + return this.documentClient.readPartitionKeyRanges(partitionKeyRangesOrCollectionLink, feedOptions) + .publishOn(this.rxScheduler); + } + + @Override + public Flux> createDocumentChangeFeedQuery(CosmosContainer collectionLink, ChangeFeedOptions feedOptions) { + return collectionLink.queryChangeFeedItems(feedOptions) + .publishOn(this.rxScheduler); + } + + @Override + public Mono readDatabase(CosmosDatabase database, CosmosDatabaseRequestOptions options) { + return database.read() + .publishOn(this.rxScheduler); + } + + @Override + public Mono readContainer(CosmosContainer containerLink, CosmosContainerRequestOptions options) { + return containerLink.read(options) + .publishOn(this.rxScheduler); + } + + @Override + public Mono createItem(CosmosContainer containerLink, Object document, CosmosItemRequestOptions options, boolean disableAutomaticIdGeneration) { + if (options != null) { + return containerLink.createItem(document, options) + .publishOn(this.rxScheduler); + } else { + return containerLink.createItem(document) + .publishOn(this.rxScheduler); + } + } + + @Override + public Mono deleteItem(CosmosItem itemLink, CosmosItemRequestOptions options) { + return itemLink.delete(options) + .publishOn(this.rxScheduler); + } + + @Override + public Mono replaceItem(CosmosItem itemLink, Object document, CosmosItemRequestOptions options) { + return itemLink.replace(document, options) + .publishOn(this.rxScheduler); + } + + @Override + public Mono readItem(CosmosItem itemLink, CosmosItemRequestOptions options) { + return itemLink.read(options) + .publishOn(this.rxScheduler); + } + + @Override + public Flux> queryItems(CosmosContainer containerLink, SqlQuerySpec querySpec, FeedOptions options) { + return containerLink.queryItems(querySpec, options) + .publishOn(this.rxScheduler); + } + + @Override + public URI getServiceEndpoint() { + return documentClient.getServiceEndpoint(); + } + + @Override + public Mono readContainerSettings(CosmosContainer containerLink, CosmosContainerRequestOptions options) { + return containerLink.read(options) + .map(cosmosContainerResponse -> cosmosContainerResponse.properties()); + } + + @Override + public CosmosContainer getContainerClient() { + return this.cosmosContainer; + } + + @Override + public CosmosDatabase getDatabaseClient() { + return this.cosmosContainer.getDatabase(); + } + + @Override + public void close() { + + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedHelper.java new file mode 100644 index 0000000000000..dee963a1b3754 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedHelper.java @@ -0,0 +1,182 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Map; + +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.Paths.COLLECTIONS_PATH_SEGMENT; +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.Paths.DATABASES_ROOT; +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.Paths.DOCUMENTS_PATH_SEGMENT; + +/** + * Implement static methods used for various simple transformations and tasks. + */ +class ChangeFeedHelper { + private static final String DEFAULT_USER_AGENT_SUFFIX = "changefeed-2.2.6"; + + public static final int HTTP_STATUS_CODE_NOT_FOUND = 404; + public static final int HTTP_STATUS_CODE_CONFLICT = 409; + public static final int HTTP_STATUS_CODE_GONE = 410; + public static final int HTTP_STATUS_CODE_PRECONDITION_FAILED = 412; + public static final int HTTP_STATUS_CODE_TOO_MANY_REQUESTS = 429; + public static final int HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR = 500; + + public static String getDatabaseLink(String databaseName) { + return String.format("/dbs/%s", databaseName); + } + + public static String getCollectionLink(String databaseName, String collectionName) { + return String.format("/dbs/%s/colls/%s", databaseName, collectionName); + } + + public static class UriFactory { + /** + * A database link in the format of "dbs/{0}/". + * + * @param databaseId the database ID. + * @return a database link in the format of "dbs/{0}/". + */ + public static String createDatabaseUri(String databaseId) { + String path = String.format("%s/%s/", DATABASES_ROOT, databaseId); + + return getUrlPath(path); + } + + /** + * A collection link in the format of "dbs/{0}/colls/{1}/". + * + * @param databaseId the database ID. + * @param collectionId the collection ID. + * @return a collection link in the format of "dbs/{0}/colls/{1}/". + */ + public static String createDocumentCollectionUri(String databaseId, String collectionId) { + String path = String.format("%s/%s/%s/%s/",DATABASES_ROOT, databaseId, + COLLECTIONS_PATH_SEGMENT, collectionId); + + return getUrlPath(path); + } + + /** + * A document link in the format of "dbs/{0}/colls/{1}/docs/{2}/". + * + * @param databaseId the database ID. + * @param collectionId the collection ID. + * @param documentId the document ID. + * @return a document link in the format of "dbs/{0}/colls/{1}/docs/{2}/". + */ + public static String createDocumentUri(String databaseId, String collectionId, String documentId) { + String path = String.format("%s/%s/%s/%s/%s/%s/",DATABASES_ROOT, databaseId, + COLLECTIONS_PATH_SEGMENT, collectionId, DOCUMENTS_PATH_SEGMENT, documentId); + + return getUrlPath(path); + } + + public static String getUrlPath(String path) { + try { + URI uri = new URI( + "http", + "localhost", + path, + null + ); + + URL url = uri.toURL(); + + return url.getPath().substring(1); + } catch (URISyntaxException | MalformedURLException uriEx) {return null;} + } + } + + /** + * Copied from com.azure.data.cosmos.internal.Paths. + */ + public static class Paths { + static final String ROOT = "/"; + + public static final String DATABASES_PATH_SEGMENT = "dbs"; + public static final String DATABASES_ROOT = ROOT + DATABASES_PATH_SEGMENT; + + public static final String USERS_PATH_SEGMENT = "users"; + public static final String PERMISSIONS_PATH_SEGMENT = "permissions"; + public static final String COLLECTIONS_PATH_SEGMENT = "colls"; + public static final String STORED_PROCEDURES_PATH_SEGMENT = "sprocs"; + public static final String TRIGGERS_PATH_SEGMENT = "triggers"; + public static final String USER_DEFINED_FUNCTIONS_PATH_SEGMENT = "udfs"; + public static final String CONFLICTS_PATH_SEGMENT = "conflicts"; + public static final String DOCUMENTS_PATH_SEGMENT = "docs"; + public static final String ATTACHMENTS_PATH_SEGMENT = "attachments"; + + // /offers + public static final String OFFERS_PATH_SEGMENT = "offers"; + public static final String OFFERS_ROOT = ROOT + OFFERS_PATH_SEGMENT + "/"; + + public static final String ADDRESS_PATH_SEGMENT = "addresses"; + public static final String PARTITIONS_PATH_SEGMENT = "partitions"; + public static final String DATABASE_ACCOUNT_PATH_SEGMENT = "databaseaccount"; + public static final String TOPOLOGY_PATH_SEGMENT = "topology"; + public static final String MEDIA_PATH_SEGMENT = "media"; + public static final String MEDIA_ROOT = ROOT + MEDIA_PATH_SEGMENT; + public static final String SCHEMAS_PATH_SEGMENT = "schemas"; + public static final String PARTITION_KEY_RANGES_PATH_SEGMENT = "pkranges"; + + public static final String USER_DEFINED_TYPES_PATH_SEGMENT = "udts"; + + public static final String RID_RANGE_PATH_SEGMENT = "ridranges"; + } + + public static class KeyValuePair implements Map.Entry + { + private K key; + private V value; + + public KeyValuePair(K key, V value) + { + this.key = key; + this.value = value; + } + + public K getKey() + { + return this.key; + } + + public V getValue() + { + return this.value; + } + + public K setKey(K key) + { + return this.key = key; + } + + public V setValue(V value) + { + return this.value = value; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverContextImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverContextImpl.java new file mode 100644 index 0000000000000..4454a1a493d54 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverContextImpl.java @@ -0,0 +1,86 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import com.azure.data.cosmos.internal.changefeed.PartitionCheckpointer; +import reactor.core.publisher.Mono; + +/** + * Implementation for ChangeFeedObserverContext. + */ +class ChangeFeedObserverContextImpl implements ChangeFeedObserverContext { + private final PartitionCheckpointer checkpointer; + private final String partitionKeyRangeId; + private final FeedResponse feedResponse; + private String responseContinuation; + + public ChangeFeedObserverContextImpl(String leaseToken) { + this.partitionKeyRangeId = leaseToken; + this.checkpointer = null; + this.feedResponse = null; + } + + public ChangeFeedObserverContextImpl(String leaseToken, FeedResponse feedResponse, PartitionCheckpointer checkpointer) + { + this.partitionKeyRangeId = leaseToken; + this.feedResponse = feedResponse; + this.checkpointer = checkpointer; + } + + /** + * Checkpoints progress of a stream. This method is valid only if manual checkpoint was configured. + *

    + * Client may accept multiple change feed batches to process in parallel. + * Once first N document processing was finished the client can call checkpoint on the last completed batches in the row. + * In case of automatic checkpointing this is method throws. + * + * @return a deferred computation of this call. + */ + @Override + public Mono checkpoint() { + this.responseContinuation = this.feedResponse.continuationToken(); + + return this.checkpointer.checkpointPartition(this.responseContinuation); + } + + /** + * @return the id of the partition for the current event. + */ + @Override + public String getPartitionKeyRangeId() { + return this.partitionKeyRangeId; + } + + /** + * @return the response from the underlying call. + */ + @Override + public FeedResponse getFeedResponse() { + return this.feedResponse; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverFactoryImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverFactoryImpl.java new file mode 100644 index 0000000000000..6c218c4caed60 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedObserverFactoryImpl.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverFactory; +import com.azure.data.cosmos.internal.changefeed.exceptions.ObserverException; + +/** + * DEFAULT implementation for {@link ChangeFeedObserverFactory}. + */ +public class ChangeFeedObserverFactoryImpl implements ChangeFeedObserverFactory { + private final Class observerType; + + public ChangeFeedObserverFactoryImpl(Class observerType) { + this.observerType = observerType; + } + + @Override + public ChangeFeedObserver createObserver() { + try { + return (ChangeFeedObserver) observerType.newInstance(); + } catch (IllegalAccessException | InstantiationException ex) { + throw new ObserverException(ex); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedProcessorBuilderImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedProcessorBuilderImpl.java new file mode 100644 index 0000000000000..3d979e59c64bc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ChangeFeedProcessorBuilderImpl.java @@ -0,0 +1,471 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.ChangeFeedProcessor; +import com.azure.data.cosmos.ChangeFeedProcessorOptions; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.changefeed.Bootstrapper; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverFactory; +import com.azure.data.cosmos.internal.changefeed.CheckpointFrequency; +import com.azure.data.cosmos.internal.changefeed.HealthMonitor; +import com.azure.data.cosmos.internal.changefeed.LeaseStoreManager; +import com.azure.data.cosmos.internal.changefeed.PartitionController; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancer; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancingStrategy; +import com.azure.data.cosmos.internal.changefeed.PartitionManager; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessor; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessorFactory; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisorFactory; +import com.azure.data.cosmos.internal.changefeed.RequestOptionsFactory; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.net.URI; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; + +/** + * Helper class to build {@link ChangeFeedProcessor} instances + * as logical representation of the Azure Cosmos DB database service. + * + *

    + * {@code
    + *  ChangeFeedProcessor.Builder()
    + *     .hostName(hostName)
    + *     .feedContainer(feedContainer)
    + *     .leaseContainer(leaseContainer)
    + *     .handleChanges(docs -> {
    + *         // Implementation for handling and processing CosmosItemProperties list goes here
    + *      })
    + *     .observer(SampleObserverImpl.class)
    + *     .build();
    + * }
    + * 
    + */ +public class ChangeFeedProcessorBuilderImpl implements ChangeFeedProcessor.BuilderDefinition, ChangeFeedProcessor, AutoCloseable { + private static final long DefaultUnhealthinessDuration = Duration.ofMinutes(15).toMillis(); + private final Duration sleepTime = Duration.ofSeconds(15); + private final Duration lockTime = Duration.ofSeconds(30); + private static final int DefaultQueryPartitionsMaxBatchSize = 100; + + private int queryPartitionsMaxBatchSize = DefaultQueryPartitionsMaxBatchSize; + private int degreeOfParallelism = 25; // default + + + private String hostName; + private ChangeFeedContextClient feedContextClient; + private ChangeFeedProcessorOptions changeFeedProcessorOptions; + private ChangeFeedObserverFactory observerFactory; + private String databaseResourceId; + private String collectionResourceId; + private ChangeFeedContextClient leaseContextClient; + private PartitionLoadBalancingStrategy loadBalancingStrategy; + private PartitionProcessorFactory partitionProcessorFactory; + private LeaseStoreManager leaseStoreManager; + private HealthMonitor healthMonitor; + private PartitionManager partitionManager; + + private ExecutorService executorService; + + /** + * Start listening for changes asynchronously. + * + * @return a representation of the deferred computation of this call. + */ + @Override + public Mono start() { + return partitionManager.start(); + } + + /** + * Stops listening for changes asynchronously. + * + * @return a representation of the deferred computation of this call. + */ + @Override + public Mono stop() { + return partitionManager.stop(); + } + + /** + * Sets the host name. + * + * @param hostName the name to be used for the host. When using multiple hosts, each host must have a unique name. + * @return current Builder. + */ + @Override + public ChangeFeedProcessorBuilderImpl hostName(String hostName) { + this.hostName = hostName; + return this; + } + + /** + * Sets and existing {@link CosmosContainer} to be used to read from the monitored collection. + * + * @param feedDocumentClient the instance of {@link CosmosContainer} to be used. + * @return current Builder. + */ + @Override + public ChangeFeedProcessorBuilderImpl feedContainer(CosmosContainer feedDocumentClient) { + if (feedDocumentClient == null) { + throw new IllegalArgumentException("feedContextClient"); + } + + this.feedContextClient = new ChangeFeedContextClientImpl(feedDocumentClient); + return this; + } + + /** + * Sets the {@link ChangeFeedProcessorOptions} to be used. + * + * @param changeFeedProcessorOptions the change feed processor options to use. + * @return current Builder. + */ + @Override + public ChangeFeedProcessorBuilderImpl options(ChangeFeedProcessorOptions changeFeedProcessorOptions) { + if (changeFeedProcessorOptions == null) { + throw new IllegalArgumentException("changeFeedProcessorOptions"); + } + + this.changeFeedProcessorOptions = changeFeedProcessorOptions; + + return this; + } + + /** + * Sets the {@link ChangeFeedObserverFactory} to be used to generate {@link ChangeFeedObserver} + * + * @param observerFactory The instance of {@link ChangeFeedObserverFactory} to use. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl observerFactory(ChangeFeedObserverFactory observerFactory) { + if (observerFactory == null) { + throw new IllegalArgumentException("observerFactory"); + } + + this.observerFactory = observerFactory; + return this; + } + + /** + * Sets an existing {@link ChangeFeedObserver} type to be used by a {@link ChangeFeedObserverFactory} to process changes. + * @param type the type of {@link ChangeFeedObserver} to be used. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl observer(Class type) { + if (type == null) { + throw new IllegalArgumentException("type"); + } + + this.observerFactory = new ChangeFeedObserverFactoryImpl(type); + + return this; + } + + @Override + public ChangeFeedProcessorBuilderImpl handleChanges(Consumer> consumer) { + return this.observerFactory(new DefaultObserverFactory(consumer)); + } + + /** + * Sets the database resource ID of the monitored collection. + * + * @param databaseResourceId the database resource ID of the monitored collection. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withDatabaseResourceId(String databaseResourceId) { + this.databaseResourceId = databaseResourceId; + return this; + } + + /** + * Sets the collection resource ID of the monitored collection. + * @param collectionResourceId the collection resource ID of the monitored collection. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withCollectionResourceId(String collectionResourceId) { + this.collectionResourceId = collectionResourceId; + return this; + } + + /** + * Sets an existing {@link CosmosContainer} to be used to read from the leases collection. + * + * @param leaseDocumentClient the instance of {@link CosmosContainer} to use. + * @return current Builder. + */ + @Override + public ChangeFeedProcessorBuilderImpl leaseContainer(CosmosContainer leaseDocumentClient) { + if (leaseDocumentClient == null) { + throw new IllegalArgumentException("leaseContextClient"); + } + + this.leaseContextClient = new ChangeFeedContextClientImpl(leaseDocumentClient); + return this; + } + + /** + * Sets the {@link PartitionLoadBalancingStrategy} to be used for partition load balancing. + * + * @param loadBalancingStrategy the {@link PartitionLoadBalancingStrategy} to be used for partition load balancing. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withPartitionLoadBalancingStrategy(PartitionLoadBalancingStrategy loadBalancingStrategy) { + if (loadBalancingStrategy == null) { + throw new IllegalArgumentException("loadBalancingStrategy"); + } + + this.loadBalancingStrategy = loadBalancingStrategy; + return this; + } + + /** + * Sets the {@link PartitionProcessorFactory} to be used to create {@link PartitionProcessor} for partition processing. + * + * @param partitionProcessorFactory the instance of {@link PartitionProcessorFactory} to use. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withPartitionProcessorFactory(PartitionProcessorFactory partitionProcessorFactory) { + if (partitionProcessorFactory == null) { + throw new IllegalArgumentException("partitionProcessorFactory"); + } + + this.partitionProcessorFactory = partitionProcessorFactory; + return this; + } + + /** + * Sets the {@link LeaseStoreManager} to be used to manage leases. + * + * @param leaseStoreManager the instance of {@link LeaseStoreManager} to use. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withLeaseStoreManager(LeaseStoreManager leaseStoreManager) { + if (leaseStoreManager == null) { + throw new IllegalArgumentException("leaseStoreManager"); + } + + this.leaseStoreManager = leaseStoreManager; + return this; + } + + /** + * Sets the {@link HealthMonitor} to be used to monitor unhealthiness situation. + * + * @param healthMonitor The instance of {@link HealthMonitor} to use. + * @return current Builder. + */ + public ChangeFeedProcessorBuilderImpl withHealthMonitor(HealthMonitor healthMonitor) { + if (healthMonitor == null) { + throw new IllegalArgumentException("healthMonitor"); + } + + this.healthMonitor = healthMonitor; + return this; + } + + /** + * Builds a new instance of the {@link ChangeFeedProcessor} with the specified configuration asynchronously. + * + * @return an instance of {@link ChangeFeedProcessor}. + */ + @Override + public ChangeFeedProcessor build() { + ChangeFeedProcessorBuilderImpl self = this; + + if (this.hostName == null) + { + throw new IllegalArgumentException("Host name was not specified"); + } + + if (this.observerFactory == null) + { + throw new IllegalArgumentException("Observer was not specified"); + } + + if (this.executorService == null) { + this.executorService = Executors.newCachedThreadPool(); + } + + // TBD: Move this initialization code as part of the start() call. + return this.initializeCollectionPropertiesForBuild() + .then(self.getLeaseStoreManager().flatMap(leaseStoreManager -> self.buildPartitionManager(leaseStoreManager))) + .map(partitionManager1 -> { + self.partitionManager = partitionManager1; + return self; + }).block(); + } + + public ChangeFeedProcessorBuilderImpl() { + this.queryPartitionsMaxBatchSize = DefaultQueryPartitionsMaxBatchSize; + this.degreeOfParallelism = 25; // default + } + + public ChangeFeedProcessorBuilderImpl(PartitionManager partitionManager) { + this.partitionManager = partitionManager; + } + + private Mono initializeCollectionPropertiesForBuild() { + ChangeFeedProcessorBuilderImpl self = this; + + if (this.changeFeedProcessorOptions == null) { + this.changeFeedProcessorOptions = new ChangeFeedProcessorOptions(); + } + + return this.feedContextClient + .readDatabase(this.feedContextClient.getDatabaseClient(), null) + .map( databaseResourceResponse -> { + self.databaseResourceId = databaseResourceResponse.database().id(); + return self.databaseResourceId; + }) + .flatMap( id -> self.feedContextClient + .readContainer(self.feedContextClient.getContainerClient(), null) + .map(documentCollectionResourceResponse -> { + self.collectionResourceId = documentCollectionResourceResponse.container().id(); + return self.collectionResourceId; + })) + .then(); + } + + private Mono getLeaseStoreManager() { + ChangeFeedProcessorBuilderImpl self = this; + + if (this.leaseStoreManager == null) { + + return this.leaseContextClient.readContainerSettings(this.leaseContextClient.getContainerClient(), null) + .flatMap( collectionSettings -> { + boolean isPartitioned = + collectionSettings.partitionKeyDefinition() != null && + collectionSettings.partitionKeyDefinition().paths() != null && + collectionSettings.partitionKeyDefinition().paths().size() > 0; + if (!isPartitioned || (collectionSettings.partitionKeyDefinition().paths().size() != 1 || !collectionSettings.partitionKeyDefinition().paths().get(0).equals("/id"))) { +// throw new IllegalArgumentException("The lease collection, if partitioned, must have partition key equal to id."); + return Mono.error(new IllegalArgumentException("The lease collection must have partition key equal to id.")); + } + + RequestOptionsFactory requestOptionsFactory = new PartitionedByIdCollectionRequestOptionsFactory(); + + String leasePrefix = self.getLeasePrefix(); + + return LeaseStoreManager.Builder() + .leasePrefix(leasePrefix) + .leaseCollectionLink(self.leaseContextClient.getContainerClient()) + .leaseContextClient(self.leaseContextClient) + .requestOptionsFactory(requestOptionsFactory) + .hostName(self.hostName) + .build() + .map(manager -> { + self.leaseStoreManager = manager; + return self.leaseStoreManager; + }); + }); + } + + return Mono.just(this.leaseStoreManager); + } + + private String getLeasePrefix() { + String optionsPrefix = this.changeFeedProcessorOptions.leasePrefix(); + + if (optionsPrefix == null) { + optionsPrefix = ""; + } + + URI uri = this.feedContextClient.getServiceEndpoint(); + + return String.format( + "%s%s_%s_%s", + optionsPrefix, + uri.getHost(), + this.databaseResourceId, + this.collectionResourceId); + } + + private Mono buildPartitionManager(LeaseStoreManager leaseStoreManager) { + ChangeFeedProcessorBuilderImpl self = this; + + CheckpointerObserverFactory factory = new CheckpointerObserverFactory(this.observerFactory, new CheckpointFrequency()); + + PartitionSynchronizerImpl synchronizer = new PartitionSynchronizerImpl( + this.feedContextClient, + this.feedContextClient.getContainerClient(), + leaseStoreManager, + leaseStoreManager, + this.degreeOfParallelism, + this.queryPartitionsMaxBatchSize + ); + + Bootstrapper bootstrapper = new BootstrapperImpl(synchronizer, leaseStoreManager, this.lockTime, this.sleepTime); + PartitionSupervisorFactory partitionSupervisorFactory = new PartitionSupervisorFactoryImpl( + factory, + leaseStoreManager, + this.partitionProcessorFactory != null ? this.partitionProcessorFactory : new PartitionProcessorFactoryImpl( + this.feedContextClient, + this.changeFeedProcessorOptions, + leaseStoreManager, + this.feedContextClient.getContainerClient()), + this.changeFeedProcessorOptions, + executorService + ); + + if (this.loadBalancingStrategy == null) { + this.loadBalancingStrategy = new EqualPartitionsBalancingStrategy( + this.hostName, + this.changeFeedProcessorOptions.minScaleCount(), + this.changeFeedProcessorOptions.maxScaleCount(), + this.changeFeedProcessorOptions.leaseExpirationInterval()); + } + + PartitionController partitionController = new PartitionControllerImpl(leaseStoreManager, leaseStoreManager, partitionSupervisorFactory, synchronizer, executorService); + + if (this.healthMonitor == null) { + this.healthMonitor = new TraceHealthMonitor(); + } + + PartitionController partitionController2 = new HealthMonitoringPartitionControllerDecorator(partitionController, this.healthMonitor); + + PartitionLoadBalancer partitionLoadBalancer = new PartitionLoadBalancerImpl( + partitionController2, + leaseStoreManager, + this.loadBalancingStrategy, + this.changeFeedProcessorOptions.leaseAcquireInterval(), + this.executorService + ); + + PartitionManager partitionManager = new PartitionManagerImpl(bootstrapper, partitionController, partitionLoadBalancer); + + return Mono.just(partitionManager); + } + + @Override + public void close() { + this.stop().subscribeOn(Schedulers.elastic()).subscribe(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/CheckpointerObserverFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/CheckpointerObserverFactory.java new file mode 100644 index 0000000000000..8d982b76afbf0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/CheckpointerObserverFactory.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverFactory; +import com.azure.data.cosmos.internal.changefeed.CheckpointFrequency; + +/** + * Factory class used to create instance(s) of {@link ChangeFeedObserver}. + */ +class CheckpointerObserverFactory implements ChangeFeedObserverFactory { + private final ChangeFeedObserverFactory observerFactory; + private final CheckpointFrequency checkpointFrequency; + + /** + * Initializes a new instance of the {@link CheckpointerObserverFactory} class. + * + * @param observerFactory the instance of observer factory. + * @param checkpointFrequency the the frequency of lease event. + */ + public CheckpointerObserverFactory(ChangeFeedObserverFactory observerFactory, CheckpointFrequency checkpointFrequency) + { + if (observerFactory == null) throw new IllegalArgumentException("observerFactory"); + if (checkpointFrequency == null) throw new IllegalArgumentException("checkpointFrequency"); + + this.observerFactory = observerFactory; + this.checkpointFrequency = checkpointFrequency; + } + + /** + * @return a new instance of {@link ChangeFeedObserver}. + */ + @Override + public ChangeFeedObserver createObserver() { + ChangeFeedObserver observer = new ObserverExceptionWrappingChangeFeedObserverDecorator(this.observerFactory.createObserver()); + if (this.checkpointFrequency.isExplicitCheckpoint()) return observer; + + return new AutoCheckpointer(this.checkpointFrequency, observer); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/Constants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/Constants.java new file mode 100644 index 0000000000000..8c1ba053b79f2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/Constants.java @@ -0,0 +1,216 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + + +/** + * Used internally. Constants in the Azure Cosmos DB database service Java SDK. + */ +final class Constants { + + public static final class Quota { + // Quota Strings + public static final String DATABASE = "databases"; + public static final String COLLECTION = "collections"; + public static final String USER = "users"; + public static final String PERMISSION = "permissions"; + public static final String COLLECTION_SIZE = "collectionSize"; + public static final String DOCUMENTS_SIZE = "documentsSize"; + public static final String STORED_PROCEDURE = "storedProcedures"; + public static final String TRIGGER = "triggers"; + public static final String USER_DEFINED_FUNCTION = "functions"; + public static final String DELIMITER_CHARS = "=|;"; + public static final String DOCUMENTS_COUNT = "documentsCount"; + } + + public static final class Properties { + public static final String ID = "id"; + public static final String R_ID = "_rid"; + public static final String SELF_LINK = "_self"; + public static final String LAST_MODIFIED = "_ts"; + public static final String COUNT = "_count"; + public static final String E_TAG = "_etag"; + public static final String AGGREGATE = "_aggregate"; + + public static final String CONSISTENCY_POLICY = "consistencyPolicy"; + public static final String DEFAULT_CONSISTENCY_LEVEL = "defaultConsistencyLevel"; + public static final String MAX_STALENESS_PREFIX = "maxStalenessPrefix"; + public static final String MAX_STALENESS_INTERVAL_IN_SECONDS = "maxIntervalInSeconds"; + public static final String PARENTS = "parents"; + + public static final String DATABASES_LINK = "_dbs"; + public static final String COLLECTIONS_LINK = "_colls"; + public static final String USERS_LINK = "_users"; + public static final String PERMISSIONS_LINK = "_permissions"; + public static final String ATTACHMENTS_LINK = "_attachments"; + public static final String STORED_PROCEDURES_LINK = "_sprocs"; + public static final String TRIGGERS_LINK = "_triggers"; + public static final String USER_DEFINED_FUNCTIONS_LINK = "_udfs"; + public static final String CONFLICTS_LINK = "_conflicts"; + public static final String DOCUMENTS_LINK = "_docs"; + public static final String RESOURCE_LINK = "resource"; + public static final String MEDIA_LINK = "media"; + + public static final String PERMISSION_MODE = "permissionMode"; + public static final String RESOURCE_KEY = "key"; + public static final String TOKEN = "_token"; + public static final String SQL_API_TYPE = "0x10"; + + // Scripting + public static final String BODY = "body"; + public static final String TRIGGER_TYPE = "triggerType"; + public static final String TRIGGER_OPERATION = "triggerOperation"; + + public static final String MAX_SIZE = "maxSize"; + public static final String CURRENT_USAGE = "currentUsage"; + + public static final String CONTENT = "content"; + + public static final String CONTENT_TYPE = "contentType"; + + // ErrorResource. + public static final String CODE = "code"; + public static final String MESSAGE = "message"; + public static final String ERROR_DETAILS = "errorDetails"; + public static final String ADDITIONAL_ERROR_INFO = "additionalErrorInfo"; + + // PartitionInfo. + public static final String RESOURCE_TYPE = "resourceType"; + public static final String SERVICE_INDEX = "serviceIndex"; + public static final String PARTITION_INDEX = "partitionIndex"; + + public static final String ADDRESS_LINK = "addresses"; + public static final String USER_REPLICATION_POLICY = "userReplicationPolicy"; + public static final String USER_CONSISTENCY_POLICY = "userConsistencyPolicy"; + public static final String SYSTEM_REPLICATION_POLICY = "systemReplicationPolicy"; + public static final String READ_POLICY = "readPolicy"; + public static final String QUERY_ENGINE_CONFIGURATION = "queryEngineConfiguration"; + + //ReplicationPolicy + public static final String REPLICATION_POLICY = "replicationPolicy"; + public static final String ASYNC_REPLICATION = "asyncReplication"; + public static final String MAX_REPLICA_SET_SIZE = "maxReplicasetSize"; + public static final String MIN_REPLICA_SET_SIZE = "minReplicaSetSize"; + + //Indexing Policy. + public static final String INDEXING_POLICY = "indexingPolicy"; + public static final String AUTOMATIC = "automatic"; + public static final String STRING_PRECISION = "StringPrecision"; + public static final String NUMERIC_PRECISION = "NumericPrecision"; + public static final String MAX_PATH_DEPTH = "maxPathDepth"; + public static final String INDEXING_MODE = "indexingMode"; + public static final String INDEX_TYPE = "IndexType"; + public static final String INDEX_KIND = "kind"; + public static final String DATA_TYPE = "dataType"; + public static final String PRECISION = "precision"; + + public static final String PATHS = "paths"; + public static final String PATH = "path"; + public static final String INCLUDED_PATHS = "includedPaths"; + public static final String EXCLUDED_PATHS = "excludedPaths"; + public static final String INDEXES = "indexes"; + public static final String COMPOSITE_INDEXES = "compositeIndexes"; + public static final String ORDER = "order"; + public static final String SPATIAL_INDEXES = "spatialIndexes"; + public static final String TYPES = "types"; + + // Unique index. + public static final String UNIQUE_KEY_POLICY = "uniqueKeyPolicy"; + public static final String UNIQUE_KEYS = "uniqueKeys"; + + // Conflict. + public static final String CONFLICT = "conflict"; + public static final String OPERATION_TYPE = "operationType"; + public static final String SOURCE_RESOURCE_ID = "resourceId"; + + // Offer resource + public static final String OFFER_TYPE = "offerType"; + public static final String OFFER_VERSION = "offerVersion"; + public static final String OFFER_CONTENT = "content"; + public static final String OFFER_THROUGHPUT = "offerThroughput"; + public static final String OFFER_VERSION_V1 = "V1"; + public static final String OFFER_VERSION_V2 = "V2"; + public static final String OFFER_RESOURCE_ID = "offerResourceId"; + + // PartitionKey + public static final String PARTITION_KEY = "partitionKey"; + public static final String PARTITION_KEY_PATHS = "paths"; + public static final String PARTITION_KIND = "kind"; + public static final String PARTITION_KEY_DEFINITION_VERSION = "version"; + + public static final String RESOURCE_PARTITION_KEY = "resourcePartitionKey"; + public static final String PARTITION_KEY_RANGE_ID = "partitionKeyRangeId"; + public static final String MIN_INCLUSIVE_EFFECTIVE_PARTITION_KEY = "minInclusiveEffectivePartitionKey"; + public static final String MAX_EXCLUSIVE_EFFECTIVE_PARTITION_KEY = "maxExclusiveEffectivePartitionKey"; + + // AddressResource + public static final String IS_PRIMARY = "isPrimary"; + public static final String PROTOCOL = "protocol"; + public static final String LOGICAL_URI = "logicalUri"; + public static final String PHYISCAL_URI = "physcialUri"; + + // Time-to-Live + public static final String TTL = "ttl"; + public static final String DEFAULT_TTL = "defaultTtl"; + + // Global DB account item + public static final String Name = "name"; + public static final String WRITABLE_LOCATIONS = "writableLocations"; + public static final String READABLE_LOCATIONS = "readableLocations"; + public static final String DATABASE_ACCOUNT_ENDPOINT = "databaseAccountEndpoint"; + + //Authorization + public static final String MASTER_TOKEN = "master"; + public static final String RESOURCE_TOKEN = "resource"; + public static final String TOKEN_VERSION = "1.0"; + public static final String AUTH_SCHEMA_TYPE = "type"; + public static final String AUTH_VERSION = "ver"; + public static final String AUTH_SIGNATURE = "sig"; + public static final String READ_PERMISSION_MODE = "read"; + public static final String ALL_PERMISSION_MODE = "all"; + public static final String PATH_SEPARATOR = "/"; + + public static final int DEFAULT_MAX_PAGE_SIZE = 100; + public static final String ENABLE_MULTIPLE_WRITE_LOCATIONS = "enableMultipleWriteLocations"; + + // Conflict resolution policy + public static final String CONFLICT_RESOLUTION_POLICY = "conflictResolutionPolicy"; + public static final String MODE = "mode"; + public static final String CONFLICT_RESOLUTION_PATH = "conflictResolutionPath"; + public static final String CONFLICT_RESOLUTION_PROCEDURE = "conflictResolutionProcedure"; + + //Handler names for RXNetty httpClient + public static final String SSL_HANDLER_NAME = "ssl-handler"; + public static final String SSL_COMPLETION_HANDLER_NAME = "ssl-completion-handler"; + public static final String HTTP_PROXY_HANDLER_NAME = "http-proxy-handler"; + public static final String LOGGING_HANDLER_NAME = "logging-handler"; + } + + public static final class PartitionedQueryExecutionInfo { + public static final int VERSION_1 = 1; + } + + public static final class QueryExecutionContext { + public static final String INCREMENTAL_FEED_HEADER_VALUE = "Incremental feed"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserver.java new file mode 100644 index 0000000000000..7b2f609a46279 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserver.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverCloseReason; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.function.Consumer; + +class DefaultObserver implements ChangeFeedObserver { + private final Logger log = LoggerFactory.getLogger(DefaultObserver.class); + private Consumer> consumer; + + public DefaultObserver(Consumer> consumer) { + this.consumer = consumer; + } + + @Override + public void open(ChangeFeedObserverContext context) { + log.info("Open processing from thread {}", Thread.currentThread().getId()); + } + + @Override + public void close(ChangeFeedObserverContext context, ChangeFeedObserverCloseReason reason) { + log.info("Close processing from thread {}", Thread.currentThread().getId()); + } + + @Override + public void processChanges(ChangeFeedObserverContext context, List docs) { + log.info("Start processing from thread {}", Thread.currentThread().getId()); + consumer.accept(docs); + log.info("Done processing from thread {}", Thread.currentThread().getId()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserverFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserverFactory.java new file mode 100644 index 0000000000000..73b70cf4fd0d9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DefaultObserverFactory.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.function.Consumer; + +class DefaultObserverFactory implements ChangeFeedObserverFactory { + private final Logger log = LoggerFactory.getLogger(DefaultObserverFactory.class); + + private Consumer> consumer; + + public DefaultObserverFactory(Consumer> consumer) { + this.consumer = consumer; + } + + @Override + public ChangeFeedObserver createObserver() { + return new DefaultObserver(consumer); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseStore.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseStore.java new file mode 100644 index 0000000000000..6ba222f2311e0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseStore.java @@ -0,0 +1,187 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.AccessCondition; +import com.azure.data.cosmos.AccessConditionType; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.LeaseStore; +import com.azure.data.cosmos.internal.changefeed.RequestOptionsFactory; +import com.azure.data.cosmos.internal.changefeed.ServiceItemLease; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Implementation for LeaseStore. + */ +class DocumentServiceLeaseStore implements LeaseStore { + private ChangeFeedContextClient client; + private String containerNamePrefix; + private CosmosContainer leaseCollectionLink; + private RequestOptionsFactory requestOptionsFactory; + private String lockETag; + + // TODO: rename to LeaseStoreImpl + public DocumentServiceLeaseStore( + ChangeFeedContextClient client, + String containerNamePrefix, + CosmosContainer leaseCollectionLink, + RequestOptionsFactory requestOptionsFactory) { + + this.client = client; + this.containerNamePrefix = containerNamePrefix; + this.leaseCollectionLink = leaseCollectionLink; + this.requestOptionsFactory = requestOptionsFactory; + } + + @Override + public Mono isInitialized() { + String markerDocId = this.getStoreMarkerName(); + + CosmosItemProperties doc = new CosmosItemProperties(); + doc.id(markerDocId); + + CosmosItemRequestOptions requestOptions = this.requestOptionsFactory.createRequestOptions( + ServiceItemLease.fromDocument(doc)); + + CosmosItem docItem = this.client.getContainerClient().getItem(markerDocId, "/id"); + return this.client.readItem(docItem, requestOptions) + .flatMap(documentResourceResponse -> Mono.just(documentResourceResponse.item() != null)) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) throwable; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND) { + return Mono.just(false); + } + } + return Mono.error(throwable); + }); + } + + @Override + public Mono markInitialized() { + String markerDocId = this.getStoreMarkerName(); + CosmosItemProperties containerDocument = new CosmosItemProperties(); + containerDocument.id(markerDocId); + + return this.client.createItem(this.leaseCollectionLink, containerDocument, null, false) + .map( item -> true) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) throwable; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_CONFLICT) { + return Mono.just(true); + } + } + return Mono.just(false); + }); + } + + @Override + public Mono acquireInitializationLock(Duration lockExpirationTime) { + String lockId = this.getStoreLockName(); + CosmosItemProperties containerDocument = new CosmosItemProperties(); + containerDocument.id(lockId); + BridgeInternal.setProperty(containerDocument, com.azure.data.cosmos.internal.Constants.Properties.TTL, Long.valueOf(lockExpirationTime.getSeconds()).intValue()); + + DocumentServiceLeaseStore self = this; + + return this.client.createItem(this.leaseCollectionLink, containerDocument, null, false) + .map(documentResourceResponse -> { + if (documentResourceResponse.item() != null) { + self.lockETag = documentResourceResponse.properties().etag(); + return true; + } else { + return false; + } + }) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) throwable; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_CONFLICT) { + return Mono.just(false); + } + } + return Mono.error(throwable); + }); + } + + @Override + public Mono releaseInitializationLock() { + String lockId = this.getStoreLockName(); + CosmosItemProperties doc = new CosmosItemProperties(); + doc.id(lockId); + + CosmosItemRequestOptions requestOptions = this.requestOptionsFactory.createRequestOptions( + ServiceItemLease.fromDocument(doc)); + + if (requestOptions == null) { + requestOptions = new CosmosItemRequestOptions(); + } + + AccessCondition accessCondition = new AccessCondition(); + accessCondition.type(AccessConditionType.IF_MATCH); + accessCondition.condition(this.lockETag); + requestOptions.accessCondition(accessCondition); + DocumentServiceLeaseStore self = this; + + CosmosItem docItem = this.client.getContainerClient().getItem(lockId, "/id"); + return this.client.deleteItem(docItem, requestOptions) + .map(documentResourceResponse -> { + if (documentResourceResponse.item() != null) { + self.lockETag = null; + return true; + } else { + return false; + } + }) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) throwable; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_CONFLICT) { + return Mono.just(false); + } + } + + return Mono.error(throwable); + }); + } + + private String getStoreMarkerName() + { + return this.containerNamePrefix + ".info"; + } + + private String getStoreLockName() + { + return this.containerNamePrefix + ".lock"; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseUpdaterImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseUpdaterImpl.java new file mode 100644 index 0000000000000..eee04010a4c19 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/DocumentServiceLeaseUpdaterImpl.java @@ -0,0 +1,204 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.AccessCondition; +import com.azure.data.cosmos.AccessConditionType; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.ServiceItemLease; +import com.azure.data.cosmos.internal.changefeed.ServiceItemLeaseUpdater; +import com.azure.data.cosmos.internal.changefeed.exceptions.LeaseLostException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.function.Function; + +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.HTTP_STATUS_CODE_CONFLICT; +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND; +import static com.azure.data.cosmos.internal.changefeed.implementation.ChangeFeedHelper.HTTP_STATUS_CODE_PRECONDITION_FAILED; + +/** + * Implementation for service lease updater interface. + */ +class DocumentServiceLeaseUpdaterImpl implements ServiceItemLeaseUpdater { + private final Logger logger = LoggerFactory.getLogger(DocumentServiceLeaseUpdaterImpl.class); + private final int RETRY_COUNT_ON_CONFLICT = 5; + private final ChangeFeedContextClient client; + + public DocumentServiceLeaseUpdaterImpl(ChangeFeedContextClient client) { + if (client == null) { + throw new IllegalArgumentException("client"); + } + + this.client = client; + } + + @Override + public Mono updateLease(Lease cachedLease, CosmosItem itemLink, CosmosItemRequestOptions requestOptions, Function updateLease) { + DocumentServiceLeaseUpdaterImpl self = this; + Lease arrayLease[] = {cachedLease}; + arrayLease[0] = updateLease.apply(cachedLease); + + if (arrayLease[0] == null) { + return Mono.empty(); + } + + arrayLease[0].setTimestamp(ZonedDateTime.now(ZoneId.of("UTC"))); + + return self.tryReplaceLease(arrayLease[0], itemLink) + .map(leaseDocument -> { + arrayLease[0] = ServiceItemLease.fromDocument(leaseDocument); + return arrayLease[0]; + }) + .hasElement() + .flatMap(hasItems -> { + if (hasItems) { + return Mono.just(arrayLease[0]); + } + // Partition lease update conflict. Reading the current version of lease. + return this.client.readItem(itemLink, requestOptions) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + CosmosClientException ex = (CosmosClientException) throwable; + if (ex.statusCode() == HTTP_STATUS_CODE_NOT_FOUND) { + // Partition lease no longer exists + throw Exceptions.propagate(new LeaseLostException(arrayLease[0])); + } + } + return Mono.error(throwable); + }) + .map(cosmosItemResponse -> { + CosmosItemProperties document = cosmosItemResponse.properties(); + ServiceItemLease serverLease = ServiceItemLease.fromDocument(document); + logger.info( + "Partition {} update failed because the lease with token '{}' was updated by host '{}' with token '{}'.", + arrayLease[0].getLeaseToken(), + arrayLease[0].getConcurrencyToken(), + serverLease.getOwner(), + serverLease.getConcurrencyToken()); + arrayLease[0] = serverLease; + + throw Exceptions.propagate(new RuntimeException("")); + }); + }) + .retry(RETRY_COUNT_ON_CONFLICT, throwable -> { + if (throwable instanceof RuntimeException) { + return throwable instanceof LeaseLostException; + } + return false; + }); + +// Lease lease = cachedLease; +// +// for (int retryCount = RETRY_COUNT_ON_CONFLICT; retryCount > 0; retryCount--) { +// lease = updateLease.apply(lease); +// +// if (lease == null) { +// return Mono.empty(); +// } +// +// lease.setTimestamp(ZonedDateTime.now(ZoneId.of("UTC"))); +// CosmosItemProperties leaseDocument = this.tryReplaceLease(lease, itemLink).block(); +// +// if (leaseDocument != null) { +// return Mono.just(ServiceItemLease.fromDocument(leaseDocument)); +// } +// +// // Partition lease update conflict. Reading the current version of lease. +// CosmosItemProperties document = null; +// try { +// CosmosItemResponse response = this.client.readItem(itemLink, requestOptions) +// .block(); +// document = response.properties(); +// } catch (RuntimeException re) { +// if (re.getCause() instanceof CosmosClientException) { +// CosmosClientException ex = (CosmosClientException) re.getCause(); +// if (ex.statusCode() == HTTP_STATUS_CODE_NOT_FOUND) { +// // Partition lease no longer exists +// throw new LeaseLostException(lease); +// } +// } +// throw re; +// } +// +// ServiceItemLease serverLease = ServiceItemLease.fromDocument(document); +// logger.info( +// "Partition {} update failed because the lease with token '{}' was updated by host '{}' with token '{}'. Will retry, {} retry(s) left.", +// lease.getLeaseToken(), +// lease.getConcurrencyToken(), +// serverLease.getOwner(), +// serverLease.getConcurrencyToken(), +// retryCount); +// +// lease = serverLease; +// } +// +// throw new LeaseLostException(lease); + } + + private Mono tryReplaceLease(Lease lease, CosmosItem itemLink) throws LeaseLostException { + DocumentServiceLeaseUpdaterImpl self = this; + return this.client.replaceItem(itemLink, lease, this.getCreateIfMatchOptions(lease)) + .map(cosmosItemResponse -> cosmosItemResponse.properties()) + .onErrorResume(re -> { + if (re instanceof CosmosClientException) { + CosmosClientException ex = (CosmosClientException) re; + switch (ex.statusCode()) { + case HTTP_STATUS_CODE_PRECONDITION_FAILED: { + return Mono.empty(); + } + case HTTP_STATUS_CODE_CONFLICT: { + throw Exceptions.propagate( new LeaseLostException(lease, ex, false)); + } + case HTTP_STATUS_CODE_NOT_FOUND: { + throw Exceptions.propagate( new LeaseLostException(lease, ex, true)); + } + default: { + return Mono.error(re); + } + } + } + return Mono.error(re); + }); + } + + private CosmosItemRequestOptions getCreateIfMatchOptions(Lease lease) { + AccessCondition ifMatchCondition = new AccessCondition(); + ifMatchCondition.type(AccessConditionType.IF_MATCH); + ifMatchCondition.condition(lease.getConcurrencyToken()); + + CosmosItemRequestOptions createIfMatchOptions = new CosmosItemRequestOptions(); + createIfMatchOptions.accessCondition(ifMatchCondition); + + return createIfMatchOptions; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/EqualPartitionsBalancingStrategy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/EqualPartitionsBalancingStrategy.java new file mode 100644 index 0000000000000..730e161ac1c18 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/EqualPartitionsBalancingStrategy.java @@ -0,0 +1,189 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancingStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implementation for {@link PartitionLoadBalancingStrategy}. + */ +class EqualPartitionsBalancingStrategy implements PartitionLoadBalancingStrategy { + private final Logger logger = LoggerFactory.getLogger(EqualPartitionsBalancingStrategy.class); + private final String hostName; + private final int minPartitionCount; + private final int maxPartitionCount; + private final Duration leaseExpirationInterval; + + public EqualPartitionsBalancingStrategy(String hostName, int minPartitionCount, int maxPartitionCount, Duration leaseExpirationInterval) { + if (hostName == null) throw new IllegalArgumentException("hostName"); + this.hostName = hostName; + this.minPartitionCount = minPartitionCount; + this.maxPartitionCount = maxPartitionCount; + this.leaseExpirationInterval = leaseExpirationInterval; + } + + @Override + public List selectLeasesToTake(List allLeases) { + Map workerToPartitionCount = new HashMap<>(); + List expiredLeases = new ArrayList<>(); + Map allPartitions = new HashMap<>(); + + this.categorizeLeases(allLeases, allPartitions, expiredLeases, workerToPartitionCount); + + int partitionCount = allPartitions.size(); + int workerCount = workerToPartitionCount.size(); + if (partitionCount <= 0) + return new ArrayList(); + + int target = this.calculateTargetPartitionCount(partitionCount, workerCount); + int myCount = workerToPartitionCount.get(this.hostName); + int partitionsNeededForMe = target - myCount; + + /* + Logger.InfoFormat( + "Host '{0}' {1} partitions, {2} hosts, {3} available leases, target = {4}, min = {5}, max = {6}, mine = {7}, will try to take {8} lease(s) for myself'.", + this.hostName, + partitionCount, + workerCount, + expiredLeases.Count, + target, + this.minScaleCount, + this.maxScaleCount, + myCount, + Math.Max(partitionsNeededForMe, 0)); + */ + + if (partitionsNeededForMe <= 0) + return new ArrayList(); + + if (expiredLeases.size() > 0) { + return expiredLeases.subList(0, partitionsNeededForMe); + } + + Lease stolenLease = getLeaseToSteal(workerToPartitionCount, target, partitionsNeededForMe, allPartitions); + List stolenLeases = new ArrayList<>(); + + if (stolenLease == null) { + stolenLeases.add(stolenLease); + } + + return stolenLeases; + } + + private static Lease getLeaseToSteal( + Map workerToPartitionCount, + int target, + int partitionsNeededForMe, + Map allPartitions) { + + Map.Entry workerToStealFrom = findWorkerWithMostPartitions(workerToPartitionCount); + + if (workerToStealFrom.getValue() > target - (partitionsNeededForMe > 1 ? 1 : 0)) { + for (Map.Entry entry : allPartitions.entrySet()) { + if (entry.getValue().getOwner().equalsIgnoreCase(workerToStealFrom.getKey())) { + return entry.getValue(); + } + } + } + + return null; + } + + private static Map.Entry findWorkerWithMostPartitions(Map workerToPartitionCount) { + Map.Entry workerToStealFrom = new ChangeFeedHelper.KeyValuePair<>("", 0); + for (Map.Entry entry : workerToPartitionCount.entrySet()) { + if (workerToStealFrom.getValue() <= entry.getValue()) { + workerToStealFrom = entry; + } + } + + return workerToStealFrom; + } + + private int calculateTargetPartitionCount(int partitionCount, int workerCount) { + int target = 1; + if (partitionCount > workerCount) { + target = (int)Math.ceil((double)partitionCount / workerCount); + } + + if (this.maxPartitionCount > 0 && target > this.maxPartitionCount) { + target = this.maxPartitionCount; + } + + if (this.minPartitionCount > 0 && target < this.minPartitionCount) { + target = this.minPartitionCount; + } + + return target; + } + + private void categorizeLeases( + List allLeases, + Map allPartitions, + List expiredLeases, + Map workerToPartitionCount) { + + for (Lease lease : allLeases) { + // Debug.Assert(lease.LeaseToken != null, "TakeLeasesAsync: lease.LeaseToken cannot be null."); + + allPartitions.put(lease.getLeaseToken(), lease); + + if (lease.getOwner() == null || lease.getOwner().isEmpty() || this.isExpired(lease)) { + // Logger.DebugFormat("Found unused or expired lease: {0}", lease); + expiredLeases.add(lease); + } else { + String assignedTo = lease.getOwner(); + Integer count = workerToPartitionCount.get(assignedTo); + + if (count != null) { + workerToPartitionCount.replace(assignedTo, count + 1); + } else { + workerToPartitionCount.put(assignedTo, 1); + } + } + } + + if (!workerToPartitionCount.containsKey(this.hostName)) { + workerToPartitionCount.put(this.hostName, 0); + } + } + + private boolean isExpired(Lease lease) { + if (lease.getOwner() == null || lease.getOwner().isEmpty() || lease.getTimestamp() == null) { + return true; + } + ZonedDateTime time = ZonedDateTime.parse(lease.getTimestamp()); + return time.plus(this.leaseExpirationInterval).isBefore(ZonedDateTime.now(ZoneId.of("UTC"))); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ExceptionClassifier.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ExceptionClassifier.java new file mode 100644 index 0000000000000..f6b9468690907 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ExceptionClassifier.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosClientException; + +/** + * Classifies exceptions based on the status codes. + */ +class ExceptionClassifier { + public static final int SubStatusCode_Undefined = -1; + + // 410: partition key range is gone. + public static final int SubStatusCode_PartitionKeyRangeGone = 1002; + + // 410: partition splitting. + public static final int SubStatusCode_Splitting = 1007; + + // 404: LSN in session token is higher. + public static final int SubStatusCode_ReadSessionNotAvailable = 1002; + + + public static StatusCodeErrorType classifyClientException(CosmosClientException clientException) { + Integer subStatusCode = clientException.subStatusCode(); + + if (clientException.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND && subStatusCode != SubStatusCode_ReadSessionNotAvailable) + return StatusCodeErrorType.PARTITION_NOT_FOUND; + + if (clientException.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_GONE && (subStatusCode == SubStatusCode_PartitionKeyRangeGone || subStatusCode == SubStatusCode_Splitting)) + return StatusCodeErrorType.PARTITION_SPLIT; + + if (clientException.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_TOO_MANY_REQUESTS || clientException.statusCode() >= ChangeFeedHelper.HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR) + return StatusCodeErrorType.TRANSIENT_ERROR; + + // Temporary workaround to compare exception message, until server provides better way of handling this case. + if (clientException.getMessage().contains("Reduce page size and try again.")) + return StatusCodeErrorType.MAX_ITEM_COUNT_TOO_LARGE; + + return StatusCodeErrorType.UNDEFINED; + + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/HealthMonitoringPartitionControllerDecorator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/HealthMonitoringPartitionControllerDecorator.java new file mode 100644 index 0000000000000..8ea9440903f46 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/HealthMonitoringPartitionControllerDecorator.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.changefeed.HealthMonitor; +import com.azure.data.cosmos.internal.changefeed.HealthMonitoringRecord; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.PartitionController; +import reactor.core.publisher.Mono; + +/** + * Monitors partition controller health. + */ +class HealthMonitoringPartitionControllerDecorator implements PartitionController { + private final PartitionController inner; + private final HealthMonitor monitor; + + public HealthMonitoringPartitionControllerDecorator(PartitionController inner, HealthMonitor monitor) { + if (inner == null) throw new IllegalArgumentException("inner"); + if (monitor == null) throw new IllegalArgumentException("monitor"); + + this.inner = inner; + this.monitor = monitor; + } + + @Override + public Mono addOrUpdateLease(Lease lease) { + return this.inner.addOrUpdateLease(lease) + .onErrorResume(throwable -> { + if (throwable instanceof CosmosClientException) { + // do nothing. + } else { + monitor.inspect(new HealthMonitoringRecord( + HealthMonitoringRecord.HealthSeverity.INFORMATIONAL, + HealthMonitoringRecord.MonitoredOperation.ACQUIRE_LEASE, + lease, throwable)); + } + return Mono.empty(); + }); + } + + @Override + public Mono initialize() { + return this.inner.initialize(); + } + + @Override + public Mono shutdown() { + return this.inner.shutdown(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseRenewerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseRenewerImpl.java new file mode 100644 index 0000000000000..dddba5eb9d257 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseRenewerImpl.java @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.CancellationToken; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseManager; +import com.azure.data.cosmos.internal.changefeed.LeaseRenewer; +import com.azure.data.cosmos.internal.changefeed.exceptions.LeaseLostException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Implementation for the {@link LeaseRenewer}. + */ +class LeaseRenewerImpl implements LeaseRenewer { + private final Logger logger = LoggerFactory.getLogger(LeaseRenewerImpl.class); + private final LeaseManager leaseManager; + private final Duration leaseRenewInterval; + private Lease lease; + private RuntimeException resultException; + + public LeaseRenewerImpl(Lease lease, LeaseManager leaseManager, Duration leaseRenewInterval) + { + this.lease = lease; + this.leaseManager = leaseManager; + this.leaseRenewInterval = leaseRenewInterval; + } + + @Override + public Mono run(CancellationToken cancellationToken) { + LeaseRenewerImpl self = this; + + return Mono.fromRunnable( () -> { + try { + logger.info(String.format("Partition %s: renewer task started.", self.lease.getLeaseToken())); + long remainingWork = this.leaseRenewInterval.toMillis() / 2; + + try { + while (!cancellationToken.isCancellationRequested() && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException ex) { + // exception caught + logger.info(String.format("Partition %s: renewer task stopped.", self.lease.getLeaseToken())); + } + + while (!cancellationToken.isCancellationRequested()) { + self.renew().block(); + + remainingWork = this.leaseRenewInterval.toMillis(); + + try { + while (!cancellationToken.isCancellationRequested() && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException ex) { + // exception caught + logger.info(String.format("Partition %s: renewer task stopped.", self.lease.getLeaseToken())); + break; + } + } + } catch (RuntimeException ex) { + logger.error(String.format("Partition %s: renew lease loop failed.", self.lease.getLeaseToken()), ex); + self.resultException = ex; + } + }); + } + + @Override + public RuntimeException getResultException() { + return this.resultException; + } + + private Mono renew() { + LeaseRenewerImpl self = this; + + return Mono.fromRunnable( () -> { + try { + Lease renewedLease = self.leaseManager.renew(this.lease).block(); + if (renewedLease != null) this.lease = renewedLease; + + logger.info(String.format("Partition %s: renewed lease with result %s", self.lease.getLeaseToken(), renewedLease != null)); + } catch (LeaseLostException leaseLostException) { + logger.error(String.format("Partition %s: lost lease on renew.", self.lease.getLeaseToken()), leaseLostException); + self.resultException = leaseLostException; + throw leaseLostException; + } catch (Exception ex) { + logger.error(String.format("Partition %s: failed to renew lease.", self.lease.getLeaseToken()), ex); + } + }); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseStoreManagerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseStoreManagerImpl.java new file mode 100644 index 0000000000000..224c69f7f7311 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/LeaseStoreManagerImpl.java @@ -0,0 +1,443 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseStore; +import com.azure.data.cosmos.internal.changefeed.LeaseStoreManager; +import com.azure.data.cosmos.internal.changefeed.LeaseStoreManagerSettings; +import com.azure.data.cosmos.internal.changefeed.RequestOptionsFactory; +import com.azure.data.cosmos.internal.changefeed.ServiceItemLease; +import com.azure.data.cosmos.internal.changefeed.ServiceItemLeaseUpdater; +import com.azure.data.cosmos.internal.changefeed.exceptions.LeaseLostException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.Exceptions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * Provides flexible way to build lease manager constructor parameters. + * For the actual creation of lease manager instance, delegates to lease manager factory. + */ +public class LeaseStoreManagerImpl implements LeaseStoreManager, LeaseStoreManager.LeaseStoreManagerBuilderDefinition { + + private final Logger logger = LoggerFactory.getLogger(LeaseStoreManagerImpl.class); + private LeaseStoreManagerSettings settings; + private ChangeFeedContextClient leaseDocumentClient; + private RequestOptionsFactory requestOptionsFactory; + private ServiceItemLeaseUpdater leaseUpdater; + private LeaseStore leaseStore; + + + public static LeaseStoreManagerBuilderDefinition Builder() { + return new LeaseStoreManagerImpl(); + } + + public LeaseStoreManagerImpl() { + this.settings = new LeaseStoreManagerSettings(); + } + + @Override + public LeaseStoreManagerBuilderDefinition leaseContextClient(ChangeFeedContextClient leaseContextClient) { + if (leaseContextClient == null) { + throw new IllegalArgumentException("leaseContextClient"); + } + + this.leaseDocumentClient = leaseContextClient; + return this; + } + + @Override + public LeaseStoreManagerBuilderDefinition leasePrefix(String leasePrefix) { + if (leasePrefix == null) { + throw new IllegalArgumentException("leasePrefix"); + } + + this.settings.withContainerNamePrefix(leasePrefix); + return this; + } + + @Override + public LeaseStoreManagerBuilderDefinition leaseCollectionLink(CosmosContainer leaseCollectionLink) { + if (leaseCollectionLink == null) { + throw new IllegalArgumentException("leaseCollectionLink"); + } + + this.settings.withLeaseCollectionLink(leaseCollectionLink); + return this; + } + + @Override + public LeaseStoreManagerBuilderDefinition requestOptionsFactory(RequestOptionsFactory requestOptionsFactory) { + if (requestOptionsFactory == null) { + throw new IllegalArgumentException("requestOptionsFactory"); + } + + this.requestOptionsFactory = requestOptionsFactory; + return this; + } + + @Override + public LeaseStoreManagerBuilderDefinition hostName(String hostName) { + if (hostName == null) { + throw new IllegalArgumentException("hostName"); + } + + this.settings.withHostName(hostName); + return this; + } + + @Override + public Mono build() { + if (this.settings == null) throw new IllegalArgumentException("properties"); + if (this.settings.getContainerNamePrefix() == null) throw new IllegalArgumentException("properties.containerNamePrefix"); + if (this.settings.getLeaseCollectionLink() == null) throw new IllegalArgumentException("properties.leaseCollectionLink"); + if (this.settings.getHostName() == null || this.settings.getHostName().isEmpty()) throw new IllegalArgumentException("properties.hostName"); + if (this.leaseDocumentClient == null) throw new IllegalArgumentException("leaseDocumentClient"); + if (this.requestOptionsFactory == null) throw new IllegalArgumentException("requestOptionsFactory"); + if (this.leaseUpdater == null) { + this.leaseUpdater = new DocumentServiceLeaseUpdaterImpl(leaseDocumentClient); + } + + this.leaseStore = new DocumentServiceLeaseStore( + this.leaseDocumentClient, + this.settings.getContainerNamePrefix(), + this.settings.getLeaseCollectionLink(), + this.requestOptionsFactory); + + LeaseStoreManagerImpl self = this; + if (this.settings.getLeaseCollectionLink() == null) + throw new IllegalArgumentException("leaseCollectionLink was not specified"); + if (this.requestOptionsFactory == null) + throw new IllegalArgumentException("requestOptionsFactory was not specified"); + + return Mono.just(self); + } + + @Override + public Flux getAllLeases() { + return this.listDocuments(this.getPartitionLeasePrefix()) + .map(documentServiceLease -> documentServiceLease); + } + + @Override + public Flux getOwnedLeases() { + LeaseStoreManagerImpl self = this; + return this.getAllLeases() + .filter(lease -> lease.getOwner() != null && lease.getOwner().equalsIgnoreCase(self.settings.getHostName())); + } + + @Override + public Mono createLeaseIfNotExist(String leaseToken, String continuationToken) { + if (leaseToken == null) throw new IllegalArgumentException("leaseToken"); + + String leaseDocId = this.getDocumentId(leaseToken); + ServiceItemLease documentServiceLease = new ServiceItemLease() + .withId(leaseDocId) + .withLeaseToken(leaseToken) + .withContinuationToken(continuationToken); + + return this.leaseDocumentClient.createItem(this.settings.getLeaseCollectionLink(), documentServiceLease, null, false) + .onErrorResume( ex -> { + if (ex instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) ex; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_CONFLICT) { + logger.info("Some other host created lease for {}.", leaseToken); + return Mono.empty(); + } + } + + return Mono.error(ex); + }) + .map(documentResourceResponse -> { + if (documentResourceResponse == null) return null; + + CosmosItemProperties document = documentResourceResponse.properties(); + + logger.info("Created lease for partition {}.", leaseToken); + + return documentServiceLease + .withId(document.id()) + .withEtag(document.etag()) + .withTs(document.getString(Constants.Properties.LAST_MODIFIED)); + }); + } + + @Override + public Mono delete(Lease lease) { + if (lease == null || lease.getId() == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + CosmosItem itemForLease = this.createItemForLease(lease.getId()); + + return this.leaseDocumentClient + .deleteItem(itemForLease, this.requestOptionsFactory.createRequestOptions(lease)) + .onErrorResume( ex -> { + if (ex instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) ex; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND) { + // Ignore - document was already deleted. + return Mono.empty(); + } + } + + return Mono.error(ex); + }) + // return some add-hoc value since we don't actually care about the result. + .map( documentResourceResponse -> true) + .then(); + } + + @Override + public Mono acquire(Lease lease) { + if (lease == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + String oldOwner = lease.getOwner(); + + return this.leaseUpdater.updateLease( + lease, + this.createItemForLease(lease.getId()), + this.requestOptionsFactory.createRequestOptions(lease), + serverLease -> { + if (serverLease.getOwner() != null && !serverLease.getOwner().equalsIgnoreCase(oldOwner)) { + logger.info("Partition {} lease was taken over by owner '{}'", lease.getLeaseToken(), serverLease.getOwner()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + serverLease.setOwner(this.settings.getHostName()); + serverLease.setProperties(lease.getProperties()); + + return serverLease; + }); + } + + @Override + public Mono release(Lease lease) { + if (lease == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + CosmosItem itemForLease = this.createItemForLease(lease.getId()); + LeaseStoreManagerImpl self = this; + + return this.leaseDocumentClient.readItem(itemForLease, this.requestOptionsFactory.createRequestOptions(lease)) + .onErrorResume( ex -> { + if (ex instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) ex; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND) { + logger.info("Partition {} failed to renew lease. The lease is gone already.", lease.getLeaseToken()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + } + + return Mono.error(ex); + }) + .map( documentResourceResponse -> ServiceItemLease.fromDocument(documentResourceResponse.properties())) + .flatMap( refreshedLease -> self.leaseUpdater.updateLease( + refreshedLease, + self.createItemForLease(refreshedLease.getId()), + self.requestOptionsFactory.createRequestOptions(lease), + serverLease -> + { + if (serverLease.getOwner() != null) { + if (!serverLease.getOwner().equalsIgnoreCase(lease.getOwner())) { + logger.info("Partition {} no need to release lease. The lease was already taken by another host '{}'.", lease.getLeaseToken(), serverLease.getOwner()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + } + + serverLease.setOwner(null); + + return serverLease; + }) + ).then(); + } + + @Override + public Mono renew(Lease lease) { + if (lease == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + // Get fresh lease. The assumption here is that check-pointing is done with higher frequency than lease renewal so almost + // certainly the lease was updated in between. + CosmosItem itemForLease = this.createItemForLease(lease.getId()); + LeaseStoreManagerImpl self = this; + + return this.leaseDocumentClient.readItem(itemForLease, this.requestOptionsFactory.createRequestOptions(lease)) + .onErrorResume( ex -> { + if (ex instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) ex; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND) { + logger.info("Partition {} failed to renew lease. The lease is gone already.", lease.getLeaseToken()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + } + + return Mono.error(ex); + }) + .map( documentResourceResponse -> ServiceItemLease.fromDocument(documentResourceResponse.properties())) + .flatMap( refreshedLease -> self.leaseUpdater.updateLease( + refreshedLease, + self.createItemForLease(refreshedLease.getId()), + self.requestOptionsFactory.createRequestOptions(lease), + serverLease -> + { + if (!serverLease.getOwner().equalsIgnoreCase(lease.getOwner())) { + logger.info("Partition {} lease was taken over by owner '{}'", lease.getLeaseToken(), serverLease.getOwner()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + + return serverLease; + }) + ); + } + + @Override + public Mono updateProperties(Lease lease) { + if (lease == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + if (!lease.getOwner().equalsIgnoreCase(this.settings.getHostName())) + { + logger.info("Partition '{}' lease was taken over by owner '{}' before lease item update", lease.getLeaseToken(), lease.getOwner()); + throw new LeaseLostException(lease); + } + + return this.leaseUpdater.updateLease( + lease, + this.createItemForLease(lease.getId()), + this.requestOptionsFactory.createRequestOptions(lease), + serverLease -> { + if (!serverLease.getOwner().equalsIgnoreCase(lease.getOwner())) { + logger.info("Partition '{}' lease was taken over by owner '{}'", lease.getLeaseToken(), serverLease.getOwner()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + serverLease.setProperties(lease.getProperties()); + return serverLease; + }); + } + + @Override + public Mono checkpoint(Lease lease, String continuationToken) { + if (lease == null) throw Exceptions.propagate(new IllegalArgumentException("lease")); + + if (continuationToken == null || continuationToken.isEmpty()) { + throw new IllegalArgumentException("continuationToken must be a non-empty string"); + } + + return this.leaseUpdater.updateLease( + lease, + this.createItemForLease(lease.getId()), + this.requestOptionsFactory.createRequestOptions(lease), + serverLease -> { + if (serverLease.getOwner() != null && !serverLease.getOwner().equalsIgnoreCase(lease.getOwner())) { + logger.info("Partition {} lease was taken over by owner '{}'", lease.getLeaseToken(), serverLease.getOwner()); + throw Exceptions.propagate(new LeaseLostException(lease)); + } + serverLease.setContinuationToken(continuationToken); + + return serverLease; + }); + } + + @Override + public Mono isInitialized() { + return this.leaseStore.isInitialized(); + } + + @Override + public Mono markInitialized() { + return this.leaseStore.markInitialized(); + } + + @Override + public Mono acquireInitializationLock(Duration lockExpirationTime) { + return this.leaseStore.acquireInitializationLock(lockExpirationTime); + } + + @Override + public Mono releaseInitializationLock() { + return this.leaseStore.releaseInitializationLock(); + } + + private Mono tryGetLease(Lease lease) { + CosmosItem itemForLease = this.createItemForLease(lease.getId()); + + return this.leaseDocumentClient.readItem(itemForLease, this.requestOptionsFactory.createRequestOptions(lease)) + .onErrorResume( ex -> { + if (ex instanceof CosmosClientException) { + CosmosClientException e = (CosmosClientException) ex; + if (e.statusCode() == ChangeFeedHelper.HTTP_STATUS_CODE_NOT_FOUND) { + return Mono.empty(); + } + } + + return Mono.error(ex); + }) + .map( documentResourceResponse -> { + if (documentResourceResponse == null) return null; + return ServiceItemLease.fromDocument(documentResourceResponse.properties()); + }); + } + + private Flux listDocuments(String prefix) { + if (prefix == null || prefix.isEmpty()) { + throw new IllegalArgumentException("prefix"); + } + + SqlParameter param = new SqlParameter(); + param.name("@PartitionLeasePrefix"); + param.value(prefix); + SqlQuerySpec querySpec = new SqlQuerySpec( + "SELECT * FROM c WHERE STARTSWITH(c.id, @PartitionLeasePrefix)", + new SqlParameterList(param)); + + Flux> query = this.leaseDocumentClient.queryItems( + this.settings.getLeaseCollectionLink(), + querySpec, + this.requestOptionsFactory.createFeedOptions()); + + return query.flatMap( documentFeedResponse -> Flux.fromIterable(documentFeedResponse.results())) + .map( ServiceItemLease::fromDocument); + } + + private String getDocumentId(String leaseToken) + { + return this.getPartitionLeasePrefix() + leaseToken; + } + + private String getPartitionLeasePrefix() + { + return this.settings.getContainerNamePrefix() + ".."; + } + + private CosmosItem createItemForLease(String leaseId) { + return this.leaseDocumentClient.getContainerClient().getItem(leaseId, "/id"); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ObserverExceptionWrappingChangeFeedObserverDecorator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ObserverExceptionWrappingChangeFeedObserverDecorator.java new file mode 100644 index 0000000000000..f228389e59514 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/ObserverExceptionWrappingChangeFeedObserverDecorator.java @@ -0,0 +1,82 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverCloseReason; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import com.azure.data.cosmos.internal.changefeed.exceptions.ObserverException; + +import java.util.List; + +/** + * Exception wrapping decorator implementation for {@link ChangeFeedObserver}. + */ +class ObserverExceptionWrappingChangeFeedObserverDecorator implements ChangeFeedObserver { + private ChangeFeedObserver changeFeedObserver; + + public ObserverExceptionWrappingChangeFeedObserverDecorator(ChangeFeedObserver changeFeedObserver) + { + this.changeFeedObserver = changeFeedObserver; + } + + @Override + public void open(ChangeFeedObserverContext context) { + try + { + this.changeFeedObserver.open(context); + } + catch (RuntimeException userException) + { + // Logger.WarnException("Exception happened on Observer.OpenAsync", userException); + throw new ObserverException(userException); + } + } + + @Override + public void close(ChangeFeedObserverContext context, ChangeFeedObserverCloseReason reason) { + try + { + this.changeFeedObserver.close(context, reason); + } + catch (RuntimeException userException) + { + // Logger.WarnException("Exception happened on Observer.CloseAsync", userException); + throw new ObserverException(userException); + } + } + + @Override + public void processChanges(ChangeFeedObserverContext context, List docs) { + try + { + this.changeFeedObserver.processChanges(context, docs); + } + catch (Exception userException) + { + // Logger.WarnException("Exception happened on Observer.OpenAsync", userException); + throw new ObserverException(userException); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionCheckpointerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionCheckpointerImpl.java new file mode 100644 index 0000000000000..08519d7c4dedb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionCheckpointerImpl.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseCheckpointer; +import com.azure.data.cosmos.internal.changefeed.PartitionCheckpointer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +/** + * Checkpoint the given partition up to the given continuation token. + */ +class PartitionCheckpointerImpl implements PartitionCheckpointer { + private final Logger logger = LoggerFactory.getLogger(PartitionCheckpointerImpl.class); + private final LeaseCheckpointer leaseCheckpointer; + private Lease lease; + + public PartitionCheckpointerImpl(LeaseCheckpointer leaseCheckpointer, Lease lease) { + this.leaseCheckpointer = leaseCheckpointer; + this.lease = lease; + } + + @Override + public Mono checkpointPartition(String сontinuationToken) { + PartitionCheckpointerImpl self = this; + return this.leaseCheckpointer.checkpoint(this.lease, сontinuationToken) + .map(lease1 -> { + self.lease = lease1; + logger.info(String.format("Checkpoint: partition %s, new continuation %s", self.lease.getLeaseToken(), self.lease.getContinuationToken())); + return lease1; + }) + .then(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionControllerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionControllerImpl.java new file mode 100644 index 0000000000000..b290114d48dc0 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionControllerImpl.java @@ -0,0 +1,186 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.CancellationToken; +import com.azure.data.cosmos.internal.changefeed.CancellationTokenSource; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseContainer; +import com.azure.data.cosmos.internal.changefeed.LeaseManager; +import com.azure.data.cosmos.internal.changefeed.PartitionController; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisor; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisorFactory; +import com.azure.data.cosmos.internal.changefeed.PartitionSynchronizer; +import com.azure.data.cosmos.internal.changefeed.exceptions.PartitionSplitException; +import com.azure.data.cosmos.internal.changefeed.exceptions.TaskCancelledException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; + +/** + * Implementation for {@link PartitionController}. + */ +class PartitionControllerImpl implements PartitionController { + private final Logger logger = LoggerFactory.getLogger(PartitionControllerImpl.class); + private final Map currentlyOwnedPartitions = new ConcurrentHashMap<>(); + + private final LeaseContainer leaseContainer; + private final LeaseManager leaseManager; + private final PartitionSupervisorFactory partitionSupervisorFactory; + private final PartitionSynchronizer synchronizer; + private CancellationTokenSource shutdownCts; + + private final ExecutorService executorService; + + public PartitionControllerImpl( + LeaseContainer leaseContainer, + LeaseManager leaseManager, + PartitionSupervisorFactory partitionSupervisorFactory, + PartitionSynchronizer synchronizer, + ExecutorService executorService) { + + this.leaseContainer = leaseContainer; + this.leaseManager = leaseManager; + this.partitionSupervisorFactory = partitionSupervisorFactory; + this.synchronizer = synchronizer; + this.executorService = executorService; + } + + @Override + public Mono initialize() { + this.shutdownCts = new CancellationTokenSource(); + return this.loadLeases(); + } + + @Override + public synchronized Mono addOrUpdateLease(Lease lease) { + WorkerTask workerTask = this.currentlyOwnedPartitions.get(lease.getLeaseToken()); + if ( workerTask != null && workerTask.isRunning()) { + Lease updatedLease = this.leaseManager.updateProperties(lease).block(); + logger.debug(String.format("Partition %s: updated.", lease.getLeaseToken())); + return Mono.just(updatedLease); + } + + try { + Lease updatedLease = this.leaseManager.acquire(lease).block(); + if (updatedLease != null) lease = updatedLease; + + logger.info(String.format("Partition %s: acquired.", lease.getLeaseToken())); + } catch (RuntimeException ex) { + this.removeLease(lease).block(); + throw ex; + } + + PartitionSupervisor supervisor = this.partitionSupervisorFactory.create(lease); + this.currentlyOwnedPartitions.put(lease.getLeaseToken(), this.processPartition(supervisor, lease)); + + return Mono.just(lease); + } + + @Override + public Mono shutdown() { + // TODO: wait for the threads to finish. + this.shutdownCts.cancel(); +// this.currentlyOwnedPartitions.clear(); + + return Mono.empty(); + } + + private Mono loadLeases() { + PartitionControllerImpl self = this; + logger.debug("Starting renew leases assigned to this host on initialize."); + + return this.leaseContainer.getOwnedLeases() + .flatMap( lease -> { + logger.info(String.format("Acquired lease for PartitionId '%s' on startup.", lease.getLeaseToken())); + return self.addOrUpdateLease(lease); + }).then(); + } + + private Mono removeLease(Lease lease) { + if (this.currentlyOwnedPartitions.get(lease.getLeaseToken()) != null) { + WorkerTask workerTask = this.currentlyOwnedPartitions.remove(lease.getLeaseToken()); + + if (workerTask.isRunning()) { + workerTask.interrupt(); + } + + logger.info(String.format("Partition %s: released.", lease.getLeaseToken())); + } + + return this.leaseManager.release(lease) + .onErrorResume(e -> { + logger.warn(String.format("Partition %s: failed to remove lease.", lease.getLeaseToken()), e); + return Mono.empty(); + } + ).doOnSuccess(aVoid -> { + logger.info("Partition {}: successfully removed lease.", lease.getLeaseToken()); + }); + } + + private WorkerTask processPartition(PartitionSupervisor partitionSupervisor, Lease lease) { + PartitionControllerImpl self = this; + + CancellationToken cancellationToken = this.shutdownCts.getToken(); + + WorkerTask partitionSupervisorTask = new WorkerTask(lease, () -> { + partitionSupervisor.run(cancellationToken) + .onErrorResume(throwable -> { + if (throwable instanceof PartitionSplitException) { + PartitionSplitException ex = (PartitionSplitException) throwable; + return self.handleSplit(lease, ex.getLastContinuation()); + } else if (throwable instanceof TaskCancelledException) { + logger.debug(String.format("Partition %s: processing canceled.", lease.getLeaseToken())); + } else { + logger.warn(String.format("Partition %s: processing failed.", lease.getLeaseToken()), throwable); + } + + return Mono.empty(); + }) + .then(self.removeLease(lease)).subscribe(); + }); + + this.executorService.execute(partitionSupervisorTask); + + return partitionSupervisorTask; + } + + private Mono handleSplit(Lease lease, String lastContinuationToken) { + PartitionControllerImpl self = this; + + lease.setContinuationToken(lastContinuationToken); + return this.synchronizer.splitPartition(lease) + .flatMap(l -> { + l.setProperties(lease.getProperties()); + return self.addOrUpdateLease(l); + }).then(self.leaseManager.delete(lease)) + .onErrorResume(throwable -> { + logger.warn(String.format("partition %s: failed to split", lease.getLeaseToken()), throwable); + return Mono.empty(); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionLoadBalancerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionLoadBalancerImpl.java new file mode 100644 index 0000000000000..316a9fbce4231 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionLoadBalancerImpl.java @@ -0,0 +1,143 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.CancellationToken; +import com.azure.data.cosmos.internal.changefeed.CancellationTokenSource; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseContainer; +import com.azure.data.cosmos.internal.changefeed.PartitionController; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancer; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancingStrategy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * Implementation for {@link PartitionLoadBalancer}. + */ +class PartitionLoadBalancerImpl implements PartitionLoadBalancer { + private final Logger logger = LoggerFactory.getLogger(PartitionLoadBalancerImpl.class); + private final PartitionController partitionController; + private final LeaseContainer leaseContainer; + private final PartitionLoadBalancingStrategy partitionLoadBalancingStrategy; + private final Duration leaseAcquireInterval; + private final ExecutorService executorService; + + private CancellationTokenSource cancellationTokenSource; + + private volatile boolean started; + + private final Object lock; + + public PartitionLoadBalancerImpl( + PartitionController partitionController, + LeaseContainer leaseContainer, + PartitionLoadBalancingStrategy partitionLoadBalancingStrategy, + Duration leaseAcquireInterval, + ExecutorService executorService) { + + if (partitionController == null) throw new IllegalArgumentException("partitionController"); + if (leaseContainer == null) throw new IllegalArgumentException("leaseContainer"); + if (partitionLoadBalancingStrategy == null) throw new IllegalArgumentException("partitionLoadBalancingStrategy"); + if (executorService == null) throw new IllegalArgumentException("executorService"); + + this.partitionController = partitionController; + this.leaseContainer = leaseContainer; + this.partitionLoadBalancingStrategy = partitionLoadBalancingStrategy; + this.leaseAcquireInterval = leaseAcquireInterval; + this.executorService = executorService; + + this.started = false; + this.lock = new Object(); + } + + @Override + public Mono start() { + PartitionLoadBalancerImpl self = this; + + return Mono.fromRunnable( () -> { + synchronized (lock) { + if (this.started) { + throw new IllegalStateException("Partition load balancer already started"); + } + + this.started = true; + this.cancellationTokenSource = new CancellationTokenSource(); + } + + CancellationToken cancellationToken = this.cancellationTokenSource.getToken(); + + this.executorService.execute(() -> self.run(cancellationToken).block()); + }); + } + + @Override + public Mono stop() { + return Mono.fromRunnable( () -> { + synchronized (lock) { + this.started = false; + this.cancellationTokenSource.cancel(); + } + + this.partitionController.shutdown().block(); + this.cancellationTokenSource = null; + }); + } + + private Mono run(CancellationToken cancellationToken) { + PartitionLoadBalancerImpl self = this; + + return Mono.fromRunnable( () -> { + try { + while (!cancellationToken.isCancellationRequested()) { + List allLeases = self.leaseContainer.getAllLeases().collectList().block(); + List leasesToTake = self.partitionLoadBalancingStrategy.selectLeasesToTake(allLeases); + for (Lease lease : leasesToTake) { + self.partitionController.addOrUpdateLease(lease).block(); + } + + long remainingWork = this.leaseAcquireInterval.toMillis(); + + try { + while (!cancellationToken.isCancellationRequested() && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException ex) { + // exception caught + logger.warn("Partition load balancer caught an interrupted exception", ex); + } + } + } catch (Exception ex) { + // We should not get here. + logger.info("Partition load balancer task stopped."); + this.stop(); + } + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionManagerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionManagerImpl.java new file mode 100644 index 0000000000000..3ca256c544573 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionManagerImpl.java @@ -0,0 +1,59 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.Bootstrapper; +import com.azure.data.cosmos.internal.changefeed.PartitionController; +import com.azure.data.cosmos.internal.changefeed.PartitionLoadBalancer; +import com.azure.data.cosmos.internal.changefeed.PartitionManager; +import reactor.core.publisher.Mono; + +/** + * Implementation for {@link PartitionManager}. + */ +class PartitionManagerImpl implements PartitionManager { + private final Bootstrapper bootstrapper; + private final PartitionController partitionController; + private final PartitionLoadBalancer partitionLoadBalancer; + + public PartitionManagerImpl(Bootstrapper bootstrapper, PartitionController partitionController, PartitionLoadBalancer partitionLoadBalancer) { + this.bootstrapper = bootstrapper; + this.partitionController = partitionController; + this.partitionLoadBalancer = partitionLoadBalancer; + } + + @Override + public Mono start() { + PartitionManagerImpl self = this; + + return self.bootstrapper.initialize() + .then(self.partitionController.initialize()) + .then(self.partitionLoadBalancer.start()); + } + + @Override + public Mono stop() { + PartitionManagerImpl self = this; + return self.partitionLoadBalancer.stop(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorFactoryImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorFactoryImpl.java new file mode 100644 index 0000000000000..87e6bc3405883 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorFactoryImpl.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.ChangeFeedProcessorOptions; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseCheckpointer; +import com.azure.data.cosmos.internal.changefeed.PartitionCheckpointer; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessor; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessorFactory; +import com.azure.data.cosmos.internal.changefeed.ProcessorSettings; + +/** + * Implementation for {@link PartitionProcessorFactory}. + */ +class PartitionProcessorFactoryImpl implements PartitionProcessorFactory { + private final ChangeFeedContextClient documentClient; + private final ChangeFeedProcessorOptions changeFeedProcessorOptions; + private final LeaseCheckpointer leaseCheckpointer; + private final CosmosContainer collectionSelfLink; + + public PartitionProcessorFactoryImpl( + ChangeFeedContextClient documentClient, + ChangeFeedProcessorOptions changeFeedProcessorOptions, + LeaseCheckpointer leaseCheckpointer, + CosmosContainer collectionSelfLink) { + + if (documentClient == null) throw new IllegalArgumentException("documentClient"); + if (changeFeedProcessorOptions == null) throw new IllegalArgumentException("changeFeedProcessorOptions"); + if (leaseCheckpointer == null) throw new IllegalArgumentException("leaseCheckpointer"); + if (collectionSelfLink == null) throw new IllegalArgumentException("collectionSelfLink"); + + this.documentClient = documentClient; + this.changeFeedProcessorOptions = changeFeedProcessorOptions; + this.leaseCheckpointer = leaseCheckpointer; + this.collectionSelfLink = collectionSelfLink; + } + + @Override + public PartitionProcessor create(Lease lease, ChangeFeedObserver observer) { + if (observer == null) throw new IllegalArgumentException("observer"); + if (lease == null) throw new IllegalArgumentException("lease"); + + String startContinuation = lease.getContinuationToken(); + + if (startContinuation == null || startContinuation.isEmpty()) { + startContinuation = this.changeFeedProcessorOptions.startContinuation(); + } + + ProcessorSettings settings = new ProcessorSettings() + .withCollectionLink(this.collectionSelfLink) + .withStartContinuation(startContinuation) + .withPartitionKeyRangeId(lease.getLeaseToken()) + .withFeedPollDelay(this.changeFeedProcessorOptions.feedPollDelay()) + .withMaxItemCount(this.changeFeedProcessorOptions.maxItemCount()) + .withStartFromBeginning(this.changeFeedProcessorOptions.startFromBeginning()) + .withStartTime(this.changeFeedProcessorOptions.startTime()); // .sessionToken(this.changeFeedProcessorOptions.sessionToken()); + + PartitionCheckpointer checkpointer = new PartitionCheckpointerImpl(this.leaseCheckpointer, lease); + return new PartitionProcessorImpl(observer, this.documentClient, settings, checkpointer); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorImpl.java new file mode 100644 index 0000000000000..8f7c563d8fe78 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionProcessorImpl.java @@ -0,0 +1,175 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.changefeed.CancellationToken; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import com.azure.data.cosmos.internal.changefeed.PartitionCheckpointer; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessor; +import com.azure.data.cosmos.internal.changefeed.ProcessorSettings; +import com.azure.data.cosmos.internal.changefeed.exceptions.PartitionNotFoundException; +import com.azure.data.cosmos.internal.changefeed.exceptions.PartitionSplitException; +import com.azure.data.cosmos.internal.changefeed.exceptions.TaskCancelledException; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.List; + +import static com.azure.data.cosmos.CommonsBridgeInternal.partitionKeyRangeIdInternal; + +/** + * Implementation for {@link PartitionProcessor}. + */ +class PartitionProcessorImpl implements PartitionProcessor { + private static final int DefaultMaxItemCount = 100; + // private final Observable> query; + private final ProcessorSettings settings; + private final PartitionCheckpointer checkpointer; + private final ChangeFeedObserver observer; + private final ChangeFeedOptions options; + private final ChangeFeedContextClient documentClient; + private RuntimeException resultException; + + private String lastContinuation; + + public PartitionProcessorImpl(ChangeFeedObserver observer, ChangeFeedContextClient documentClient, ProcessorSettings settings, PartitionCheckpointer checkpointer) { + this.observer = observer; + this.documentClient = documentClient; + this.settings = settings; + this.checkpointer = checkpointer; + + this.options = new ChangeFeedOptions(); + this.options.maxItemCount(settings.getMaxItemCount()); + partitionKeyRangeIdInternal(this.options, settings.getPartitionKeyRangeId()); + // this.options.sessionToken(properties.sessionToken()); + this.options.startFromBeginning(settings.isStartFromBeginning()); + this.options.requestContinuation(settings.getStartContinuation()); + this.options.startDateTime(settings.getStartTime()); + + //this.query = documentClient.createDocumentChangeFeedQuery(self.properties.getCollectionSelfLink(), this.options); + } + + @Override + public Mono run(CancellationToken cancellationToken) { + PartitionProcessorImpl self = this; + this.lastContinuation = this.settings.getStartContinuation(); + + return Mono.fromRunnable( () -> { + while (!cancellationToken.isCancellationRequested()) { + Duration delay = self.settings.getFeedPollDelay(); + + try { + self.options.requestContinuation(self.lastContinuation); + List> documentFeedResponseList = self.documentClient.createDocumentChangeFeedQuery(self.settings.getCollectionSelfLink(), self.options) + .collectList() + .block(); + + for (FeedResponse documentFeedResponse : documentFeedResponseList) { + self.lastContinuation = documentFeedResponse.continuationToken(); + if (documentFeedResponse.results() != null && documentFeedResponse.results().size() > 0) { + self.dispatchChanges(documentFeedResponse); + } + + self.options.requestContinuation(self.lastContinuation); + + if (cancellationToken.isCancellationRequested()) { + // Observation was cancelled. + throw new TaskCancelledException(); + } + } + + if (this.options.maxItemCount().compareTo(this.settings.getMaxItemCount()) == 0) { + this.options.maxItemCount(this.settings.getMaxItemCount()); // Reset after successful execution. + } + } catch (RuntimeException ex) { + if (ex.getCause() instanceof CosmosClientException) { + + CosmosClientException clientException = (CosmosClientException) ex.getCause(); + // this.logger.WarnException("exception: partition '{0}'", clientException, this.properties.PartitionKeyRangeId); + StatusCodeErrorType docDbError = ExceptionClassifier.classifyClientException(clientException); + + switch (docDbError) { + case PARTITION_NOT_FOUND: { + self.resultException = new PartitionNotFoundException("Partition not found.", self.lastContinuation); + } + case PARTITION_SPLIT: { + self.resultException = new PartitionSplitException("Partition split.", self.lastContinuation); + } + case UNDEFINED: { + self.resultException = ex; + } + case MAX_ITEM_COUNT_TOO_LARGE: { + if (this.options.maxItemCount() == null) { + this.options.maxItemCount(DefaultMaxItemCount); + } else if (this.options.maxItemCount() <= 1) { + // this.logger.ErrorFormat("Cannot reduce maxItemCount further as it's already at {0}.", this.options.MaxItemCount); + throw ex; + } + + this.options.maxItemCount(this.options.maxItemCount() / 2); + // this.logger.WarnFormat("Reducing maxItemCount, new value: {0}.", this.options.MaxItemCount); + break; + } + default: { + // this.logger.Fatal($"Unrecognized DocDbError enum value {docDbError}"); + // Debug.Fail($"Unrecognized DocDbError enum value {docDbError}"); + self.resultException = ex; + } + } + } else if (ex instanceof TaskCancelledException) { + // this.logger.WarnException("exception: partition '{0}'", canceledException, this.properties.PartitionKeyRangeId); + self.resultException = ex; + } + } + + long remainingWork = delay.toMillis(); + + try { + while (!cancellationToken.isCancellationRequested() && remainingWork > 0) { + Thread.sleep(100); + remainingWork -= 100; + } + } catch (InterruptedException iex) { + // exception caught + } + } + }); + } + + @Override + public RuntimeException getResultException() { + return this.resultException; + } + + private void dispatchChanges(FeedResponse response) { + ChangeFeedObserverContext context = new ChangeFeedObserverContextImpl(this.settings.getPartitionKeyRangeId(), response, this.checkpointer); + + this.observer.processChanges(context, response.results()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorFactoryImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorFactoryImpl.java new file mode 100644 index 0000000000000..2f86448ca9e60 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorFactoryImpl.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.ChangeFeedProcessorOptions; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverFactory; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseManager; +import com.azure.data.cosmos.internal.changefeed.LeaseRenewer; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessor; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessorFactory; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisor; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisorFactory; + +import java.util.concurrent.ExecutorService; + +/** + * Implementation for the partition supervisor factory. + */ +class PartitionSupervisorFactoryImpl implements PartitionSupervisorFactory { + private final ChangeFeedObserverFactory observerFactory; + private final LeaseManager leaseManager; + private final ChangeFeedProcessorOptions changeFeedProcessorOptions; + private final PartitionProcessorFactory partitionProcessorFactory; + private final ExecutorService executorService; + + + public PartitionSupervisorFactoryImpl( + ChangeFeedObserverFactory observerFactory, + LeaseManager leaseManager, + PartitionProcessorFactory partitionProcessorFactory, + ChangeFeedProcessorOptions options, + ExecutorService executorService) { + if (observerFactory == null) throw new IllegalArgumentException("observerFactory"); + if (leaseManager == null) throw new IllegalArgumentException("leaseManager"); + if (options == null) throw new IllegalArgumentException("options"); + if (partitionProcessorFactory == null) throw new IllegalArgumentException("partitionProcessorFactory"); + + this.observerFactory = observerFactory; + this.leaseManager = leaseManager; + this.changeFeedProcessorOptions = options; + this.partitionProcessorFactory = partitionProcessorFactory; + this.executorService = executorService; + } + + @Override + public PartitionSupervisor create(Lease lease) { + if (lease == null) throw new IllegalArgumentException("lease"); + + ChangeFeedObserver changeFeedObserver = this.observerFactory.createObserver(); + PartitionProcessor processor = this.partitionProcessorFactory.create(lease, changeFeedObserver); + LeaseRenewer renewer = new LeaseRenewerImpl(lease, this.leaseManager, this.changeFeedProcessorOptions.leaseRenewInterval()); + + return new PartitionSupervisorImpl(lease, changeFeedObserver, processor, renewer, this.executorService); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorImpl.java new file mode 100644 index 0000000000000..e2945bef2f7db --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSupervisorImpl.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.CancellationToken; +import com.azure.data.cosmos.internal.changefeed.CancellationTokenSource; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserver; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverCloseReason; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedObserverContext; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseRenewer; +import com.azure.data.cosmos.internal.changefeed.PartitionProcessor; +import com.azure.data.cosmos.internal.changefeed.PartitionSupervisor; +import com.azure.data.cosmos.internal.changefeed.exceptions.LeaseLostException; +import com.azure.data.cosmos.internal.changefeed.exceptions.ObserverException; +import com.azure.data.cosmos.internal.changefeed.exceptions.PartitionSplitException; +import com.azure.data.cosmos.internal.changefeed.exceptions.TaskCancelledException; +import reactor.core.publisher.Mono; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Implementation for {@link PartitionSupervisor}. + */ +class PartitionSupervisorImpl implements PartitionSupervisor, Closeable { + private final Lease lease; + private final ChangeFeedObserver observer; + private final PartitionProcessor processor; + private final LeaseRenewer renewer; + private CancellationTokenSource renewerCancellation; + private CancellationTokenSource processorCancellation; + + private RuntimeException resultException; + + private ExecutorService executorService; + + public PartitionSupervisorImpl(Lease lease, ChangeFeedObserver observer, PartitionProcessor processor, LeaseRenewer renewer, ExecutorService executorService) { + this.lease = lease; + this.observer = observer; + this.processor = processor; + this.renewer = renewer; + this.executorService = executorService; + + if (executorService == null) { + this.executorService = Executors.newFixedThreadPool(3); + } + } + + @Override + public Mono run(CancellationToken shutdownToken) { + PartitionSupervisorImpl self = this; + this.resultException = null; + + ChangeFeedObserverContext context = new ChangeFeedObserverContextImpl(self.lease.getLeaseToken()); + + self.observer.open(context); + + ChangeFeedObserverCloseReason closeReason = ChangeFeedObserverCloseReason.UNKNOWN; + + try { + self.processorCancellation = new CancellationTokenSource(); + + Thread processorThread = new Thread(new Runnable() { + @Override + public void run() { + self.processor.run(self.processorCancellation.getToken()).block(); + } + }); + + self.renewerCancellation = new CancellationTokenSource(); + + Thread renewerThread = new Thread(new Runnable() { + @Override + public void run() { + self.renewer.run(self.renewerCancellation.getToken()).block(); + } + }); + + self.executorService.execute(processorThread); + self.executorService.execute(renewerThread); + + while (!shutdownToken.isCancellationRequested() && self.processor.getResultException() == null && self.renewer.getResultException() == null) { + try { + Thread.sleep(100); + } catch (InterruptedException iex) { + break; + } + } + + this.processorCancellation.cancel(); + this.renewerCancellation.cancel(); + + if (self.processor.getResultException() != null) { + throw self.processor.getResultException(); + } + + if (self.renewer.getResultException() != null) { + throw self.renewer.getResultException(); + } + + closeReason = shutdownToken.isCancellationRequested() ? + ChangeFeedObserverCloseReason.SHUTDOWN : + ChangeFeedObserverCloseReason.UNKNOWN; + + } catch (LeaseLostException llex) { + closeReason = ChangeFeedObserverCloseReason.LEASE_LOST; + self.resultException = llex; + } catch (PartitionSplitException pex) { + closeReason = ChangeFeedObserverCloseReason.LEASE_GONE; + self.resultException = pex; + } catch (TaskCancelledException tcex) { + closeReason = ChangeFeedObserverCloseReason.SHUTDOWN; + self.resultException = null; + } catch (ObserverException oex) { + closeReason = ChangeFeedObserverCloseReason.OBSERVER_ERROR; + self.resultException = oex; + } catch (Exception ex) { + closeReason = ChangeFeedObserverCloseReason.UNKNOWN; + } finally { + self.observer.close(context, closeReason); + } + + if (self.resultException != null) { + return Mono.error(self.resultException); + } else { + return Mono.empty(); + } + } + + @Override + public RuntimeException getResultException() { + return this.resultException; + } + + @Override + public void close() throws IOException { + if (this.processorCancellation != null) { + this.processorCancellation.close(); + } + + this.renewerCancellation.close(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSynchronizerImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSynchronizerImpl.java new file mode 100644 index 0000000000000..68c71488da960 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionSynchronizerImpl.java @@ -0,0 +1,174 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.LeaseContainer; +import com.azure.data.cosmos.internal.changefeed.LeaseManager; +import com.azure.data.cosmos.internal.changefeed.PartitionSynchronizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.HashSet; +import java.util.Set; + +import static com.azure.data.cosmos.BridgeInternal.extractContainerSelfLink; + +/** + * Implementation for the partition synchronizer. + */ +class PartitionSynchronizerImpl implements PartitionSynchronizer { + private final Logger logger = LoggerFactory.getLogger(PartitionSynchronizerImpl.class); + private final ChangeFeedContextClient documentClient; + private final CosmosContainer collectionSelfLink; + private final LeaseContainer leaseContainer; + private final LeaseManager leaseManager; + private final int degreeOfParallelism; + private final int maxBatchSize; + + public PartitionSynchronizerImpl( + ChangeFeedContextClient documentClient, + CosmosContainer collectionSelfLink, + LeaseContainer leaseContainer, + LeaseManager leaseManager, + int degreeOfParallelism, + int maxBatchSize) + { + this.documentClient = documentClient; + this.collectionSelfLink = collectionSelfLink; + this.leaseContainer = leaseContainer; + this.leaseManager = leaseManager; + this.degreeOfParallelism = degreeOfParallelism; + this.maxBatchSize = maxBatchSize; + } + + @Override + public Mono createMissingLeases() { + PartitionSynchronizerImpl self = this; + + return this.enumPartitionKeyRanges() + .map(partitionKeyRange -> { + // TODO: log the partition key ID found. + return partitionKeyRange.id(); + }) + .collectList() + .flatMap( partitionKeyRangeIds -> { + Set leaseTokens = new HashSet<>(partitionKeyRangeIds); + return self.createLeases(leaseTokens).then(); + }) + .onErrorResume( throwable -> { + // TODO: log the exception. + return Mono.empty(); + }); + } + + @Override + public Flux splitPartition(Lease lease) { + if (lease == null) throw new IllegalArgumentException("lease"); + + PartitionSynchronizerImpl self = this; + String leaseToken = lease.getLeaseToken(); + String lastContinuationToken = lease.getContinuationToken(); + + logger.info(String.format("Partition %s is gone due to split.", leaseToken)); + + // After a split, the children are either all or none available + return this.enumPartitionKeyRanges() + .filter(range -> range != null && range.getParents() != null && range.getParents().contains(leaseToken)) + .map(PartitionKeyRange::id) + .collectList() + .flatMapMany(addedLeaseTokens -> { + if (addedLeaseTokens.size() == 0) { + logger.error(String.format("Partition %s had split but we failed to find at least one child partition", leaseToken)); + throw new RuntimeException(String.format("Partition %s had split but we failed to find at least one child partition", leaseToken)); + } + return Flux.fromIterable(addedLeaseTokens); + }) + .flatMap(addedRangeId -> { + // Creating new lease. + return self.leaseManager.createLeaseIfNotExist(addedRangeId, lastContinuationToken); + }, self.degreeOfParallelism) + .map(newLease -> { + logger.info(String.format("Partition %s split into new partition with lease token %s.", leaseToken, newLease.getLeaseToken())); + return newLease; + }); + } + + private Flux enumPartitionKeyRanges() { + // STRING partitionKeyRangesPath = STRING.format("%spkranges", this.collectionSelfLink); + String partitionKeyRangesPath = extractContainerSelfLink(this.collectionSelfLink); + FeedOptions feedOptions = new FeedOptions(); + feedOptions.maxItemCount(this.maxBatchSize); + feedOptions.requestContinuation(null); + + return this.documentClient.readPartitionKeyRangeFeed(partitionKeyRangesPath, feedOptions) + .map(partitionKeyRangeFeedResponse -> partitionKeyRangeFeedResponse.results()) + .flatMap(partitionKeyRangeList -> Flux.fromIterable(partitionKeyRangeList)) + .onErrorResume(throwable -> { + // TODO: Log the exception. + return Flux.empty(); + }); + } + + /** + * Creates leases if they do not exist. This might happen on initial start or if some lease was unexpectedly lost. + *

    + * Leases are created without the continuation token. It means partitions will be read according to + * 'From Beginning' or 'From current time'. + * Same applies also to split partitions. We do not search for parent lease and take continuation token since this + * might end up of reprocessing all the events since the split. + * + * @param leaseTokens a hash set of all the lease tokens. + * @return a deferred computation of this call. + */ + private Flux createLeases(Set leaseTokens) + { + PartitionSynchronizerImpl self = this; + Set addedLeaseTokens = new HashSet<>(leaseTokens); + + return this.leaseContainer.getAllLeases() + .map(lease -> { + if (lease != null) { + // Get leases after getting ranges, to make sure that no other hosts checked in continuation for + // split partition after we got leases. + addedLeaseTokens.remove(lease.getLeaseToken()); + } + + return lease; + }) + .thenMany(Flux.fromIterable(addedLeaseTokens) + .flatMap( addedRangeId -> + self.leaseManager.createLeaseIfNotExist(addedRangeId, null), self.degreeOfParallelism) + .map( lease -> { + // TODO: log the lease info that was added. + return lease; + }) + ); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionedByIdCollectionRequestOptionsFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionedByIdCollectionRequestOptionsFactory.java new file mode 100644 index 0000000000000..c0fb1fcaf04c6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/PartitionedByIdCollectionRequestOptionsFactory.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.changefeed.Lease; +import com.azure.data.cosmos.internal.changefeed.RequestOptionsFactory; + +/** + * Used to create request options for partitioned lease collections, when partition key is defined as /id. + */ +class PartitionedByIdCollectionRequestOptionsFactory implements RequestOptionsFactory { + @Override + public CosmosItemRequestOptions createRequestOptions(Lease lease) { + CosmosItemRequestOptions requestOptions = new CosmosItemRequestOptions(); + requestOptions.partitionKey(new PartitionKey(lease.getId())); + + return requestOptions; + } + + @Override + public FeedOptions createFeedOptions() { + FeedOptions feedOptions = new FeedOptions(); + feedOptions.enableCrossPartitionQuery(true); + + return feedOptions; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingPartitionWorkImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingPartitionWorkImpl.java new file mode 100644 index 0000000000000..c770966f9d8cf --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingPartitionWorkImpl.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.RemainingPartitionWork; + +/** + * Implements the {@link RemainingPartitionWork} interface. + */ +class RemainingPartitionWorkImpl implements RemainingPartitionWork { + private final String partitionKeyRangeId; + private final long remainingWork; + + /** + * Initializes a new instance of the {@link RemainingPartitionWork} object. + * + * @param partitionKeyRangeId the partition key range ID for which the remaining work is calculated. + * @param remainingWork the amount of documents remaining to be processed. + */ + public RemainingPartitionWorkImpl(String partitionKeyRangeId, long remainingWork) { + if (partitionKeyRangeId == null || partitionKeyRangeId.isEmpty()) throw new IllegalArgumentException("partitionKeyRangeId"); + + this.partitionKeyRangeId = partitionKeyRangeId; + this.remainingWork = remainingWork; + } + + + @Override + public String getPartitionKeyRangeId() { + return this.partitionKeyRangeId; + } + + @Override + public long getRemainingWork() { + return this.remainingWork; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingWorkEstimatorImpl.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingWorkEstimatorImpl.java new file mode 100644 index 0000000000000..c92785af3911f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/RemainingWorkEstimatorImpl.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.ChangeFeedContextClient; +import com.azure.data.cosmos.internal.changefeed.LeaseContainer; +import com.azure.data.cosmos.internal.changefeed.RemainingPartitionWork; +import com.azure.data.cosmos.internal.changefeed.RemainingWorkEstimator; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Implementation for {@link RemainingWorkEstimator}. + */ +class RemainingWorkEstimatorImpl implements RemainingWorkEstimator { + private final char PKRangeIdSeparator = ':'; + private final char SegmentSeparator = '#'; + private final String LSNPropertyName = "_lsn"; + private final ChangeFeedContextClient feedDocumentClient; + private final LeaseContainer leaseContainer; + private final String collectionSelfLink; + private final int degreeOfParallelism; + + public RemainingWorkEstimatorImpl( + LeaseContainer leaseContainer, + ChangeFeedContextClient feedDocumentClient, + String collectionSelfLink, + int degreeOfParallelism) { + + if (leaseContainer == null) throw new IllegalArgumentException("leaseContainer"); + if (collectionSelfLink == null || collectionSelfLink.isEmpty()) throw new IllegalArgumentException("collectionSelfLink"); + if (feedDocumentClient == null) throw new IllegalArgumentException("feedDocumentClient"); + if (degreeOfParallelism < 1) throw new IllegalArgumentException("degreeOfParallelism - Degree of parallelism is out of range"); + + this.leaseContainer = leaseContainer; + this.collectionSelfLink = collectionSelfLink; + this.feedDocumentClient = feedDocumentClient; + this.degreeOfParallelism = degreeOfParallelism; + } + + @Override + public Mono estimatedRemainingWork() { + return this.estimatedRemainingWorkPerPartition() + .map(RemainingPartitionWork::getRemainingWork) + .collectList() + .map(list -> { + long sum; + if (list.size() == 0) { + sum = 1; + } else { + sum = 0; + for (long value : list) { + sum += value; + } + } + + return sum; + }); + } + + @Override + public Flux estimatedRemainingWorkPerPartition() { + return null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/StatusCodeErrorType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/StatusCodeErrorType.java new file mode 100644 index 0000000000000..51a5dfeba3607 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/StatusCodeErrorType.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +/** + * Groups types of status code errors returned while processing the change feeds. + */ +enum StatusCodeErrorType { + UNDEFINED, + PARTITION_NOT_FOUND, + PARTITION_SPLIT, + TRANSIENT_ERROR, + MAX_ITEM_COUNT_TOO_LARGE +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/TraceHealthMonitor.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/TraceHealthMonitor.java new file mode 100644 index 0000000000000..8ac8060bb709f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/TraceHealthMonitor.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.HealthMonitor; +import com.azure.data.cosmos.internal.changefeed.HealthMonitoringRecord; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +/** + * Implementation for trace health monitor. + */ +class TraceHealthMonitor implements HealthMonitor { + private final Logger logger = LoggerFactory.getLogger(TraceHealthMonitor.class); + @Override + public Mono inspect(HealthMonitoringRecord record) { + return Mono.fromRunnable(() -> { + if (record.getSeverity() == HealthMonitoringRecord.HealthSeverity.ERROR) { + logger.error(String.format("Unhealthiness detected in the operation %s for %s.", record.operation.name(), record.lease.getId()), record.throwable); + } + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/WorkerTask.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/WorkerTask.java new file mode 100644 index 0000000000000..be23b47ae7107 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/changefeed/implementation/WorkerTask.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.changefeed.implementation; + +import com.azure.data.cosmos.internal.changefeed.Lease; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Worker task that executes in a separate thread. + */ +class WorkerTask extends Thread { + private final Logger logger = LoggerFactory.getLogger(WorkerTask.class); + private boolean done = false; + private Runnable job; + private Lease lease; + + WorkerTask(Lease lease, Runnable job) { + this.lease = lease; + this.job = job; + } + + @Override + public void run() { + try { + job.run(); + logger.info("Partition controller worker task {} has finished running.", lease.getLeaseToken()); + } finally { + logger.info("Partition controller worker task {} has exited.", lease.getLeaseToken()); + job = null; + this.done = true; + } + } + + public Lease lease() { + return this.lease; + } + + public boolean isRunning() { + return !this.done; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Address.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Address.java new file mode 100644 index 0000000000000..bdfc3c190d4e8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Address.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.Constants; + +/** + * Used internally to represent a physical address in the Azure Cosmos DB database service. + */ +public class Address extends Resource { + /** + * Initialize an offer object. + */ + public Address() { + super(); + } + + /** + * Initialize an address object from json string. + * + * @param jsonString the json string that represents the address. + */ + public Address(String jsonString) { + super(jsonString); + } + + public boolean IsPrimary() { + return super.getBoolean(Constants.Properties.IS_PRIMARY); + } + + void setIsPrimary(boolean isPrimary) { + BridgeInternal.setProperty(this, Constants.Properties.IS_PRIMARY, isPrimary); + } + + public String getProtocolScheme() { + return super.getString(Constants.Properties.PROTOCOL); + } + + void setProtocol(String protocol) { + BridgeInternal.setProperty(this, Constants.Properties.PROTOCOL, protocol); + } + + public String getLogicalUri() { + return super.getString(Constants.Properties.LOGICAL_URI); + } + + void setLogicalUri(String logicalUri) { + BridgeInternal.setProperty(this, Constants.Properties.LOGICAL_URI, logicalUri); + } + + public String getPhyicalUri() { + return super.getString(Constants.Properties.PHYISCAL_URI); + } + + void setPhysicalUri(String phyicalUri) { + BridgeInternal.setProperty(this, Constants.Properties.PHYISCAL_URI, phyicalUri); + } + + public String getPartitionIndex() { + return super.getString(Constants.Properties.PARTITION_INDEX); + } + + void setPartitionIndex(String partitionIndex) { + BridgeInternal.setProperty(this, Constants.Properties.PARTITION_INDEX, partitionIndex); + } + + public String getParitionKeyRangeId() { + return super.getString(Constants.Properties.PARTITION_KEY_RANGE_ID); + } + + public void setPartitionKeyRangeId(String partitionKeyRangeId) { + BridgeInternal.setProperty(this, Constants.Properties.PARTITION_KEY_RANGE_ID, partitionKeyRangeId); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressInformation.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressInformation.java new file mode 100644 index 0000000000000..044832816380c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressInformation.java @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import java.util.Objects; + +/** + * Used internally to encapsulate a physical address information in the Azure Cosmos DB database service. + */ +public class AddressInformation { + private Protocol protocol; + private boolean isPublic; + private boolean isPrimary; + private String physicalUri; + + public AddressInformation(boolean isPublic, boolean isPrimary, String physicalUri, Protocol protocol) { + Objects.requireNonNull(protocol); + this.protocol = protocol; + this.isPublic = isPublic; + this.isPrimary = isPrimary; + this.physicalUri = physicalUri; + } + + public AddressInformation(boolean isPublic, boolean isPrimary, String physicalUri, String protocolScheme) { + this(isPublic, isPrimary, physicalUri, scheme2protocol(protocolScheme)); + } + + public boolean isPublic() { + return isPublic; + } + + public boolean isPrimary() { + return isPrimary; + } + + public String getPhysicalUri() { + return physicalUri; + } + + public Protocol getProtocol() { + return this.protocol; + } + + public String getProtocolName() { + return this.protocol.toString(); + } + + public String getProtocolScheme() { + return this.protocol.scheme(); + } + + @Override + public String toString() { + return "AddressInformation{" + + "protocol='" + protocol + '\'' + + ", isPublic=" + isPublic + + ", isPrimary=" + isPrimary + + ", physicalUri='" + physicalUri + '\'' + + '}'; + } + + private static Protocol scheme2protocol(String scheme) { + + Objects.requireNonNull(scheme, "scheme"); + + switch (scheme.toLowerCase()) { + case "https": + return Protocol.HTTPS; + case "rntbd": + return Protocol.TCP; + default: + throw new IllegalArgumentException(String.format("scheme: %s", scheme)); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolver.java new file mode 100644 index 0000000000000..d02517152cded --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolver.java @@ -0,0 +1,706 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.ICollectionRoutingMapCache; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceId; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * Abstracts out the logic to resolve physical replica addresses for the given {@link RxDocumentServiceRequest} + *

    + * AddressCache internally maintains CollectionCache, CollectionRoutingMapCache and BackendAddressCache. + * Logic in this class mainly joins these 3 caches and deals with potential staleness of the caches. + */ +public class AddressResolver implements IAddressResolver { + private static Logger logger = LoggerFactory.getLogger(AddressResolver.class); + + private final static PartitionKeyRangeIdentity masterPartitionKeyRangeIdentity = + new PartitionKeyRangeIdentity(PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID); + + private RxCollectionCache collectionCache; + private ICollectionRoutingMapCache collectionRoutingMapCache; + private IAddressCache addressCache; + + public AddressResolver() { + } + + public void initializeCaches( + RxCollectionCache collectionCache, + ICollectionRoutingMapCache collectionRoutingMapCache, + IAddressCache addressCache) { + this.collectionCache = collectionCache; + this.addressCache = addressCache; + this.collectionRoutingMapCache = collectionRoutingMapCache; + } + + public Mono resolveAsync( + RxDocumentServiceRequest request, + boolean forceRefreshPartitionAddresses) { + + Mono resultObs = this.resolveAddressesAndIdentityAsync(request, forceRefreshPartitionAddresses); + + return resultObs.flatMap(result -> { + + try { + this.throwIfTargetChanged(request, result.TargetPartitionKeyRange); + } catch (Exception e) { + return Mono.error(e); + } + + request.requestContext.resolvedPartitionKeyRange = result.TargetPartitionKeyRange; + + return Mono.just(result.Addresses); + }); + } + + private static boolean isSameCollection(PartitionKeyRange initiallyResolved, PartitionKeyRange newlyResolved) { + if (initiallyResolved == null) { + throw new IllegalArgumentException("parent"); + } + + if (newlyResolved == null) { + return false; + } + + if (Strings.areEqual(initiallyResolved.id(), PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID) && + Strings.areEqual(newlyResolved.id(), PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID)) { + return true; + } + + if (Strings.areEqual(initiallyResolved.id(), PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID) + || Strings.areEqual(newlyResolved.id(), PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID)) { + String message = + "Request was resolved to master partition and then to server partition."; + assert false : message; + logger.warn(message); + return false; + } + + if (ResourceId.parse(initiallyResolved.resourceId()).getDocumentCollection() + != ResourceId.parse(newlyResolved.resourceId()).getDocumentCollection()) { + return false; + } + + if (!Strings.areEqual(initiallyResolved.id(), newlyResolved.id()) && + !(newlyResolved.getParents() != null && newlyResolved.getParents().contains(initiallyResolved.id()))) { + // the above condition should be always false in current codebase. + // We don't need to refresh any caches if we resolved to a range which is child of previously resolved range. + // Quorum reads should be handled transparently as child partitions share LSNs with parent partitions which are gone. + String message = + "Request is targeted at a partition key range which is not child of previously targeted range."; + assert false : message; + logger.warn(message); + + return false; + } + + return true; + } + + /** + * Validates if the target partition to which the request is being sent has changed during retry. + *

    + * If that happens, the request is no more valid and need to be retried. + * + * @param request Request in progress + * @param targetRange Target partition key range determined by address resolver + * @*/ + private void throwIfTargetChanged(RxDocumentServiceRequest request, PartitionKeyRange targetRange) throws CosmosClientException { + // If new range is child of previous range, we don't need to throw any exceptions + // as LSNs are continued on child ranges. + if (request.requestContext.resolvedPartitionKeyRange != null && + !isSameCollection(request.requestContext.resolvedPartitionKeyRange, targetRange)) { + if (!request.getIsNameBased()) { + String message = String.format( + "Target should not change for non name based requests. Previous target {}, Current {}", + request.requestContext.resolvedPartitionKeyRange, targetRange); + assert false : message; + logger.warn(message); + } + + request.requestContext.resolvedPartitionKeyRange = null; + throw new InvalidPartitionException(RMResources.InvalidTarget, request.getResourceAddress()); + } + } + + private static void ensureRoutingMapPresent( + RxDocumentServiceRequest request, + CollectionRoutingMap routingMap, + DocumentCollection collection) throws CosmosClientException { + if (routingMap == null && request.getIsNameBased() && request.getPartitionKeyRangeIdentity() != null + && request.getPartitionKeyRangeIdentity().getCollectionRid() != null) { + // By design, if partitionkeyrangeid header is present and it contains collectionrid for collection + // which doesn't exist, we return InvalidPartitionException. Backend does the same. + // Caller (client SDK or whoever attached the header) supposedly has outdated collection cache and will refresh it. + // We cannot retry here, as the logic for retry in this case is use-case specific. + logger.debug( + "Routing map for request with partitionkeyrageid {} was not found", + request.getPartitionKeyRangeIdentity().toHeader()); + + InvalidPartitionException invalidPartitionException = new InvalidPartitionException(); + BridgeInternal.setResourceAddress(invalidPartitionException, request.getResourceAddress()); + throw invalidPartitionException; + } + + if (routingMap == null) { + logger.debug( + "Routing map was not found although collection cache is upto date for collection {}", + collection.resourceId()); + // Routing map not found although collection was resolved correctly. + NotFoundException e = new NotFoundException(); + BridgeInternal.setResourceAddress(e, request.getResourceAddress()); + throw e; + } + } + + private Mono tryResolveServerPartitionAsync( + RxDocumentServiceRequest request, + DocumentCollection collection, + CollectionRoutingMap routingMap, + boolean collectionCacheIsUptodate, + boolean collectionRoutingMapCacheIsUptodate, + boolean forceRefreshPartitionAddresses) { + + try { + // Check if this request partitionkeyrange-aware routing logic. We cannot retry here in this case + // and need to bubble up errors. + if (request.getPartitionKeyRangeIdentity() != null) { + return this.tryResolveServerPartitionByPartitionKeyRangeIdAsync( + request, + collection, + routingMap, + collectionCacheIsUptodate, + collectionRoutingMapCacheIsUptodate, + forceRefreshPartitionAddresses); + } + + if (!request.getResourceType().isPartitioned() && + !(request.getResourceType() == ResourceType.StoredProcedure && request.getOperationType() == OperationType.ExecuteJavaScript) && + // Collection head is sent internally for strong consistency given routing hints from original requst, which is for partitioned resource. + !(request.getResourceType() == ResourceType.DocumentCollection && request.getOperationType() == OperationType.Head)) { + logger.error( + "Shouldn't come here for non partitioned resources. resourceType : {}, operationtype:{}, resourceaddress:{}", + request.getResourceType(), + request.getOperationType(), + request.getResourceAddress()); + return Mono.error(BridgeInternal.setResourceAddress(new InternalServerErrorException(RMResources.InternalServerError), request.getResourceAddress())); + } + + PartitionKeyRange range; + String partitionKeyString = request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY); + + if (partitionKeyString != null) { + range = this.tryResolveServerPartitionByPartitionKey( + request, + partitionKeyString, + collectionCacheIsUptodate, + collection, + routingMap); + } else { + range = this.tryResolveSinglePartitionCollection(request, routingMap, collectionCacheIsUptodate); + } + + if (range == null) { + // Collection cache or routing map cache is potentially outdated. Return empty - + // upper logic will refresh cache and retry. + return Mono.empty(); + } + + Mono addressesObs = this.addressCache.tryGetAddresses( + request, + new PartitionKeyRangeIdentity(collection.resourceId(), range.id()), + forceRefreshPartitionAddresses); + + return addressesObs.flatMap(addresses -> Mono.just(new ResolutionResult(range, addresses))).switchIfEmpty(Mono.defer(() -> { + logger.info( + "Could not resolve addresses for identity {}/{}. Potentially collection cache or routing map cache is outdated. Return empty - upper logic will refresh and retry. ", + new PartitionKeyRangeIdentity(collection.resourceId(), range.id())); + return Mono.empty(); + })); + + } catch (Exception e) { + return Mono.error(e); + } + } + + private PartitionKeyRange tryResolveSinglePartitionCollection( + RxDocumentServiceRequest request, + CollectionRoutingMap routingMap, + boolean collectionCacheIsUptoDate) throws CosmosClientException { + // Neither partitionkey nor partitionkeyrangeid is specified. + // Three options here: + // * This is non-partitioned collection and old client SDK which doesn't send partition key. In + // this case there's single entry in routing map. But can be multiple entries if before that + // existed partitioned collection with same name. + // * This is partitioned collection and old client SDK which doesn't send partition key. + // In this case there can be multiple ranges in routing map. + // * This is partitioned collection and this is custom written REST sdk, which has a bug and doesn't send + // partition key. + // We cannot know for sure whether this is partitioned collection or not, because + // partition key definition cache can be outdated. + // So we route request to the first partition. If this is non-partitioned collection - request will succeed. + // If it is partitioned collection - backend will return bad request as partition key header is required in this case. + if (routingMap.getOrderedPartitionKeyRanges().size() == 1) { + return routingMap.getOrderedPartitionKeyRanges().get(0); + } + + if (collectionCacheIsUptoDate) { + throw BridgeInternal.setResourceAddress(new BadRequestException(RMResources.MissingPartitionKeyValue), request.getResourceAddress()); + } else { + return null; + } + } + + private Mono resolveMasterResourceAddress(RxDocumentServiceRequest request, + boolean forceRefreshPartitionAddresses) { + assert ReplicatedResourceClient.isReadingFromMaster(request.getResourceType(), request.getOperationType()) + && request.getPartitionKeyRangeIdentity() == null; + + // ServiceIdentity serviceIdentity = this.masterServiceIdentity; + Mono addressesObs = this.addressCache.tryGetAddresses(request, + masterPartitionKeyRangeIdentity,forceRefreshPartitionAddresses); + + return addressesObs.flatMap(addresses -> { + PartitionKeyRange partitionKeyRange = new PartitionKeyRange(); + partitionKeyRange.id(PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID); + return Mono.just(new ResolutionResult(partitionKeyRange, addresses)); + }).switchIfEmpty(Mono.defer(() -> { + logger.warn("Could not get addresses for master partition"); + + // return Observable.error() + NotFoundException e = new NotFoundException(); + BridgeInternal.setResourceAddress(e, request.getResourceAddress()); + return Mono.error(e); + })); + } + + private class RefreshState { + + volatile boolean collectionCacheIsUptoDate; + volatile boolean collectionRoutingMapCacheIsUptoDate; + volatile DocumentCollection collection; + volatile CollectionRoutingMap routingMap; + volatile ResolutionResult resolutionResult; + } + + private Mono getOrRefreshRoutingMap(RxDocumentServiceRequest request, boolean forceRefreshPartitionAddresses) { + + RefreshState state = new RefreshState(); + + state.collectionCacheIsUptoDate = !request.getIsNameBased() || + (request.getPartitionKeyRangeIdentity() != null && request.getPartitionKeyRangeIdentity().getCollectionRid() != null); + state.collectionRoutingMapCacheIsUptoDate = false; + + Mono collectionObs = this.collectionCache.resolveCollectionAsync(request); + + Mono stateObs = collectionObs.flatMap(collection -> { + state.collection = collection; + Mono routingMapObs = + this.collectionRoutingMapCache.tryLookupAsync(collection.resourceId(), null, request.forceCollectionRoutingMapRefresh, request.properties); + final DocumentCollection underlyingCollection = collection; + return routingMapObs.flatMap(routingMap -> { + state.routingMap = routingMap; + + if (request.forcePartitionKeyRangeRefresh) { + state.collectionRoutingMapCacheIsUptoDate = true; + request.forcePartitionKeyRangeRefresh = false; + if (routingMap != null) { + return this.collectionRoutingMapCache.tryLookupAsync(underlyingCollection.resourceId(), routingMap, request.properties) + .map(newRoutingMap -> { + state.routingMap = newRoutingMap; + return state; + }); + } + } + + return Mono.just(state); + }).switchIfEmpty(Mono.defer(() -> { + if (request.forcePartitionKeyRangeRefresh) { + state.collectionRoutingMapCacheIsUptoDate = true; + request.forcePartitionKeyRangeRefresh = false; + } + return Mono.just(state); + })); + }); + + return stateObs.flatMap(newState -> { + + if (newState.routingMap == null && !newState.collectionCacheIsUptoDate) { + // Routing map was not found by resolved collection rid. Maybe collection rid is outdated. + // Refresh collection cache and reresolve routing map. + request.forceNameCacheRefresh = true; + newState.collectionCacheIsUptoDate = true; + newState.collectionRoutingMapCacheIsUptoDate = false; + + Mono newCollectionObs = this.collectionCache.resolveCollectionAsync(request); + + return newCollectionObs.flatMap(collection -> { + newState.collection = collection; + Mono newRoutingMapObs = this.collectionRoutingMapCache.tryLookupAsync( + collection.resourceId(), + null, + request.properties); + + return newRoutingMapObs.map(routingMap -> { + newState.routingMap = routingMap; + return newState; + }); + } + ); + + } + + return Mono.just(newState); + }); + } + + private Mono getStateWithNewRoutingMap(RefreshState state, Mono routingMapSingle) { + return routingMapSingle.map(r -> { + state.routingMap = r; + return state; + }).switchIfEmpty(Mono.fromSupplier(() -> { + state.routingMap = null; + return state; + })); + } + + /** + * Resolves the endpoint of the partition for the given request + * + * @param request Request for which the partition endpoint resolution is to be performed + * @param forceRefreshPartitionAddresses Force refresh the partition's endpoint + * @return ResolutionResult + */ + private Mono resolveAddressesAndIdentityAsync( + RxDocumentServiceRequest request, + boolean forceRefreshPartitionAddresses) { + + if (ReplicatedResourceClient.isReadingFromMaster(request.getResourceType(), request.getOperationType()) + && request.getPartitionKeyRangeIdentity() == null) { + return resolveMasterResourceAddress(request, forceRefreshPartitionAddresses); + } + + Mono refreshStateObs = this.getOrRefreshRoutingMap(request, forceRefreshPartitionAddresses); + + return refreshStateObs.flatMap( + state -> { + try { + AddressResolver.ensureRoutingMapPresent(request, state.routingMap, state.collection); + + } catch (Exception e) { + return Mono.error(e); + } + + // At this point we have both collection and routingMap. + Mono resultObs = this.tryResolveServerPartitionAsync( + request, + state.collection, + state.routingMap, + state.collectionCacheIsUptoDate, + state.collectionRoutingMapCacheIsUptoDate, + forceRefreshPartitionAddresses); + + + Function> addCollectionRidIfNameBased = funcResolutionResult -> { + assert funcResolutionResult != null; + if (request.getIsNameBased()) { + // Append collection rid. + // If we resolved collection rid incorrectly because of outdated cache, this can lead + // to incorrect routing decisions. But backend will validate collection rid and throw + // InvalidPartitionException if we reach wrong collection. + // Also this header will be used by backend to inject collection rid into metrics for + // throttled requests. + request.getHeaders().put(WFConstants.BackendHeaders.COLLECTION_RID, state.collection.resourceId()); + } + + return Mono.just(funcResolutionResult); + }; + + return resultObs.flatMap(addCollectionRidIfNameBased).switchIfEmpty(Mono.defer(() -> { + // result is empty + + Function> ensureCollectionRoutingMapCacheIsUptoDateFunc = funcState -> { + if (!funcState.collectionRoutingMapCacheIsUptoDate) { + funcState.collectionRoutingMapCacheIsUptoDate = true; + Mono newRoutingMapObs = this.collectionRoutingMapCache.tryLookupAsync( + funcState.collection.resourceId(), + funcState.routingMap, + request.properties); + + return getStateWithNewRoutingMap(funcState, newRoutingMapObs); + } else { + return Mono.just(state); + } + }; + + Function> resolveServerPartition = funcState -> { + + try { + AddressResolver.ensureRoutingMapPresent(request, funcState.routingMap, funcState.collection); + } catch (Exception e) { + return Mono.error(e); + } + + return this.tryResolveServerPartitionAsync( + request, + funcState.collection, + funcState.routingMap, + true, + true, + forceRefreshPartitionAddresses); + }; + + Function> onNullThrowNotFound = funcResolutionResult -> { + if (funcResolutionResult == null) { + logger.debug("Couldn't route partitionkeyrange-oblivious request after retry/cache refresh. Collection doesn't exist."); + + // At this point collection cache and routing map caches are refreshed. + // The only reason we will get here is if collection doesn't exist. + // Case when partition-key-range doesn't exist is handled in the corresponding method. + + return Mono.error(BridgeInternal.setResourceAddress(new NotFoundException(), request.getResourceAddress())); + } + + return Mono.just(funcResolutionResult); + }; + + // Couldn't resolve server partition or its addresses. + // Either collection cache is outdated or routing map cache is outdated. + if (!state.collectionCacheIsUptoDate) { + request.forceNameCacheRefresh = true; + state.collectionCacheIsUptoDate = true; + + Mono newCollectionObs = this.collectionCache.resolveCollectionAsync(request); + Mono newRefreshStateObs = newCollectionObs.flatMap(collection -> { + state.collection = collection; + + if (collection.resourceId() != state.routingMap.getCollectionUniqueId()) { + // Collection cache was stale. We resolved to new Rid. routing map cache is potentially stale + // for this new collection rid. Mark it as such. + state.collectionRoutingMapCacheIsUptoDate = false; + Mono newRoutingMap = this.collectionRoutingMapCache.tryLookupAsync( + collection.resourceId(), + null, + request.properties); + + return getStateWithNewRoutingMap(state, newRoutingMap); + } + + return Mono.just(state); + }); + + Mono newResultObs = newRefreshStateObs.flatMap(ensureCollectionRoutingMapCacheIsUptoDateFunc) + .flatMap(resolveServerPartition); + + return newResultObs.flatMap(onNullThrowNotFound).flatMap(addCollectionRidIfNameBased); + + } else { + return ensureCollectionRoutingMapCacheIsUptoDateFunc.apply(state) + .flatMap(resolveServerPartition) + .flatMap(onNullThrowNotFound) + .flatMap(addCollectionRidIfNameBased); + } + })); + } + ); + } + + private ResolutionResult handleRangeAddressResolutionFailure( + RxDocumentServiceRequest request, + boolean collectionCacheIsUpToDate, + boolean routingMapCacheIsUpToDate, + CollectionRoutingMap routingMap) throws CosmosClientException { + // Optimization to not refresh routing map unnecessary. As we keep track of parent child relationships, + // we can determine that a range is gone just by looking up in the routing map. + if (collectionCacheIsUpToDate && routingMapCacheIsUpToDate || + collectionCacheIsUpToDate && routingMap.IsGone(request.getPartitionKeyRangeIdentity().getPartitionKeyRangeId())) { + String errorMessage = String.format( + RMResources.PartitionKeyRangeNotFound, + request.getPartitionKeyRangeIdentity().getPartitionKeyRangeId(), + request.getPartitionKeyRangeIdentity().getCollectionRid()); + throw BridgeInternal.setResourceAddress(new PartitionKeyRangeGoneException(errorMessage), request.getResourceAddress()); + } + + return null; + } + + private Mono returnOrError(Callable function) { + try { + return Mono.justOrEmpty(function.call()); + } catch (Exception e) { + return Mono.error(e); + } + } + + private Mono tryResolveServerPartitionByPartitionKeyRangeIdAsync( + RxDocumentServiceRequest request, + DocumentCollection collection, + CollectionRoutingMap routingMap, + boolean collectionCacheIsUpToDate, + boolean routingMapCacheIsUpToDate, + boolean forceRefreshPartitionAddresses) { + + PartitionKeyRange partitionKeyRange = routingMap.getRangeByPartitionKeyRangeId(request.getPartitionKeyRangeIdentity().getPartitionKeyRangeId()); + if (partitionKeyRange == null) { + logger.debug("Cannot resolve range '{}'", request.getPartitionKeyRangeIdentity().toHeader()); + return returnOrError(() -> this.handleRangeAddressResolutionFailure(request, collectionCacheIsUpToDate, routingMapCacheIsUpToDate, routingMap)); + } + + Mono addressesObs = this.addressCache.tryGetAddresses( + request, + new PartitionKeyRangeIdentity(collection.resourceId(), request.getPartitionKeyRangeIdentity().getPartitionKeyRangeId()), + forceRefreshPartitionAddresses); + + return addressesObs.flatMap(addresses -> Mono.just(new ResolutionResult(partitionKeyRange, addresses))).switchIfEmpty(Mono.defer(() -> { + logger.debug("Cannot resolve addresses for range '{}'", request.getPartitionKeyRangeIdentity().toHeader()); + + try { + return Mono.justOrEmpty(this.handleRangeAddressResolutionFailure(request, collectionCacheIsUpToDate, routingMapCacheIsUpToDate, routingMap)); + } catch (CosmosClientException e) { + return Mono.error(e); + } + })); + } + + private PartitionKeyRange tryResolveServerPartitionByPartitionKey( + RxDocumentServiceRequest request, + String partitionKeyString, + boolean collectionCacheUptoDate, + DocumentCollection collection, + CollectionRoutingMap routingMap) throws CosmosClientException { + if (request == null) { + throw new NullPointerException("request"); + } + + if (partitionKeyString == null) { + throw new NullPointerException("partitionKeyString"); + } + + if (collection == null) { + throw new NullPointerException("collection"); + } + + if (routingMap == null) { + throw new NullPointerException("routingMap"); + } + + PartitionKeyInternal partitionKey; + + try { + partitionKey = PartitionKeyInternal.fromJsonString(partitionKeyString); + } catch (Exception ex) { + throw BridgeInternal.setResourceAddress(new BadRequestException( + String.format(RMResources.InvalidPartitionKey, partitionKeyString), + ex), request.getResourceAddress()); + } + + if (partitionKey == null) { + throw new InternalServerErrorException(String.format("partition key is null '%s'", partitionKeyString)); + } + + if (partitionKey.equals(PartitionKeyInternal.Empty) || partitionKey.getComponents().size() == collection.getPartitionKey().paths().size()) { + // Although we can compute effective partition key here, in general case this GATEWAY can have outdated + // partition key definition cached - like if collection with same name but with RANGE partitioning is created. + // In this case server will not pass x-ms-documentdb-collection-rid check and will return back InvalidPartitionException. + // GATEWAY will refresh its cache and retry. + String effectivePartitionKey = PartitionKeyInternalHelper.getEffectivePartitionKeyString(partitionKey, collection.getPartitionKey()); + + // There should be exactly one range which contains a partition key. Always. + return routingMap.getRangeByEffectivePartitionKey(effectivePartitionKey); + } + + if (collectionCacheUptoDate) { + BadRequestException badRequestException = BridgeInternal.setResourceAddress(new BadRequestException(RMResources.PartitionKeyMismatch), request.getResourceAddress()); + badRequestException.responseHeaders().put(WFConstants.BackendHeaders.SUB_STATUS, Integer.toString(HttpConstants.SubStatusCodes.PARTITION_KEY_MISMATCH)); + + throw badRequestException; + } + + // Partition key supplied has different number paths than locally cached partition key definition. + // Three things can happen: + // 1. User supplied wrong partition key. + // 2. Client SDK has outdated partition key definition cache and extracted wrong value from the document. + // 3. GATEWAY's cache is outdated. + // + // What we will do is append x-ms-documentdb-collection-rid header and forward it to random collection partition. + // * If collection rid matches, server will send back 400.1001, because it also will not be able to compute + // effective partition key. GATEWAY will forward this status code to client - client will handle it. + // * If collection rid doesn't match, server will send back InvalidPartiitonException and GATEWAY will + // refresh name routing cache - this will refresh partition key definition as well, and retry. + + logger.debug( + "Cannot compute effective partition key. Definition has '{}' paths, values supplied has '{}' paths. Will refresh cache and retry.", + collection.getPartitionKey().paths().size(), + partitionKey.getComponents().size()); + + return null; + } + + private class ResolutionResult { + final PartitionKeyRange TargetPartitionKeyRange; + final AddressInformation[] Addresses; + + ResolutionResult( + PartitionKeyRange targetPartitionKeyRange, + AddressInformation[] addresses) { + if (targetPartitionKeyRange == null) { + throw new NullPointerException("targetPartitionKeyRange"); + } + + if (addresses == null) { + throw new NullPointerException("addresses"); + } + + this.TargetPartitionKeyRange = targetPartitionKeyRange; + this.Addresses = addresses; + } + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelector.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelector.java new file mode 100644 index 0000000000000..05c72415d6671 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelector.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class AddressSelector { + private final IAddressResolver addressResolver; + private final Protocol protocol; + + public AddressSelector(IAddressResolver addressResolver, Protocol protocol) { + this.addressResolver = addressResolver; + this.protocol = protocol; + } + + public Mono> resolveAllUriAsync( + RxDocumentServiceRequest request, + boolean includePrimary, + boolean forceRefresh) { + Mono> allReplicaAddressesObs = this.resolveAddressesAsync(request, forceRefresh); + return allReplicaAddressesObs.map(allReplicaAddresses -> allReplicaAddresses.stream().filter(a -> includePrimary || !a.isPrimary()) + .map(a -> HttpUtils.toURI(a.getPhysicalUri())).collect(Collectors.toList())); + } + + public Mono resolvePrimaryUriAsync(RxDocumentServiceRequest request, boolean forceAddressRefresh) { + Mono> replicaAddressesObs = this.resolveAddressesAsync(request, forceAddressRefresh); + return replicaAddressesObs.flatMap(replicaAddresses -> { + try { + return Mono.just(AddressSelector.getPrimaryUri(request, replicaAddresses)); + } catch (Exception e) { + return Mono.error(e); + } + }); + } + + public static URI getPrimaryUri(RxDocumentServiceRequest request, List replicaAddresses) throws GoneException { + AddressInformation primaryAddress = null; + + if (request.getDefaultReplicaIndex() != null) { + int defaultReplicaIndex = request.getDefaultReplicaIndex(); + if (defaultReplicaIndex >= 0 && defaultReplicaIndex < replicaAddresses.size()) { + primaryAddress = replicaAddresses.get(defaultReplicaIndex); + } + } else { + primaryAddress = replicaAddresses.stream().filter(address -> address.isPrimary() && !address.getPhysicalUri().contains("[")) + .findAny().orElse(null); + } + + if (primaryAddress == null) { + // Primary endpoint (of the desired protocol) was not found. + throw new GoneException(String.format("The requested resource is no longer available at the server. Returned addresses are {%s}", + replicaAddresses.stream().map(AddressInformation::getPhysicalUri).collect(Collectors.joining(","))), null); + } + + return HttpUtils.toURI(primaryAddress.getPhysicalUri()); + } + + public Mono> resolveAddressesAsync(RxDocumentServiceRequest request, boolean forceAddressRefresh) { + Mono> resolvedAddressesObs = + (this.addressResolver.resolveAsync(request, forceAddressRefresh)) + .map(addresses -> Arrays.stream(addresses) + .filter(address -> !Strings.isNullOrEmpty(address.getPhysicalUri()) && Strings.areEqualIgnoreCase(address.getProtocolScheme(), this.protocol.scheme())) + .collect(Collectors.toList())); + + return resolvedAddressesObs.map( + resolvedAddresses -> { + List r = resolvedAddresses.stream().filter(address -> !address.isPublic()).collect(Collectors.toList()); + if (r.size() > 0) { + return r; + } else { + return resolvedAddresses.stream().filter(AddressInformation::isPublic).collect(Collectors.toList()); + } + } + ); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelper.java new file mode 100644 index 0000000000000..2eca282760cfd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelper.java @@ -0,0 +1,168 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.internal.AuthorizationTokenType; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceId; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.Exceptions; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class BarrierRequestHelper { + private final static Logger logger = LoggerFactory.getLogger(BarrierRequestHelper.class); + + public static Mono createAsync( + RxDocumentServiceRequest request, + IAuthorizationTokenProvider authorizationTokenProvider, + Long targetLsn, + Long targetGlobalCommittedLsn) { + + boolean isCollectionHeadRequest = BarrierRequestHelper.isCollectionHeadBarrierRequest( + request.getResourceType(), + request.getOperationType()); + + AuthorizationTokenType originalRequestTokenType = request.authorizationTokenType; + + if (originalRequestTokenType == AuthorizationTokenType.Invalid) { + String message = "AuthorizationTokenType not set for the read request"; + assert false : message; + logger.error(message); + } + + String authorizationToken = Strings.Emtpy; + RxDocumentServiceRequest barrierLsnRequest = null; + if (!isCollectionHeadRequest) { + // DB Feed + barrierLsnRequest = RxDocumentServiceRequest.create( + OperationType.HeadFeed, + (String) null, + (ResourceType) ResourceType.Database, + (Map) null); + } else if (request.getIsNameBased()) { + // Name based server request + + // get the collection full name + // dbs/{id}/colls/{collid}/ + String collectionLink = PathsHelper.getCollectionPath(request.getResourceAddress()); + barrierLsnRequest = RxDocumentServiceRequest.createFromName( + OperationType.Head, + collectionLink, + ResourceType.DocumentCollection); + } else { + // RID based Server request + barrierLsnRequest = RxDocumentServiceRequest.create( + OperationType.Head, + ResourceId.parse(request.getResourceId()).getDocumentCollectionId().toString(), + ResourceType.DocumentCollection, null); + } + + barrierLsnRequest.getHeaders().put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + + if (targetLsn != null && targetLsn > 0) { + barrierLsnRequest.getHeaders().put(HttpConstants.HttpHeaders.TARGET_LSN, targetLsn.toString()); + } + + if (targetGlobalCommittedLsn != null && targetGlobalCommittedLsn > 0) { + barrierLsnRequest.getHeaders().put(HttpConstants.HttpHeaders.TARGET_GLOBAL_COMMITTED_LSN, targetGlobalCommittedLsn.toString()); + } + + switch (originalRequestTokenType) { + case PrimaryMasterKey: + case PrimaryReadonlyMasterKey: + case SecondaryMasterKey: + case SecondaryReadonlyMasterKey: + authorizationToken = authorizationTokenProvider.getUserAuthorizationToken( + barrierLsnRequest.getResourceAddress(), + isCollectionHeadRequest ? ResourceType.DocumentCollection : ResourceType.Database, + HttpConstants.HttpMethods.HEAD, + barrierLsnRequest.getHeaders(), + originalRequestTokenType, + request.properties); + break; + + + case ResourceToken: + authorizationToken = request.getHeaders().get(HttpConstants.HttpHeaders.AUTHORIZATION); + break; + + default: + String unknownAuthToken = "Unknown authorization token kind for read request"; + assert false : unknownAuthToken; + logger.error(unknownAuthToken); + throw Exceptions.propagate(new InternalServerErrorException(RMResources.InternalServerError)); + } + + barrierLsnRequest.getHeaders().put(HttpConstants.HttpHeaders.AUTHORIZATION, authorizationToken); + barrierLsnRequest.requestContext = request.requestContext.clone(); + + if (request.getPartitionKeyRangeIdentity() != null) { + barrierLsnRequest.routeTo(request.getPartitionKeyRangeIdentity()); + } + if (request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY) != null) { + barrierLsnRequest.getHeaders().put(HttpConstants.HttpHeaders.PARTITION_KEY, request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)); + } + if (request.getHeaders().get(WFConstants.BackendHeaders.COLLECTION_RID) != null) { + barrierLsnRequest.getHeaders().put(WFConstants.BackendHeaders.COLLECTION_RID, request.getHeaders().get(WFConstants.BackendHeaders.COLLECTION_RID)); + } + + return Mono.just(barrierLsnRequest); + } + + static boolean isCollectionHeadBarrierRequest(ResourceType resourceType, OperationType operationType) { + switch (resourceType) { + case Attachment: + case Document: + case Conflict: + case StoredProcedure: + case UserDefinedFunction: + case Trigger: + return true; + case DocumentCollection: + if (operationType != OperationType.ReadFeed && operationType != OperationType.Query && operationType != OperationType.SqlQuery) { + return true; + } else { + return false; + } + case PartitionKeyRange: + // no logic for OperationType.GetSplitPoint and OperationType.AbortSplit + // as they are not applicable to SDK + return false; + default: + return false; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReader.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReader.java new file mode 100644 index 0000000000000..3ddf572d09643 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReader.java @@ -0,0 +1,426 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.ISessionToken; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.List; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; + +/* + ConsistencyLevel Replication Mode Desired ReadMode + ------------------- -------------------- --------------------------------------------------------------------------- + STRONG Synchronous READ from READ Quorum + Asynchronous Not supported + + Bounded Staleness Synchronous READ from READ Quorum + Asynchronous READ from READ Quorum. Performing read barrier on Primary is unsupported. + + SESSION Sync/Async READ Any (With LSN Cookie) + DEFAULT to Primary as last resort (which should succeed always) + + EVENTUAL Sync/Async READ Any + + Client does validation of unsupported combinations. + + + Preliminaries + ============= + 1. We do primary copy/single master replication. + 2. We do sync or async replication depending on the value of DefaultConsistencyLevel on a database account. + If the database account is configured with DefaultConsistencyLevel = STRONG, we do sync replication. By default, for all other values of DefaultConsistencyLevel, we do asynchronous replication. + + Replica set + =========== + We define N as the current number of replicas protecting a partition. + At any given point, the value of N can fluctuate between NMax and NMin. + NMax is called the target replica set size and NMin is called the minimum write availability set size. + NMin and NMax are statically defined whereas N is dynamic. + Dynamic replica set is great for dealing with successive failures. + Since N fluctuates between NMax and NMin, the value of N at the time of calculation of W may not be the same when R is calculated. + This is a side effect of dynamic quorum and requires careful consideration. + + NMin = 2, NMax >= 3 + + Simultaneous Failures + ===================== + In general N replicas imply 2f+1 simultaneous failures + N = 5 allows for 2 simultaneous failures + N = 4 allows for 1 failure + N = 3 allows for 1 failure + N < 3 allows for 0 failures + + Quorums + ======= + W = Write Quorum = NUMBER of replicas which acknowledge a write before the primary can ack the client. It is majority set i.e. N/2 + 1 + R = READ Quorum = Set of replicas such that there is non-empty intersection between W and R that constitute N i.e. R = N -W + 1 + + For sync replication, W is used as a majority quorum. + For async replication, W = 1. We have two LSNs, one is quorum acknowledged LSN (LSN-Q) and another is what is visible to the client (LSN-C). + LSN-Q is the stable LSN which corresponds to the write quorum of Windows Fabric. LSN-C is unstable and corresponds to W=1. + + Assumptions + =========== + Nmin <= N <= Nmax + W >= N/2 + 1 + R = N -W + 1 + + N from read standpoint means number of address from BE which is returning successful response. + Successful reponse: Any BE response containing LSN response header is considered successful reponse. Typically every response other than 410 is treated as succesful response. + + STRONG Consistency + ================== + STRONG READ requires following guarantees. + * READ value is the latest that has been written. If a write operation finished. Any subsequent reads should see that value. + * Monotonic guarantee. Any read that starts after a previous read operation, should see atleast return equal or higher version of the value. + + To perform strong read we require that atleast R i.e. READ Quorum number of replicas have the value committed. To acheve that such read : + * READ R replicas. If they have the same LSN, use the read result + * If they don't have the same LSN, we will either return the result with the highest LSN observed from those R replicas, after ensuring that LSN + becomes available with R replicas. + * Secondary replicas are always preferred for reading. If R secondaries have returned the result but cannot agree on the resulting LSN, we can include Primary to satisfy read quorum. + * If we only have R replicas (i.e. N==R), we include primary in reading the result and validate N==R. + + Bounded Staleness + ================= + Sync Replication: + Bounded staleness uses the same logic as STRONG for cases where the server is using sync replication. + + Async Replication: + For async replication, we make sure that we do not use the Primary as barrier for read quorum. This is because Primary is always going to run ahead (async replication uses W=1 on Primary). + Using primary would voilate the monotonic read guarantees when we fall back to reading from secondary in the subsequent reads as they are always running slower as compared to Primary. + + SESSION + ======= + We read from secondaries one by one until we find a match for the client's session token (LSN-C). + We go to primary as a last resort which should satisfy LSN-C. + + Availability for Bounded Staleness (for NMax = 4 and NMin = 2): + When there is a partition, the minority quorum can remain available for read as long as N >= 1 + When there is a partition, the minority quorum can remain available for writes as long as N >= 2 + + EVENTUAL + ======== + We can read from any replicas. + + Availability for Bounded Staleness (for NMax = 4 and NMin = 2): + When there is a partition, the minority quorum can remain available for read as long as N >= 1 + When there is a partition, the minority quorum can remain available for writes as long as N >= 2 + + READ Retry logic + ----------------- + For Any NonQuorum Reads(A.K.A ReadAny); AddressCache is refreshed for following condition. + 1) No Secondary Address is found in Address Cache. + 2) Chosen Secondary Returned GoneException/EndpointNotFoundException. + + For Quorum READ address cache is refreshed on following condition. + 1) We found only R secondary where R < RMAX. + 2) We got GoneException/EndpointNotFoundException on all the secondary we contacted. + + */ +/** + * ConsistencyReader has a dependency on both StoreReader and QuorumReader. For Bounded Staleness and STRONG Consistency, it uses the Quorum Reader + * to converge on a read from read quorum number of replicas. + * For SESSION and EVENTUAL Consistency, it directly uses the store reader. + */ +public class ConsistencyReader { + private final static int MAX_NUMBER_OF_SECONDARY_READ_RETRIES = 3; + private final static Logger logger = LoggerFactory.getLogger(ConsistencyReader.class); + + private final AddressSelector addressSelector; + private final GatewayServiceConfigurationReader serviceConfigReader; + private final IAuthorizationTokenProvider authorizationTokenProvider; + private final StoreReader storeReader; + private final QuorumReader quorumReader; + private final Configs configs; + + public ConsistencyReader( + Configs configs, + AddressSelector addressSelector, + ISessionContainer sessionContainer, + TransportClient transportClient, + GatewayServiceConfigurationReader serviceConfigReader, + IAuthorizationTokenProvider authorizationTokenProvider) { + this.configs = configs; + this.addressSelector = addressSelector; + this.serviceConfigReader = serviceConfigReader; + this.authorizationTokenProvider = authorizationTokenProvider; + this.storeReader = createStoreReader(transportClient, addressSelector, sessionContainer); + this.quorumReader = createQuorumReader(transportClient, addressSelector, this.storeReader, serviceConfigReader, authorizationTokenProvider); + } + + public Mono readAsync(RxDocumentServiceRequest entity, + TimeoutHelper timeout, + boolean isInRetry, + boolean forceRefresh) { + if (!isInRetry) { + if (timeout.isElapsed()) { + return Mono.error(new RequestTimeoutException()); + } + + } else { + if (timeout.isElapsed()) { + return Mono.error(new GoneException()); + } + } + + entity.requestContext.timeoutHelper = timeout; + + if (entity.requestContext.requestChargeTracker == null) { + entity.requestContext.requestChargeTracker = new RequestChargeTracker(); + } + + if(entity.requestContext.cosmosResponseDiagnostics == null) { + entity.requestContext.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + + entity.requestContext.forceRefreshAddressCache = forceRefresh; + + ValueHolder targetConsistencyLevel = ValueHolder.initialize(null); + ValueHolder useSessionToken = ValueHolder.initialize(null); + ReadMode desiredReadMode; + try { + desiredReadMode = this.deduceReadMode(entity, targetConsistencyLevel, useSessionToken); + } catch (CosmosClientException e) { + return Mono.error(e); + } + int maxReplicaCount = this.getMaxReplicaSetSize(entity); + int readQuorumValue = maxReplicaCount - (maxReplicaCount / 2); + + switch (desiredReadMode) { + case Primary: + return this.readPrimaryAsync(entity, useSessionToken.v); + + case Strong: + entity.requestContext.performLocalRefreshOnGoneException = true; + return this.quorumReader.readStrongAsync(entity, readQuorumValue, desiredReadMode); + + case BoundedStaleness: + entity.requestContext.performLocalRefreshOnGoneException = true; + + // for bounded staleness, we are defaulting to read strong for local region reads. + // this can be done since we are always running with majority quorum w = 3 (or 2 during quorum downshift). + // This means that the primary will always be part of the write quorum, and + // therefore can be included for barrier reads. + + // NOTE: this assumes that we are running with SYNC replication (i.e. majority quorum). + // When we run on a minority write quorum(w=2), to ensure monotonic read guarantees + // we always contact two secondary replicas and exclude primary. + // However, this model significantly reduces availability and available throughput for serving reads for bounded staleness during reconfiguration. + // Therefore, to ensure monotonic read guarantee from any replica set we will just use regular quorum read(R=2) since our write quorum is always majority(W=3) + return this.quorumReader.readStrongAsync(entity, readQuorumValue, desiredReadMode); + + case Any: + if (targetConsistencyLevel.v == ConsistencyLevel.SESSION) { + return this.readSessionAsync(entity, desiredReadMode); + } else { + return this.readAnyAsync(entity, desiredReadMode); + } + + default: + throw new IllegalStateException("invalid operation " + desiredReadMode); + } + } + + private Mono readPrimaryAsync(RxDocumentServiceRequest entity, + boolean useSessionToken) { + + Mono responseObs = this.storeReader.readPrimaryAsync( + entity, + false /*required valid LSN*/, + useSessionToken); + return responseObs.flatMap(response -> { + try { + return Mono.just(response.toResponse()); + } catch (CosmosClientException e) { + return Mono.error(e); + } + }); + } + + private Mono readAnyAsync(RxDocumentServiceRequest entity, + ReadMode readMode) { + Mono> responsesObs = this.storeReader.readMultipleReplicaAsync( + entity, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN*/ false, + /* useSessionToken */ false, + /* readMode */ readMode); + + return responsesObs.flatMap( + responses -> { + if (responses.size() == 0) { + return Mono.error(new GoneException(RMResources.Gone)); + } + + try { + return Mono.just(responses.get(0).toResponse()); + } catch (CosmosClientException e) { + return Mono.error(e); + } + } + ); + } + + private Mono readSessionAsync(RxDocumentServiceRequest entity, + ReadMode readMode) { + + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + Mono> responsesObs = this.storeReader.readMultipleReplicaAsync( + entity, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN */ true, + /* useSessionToken */ true, + /* readMode */ readMode, + /* checkMinLsn */ true, + /* forceReadAll */ false); + + return responsesObs.flatMap(responses -> { + + if (responses.size() > 0) { + try { + return Mono.just(responses.get(0).toResponse(entity.requestContext.requestChargeTracker)); + } catch (NotFoundException notFoundException) { + try { + if (entity.requestContext.sessionToken != null + && responses.get(0).sessionToken != null + && !entity.requestContext.sessionToken.isValid(responses.get(0).sessionToken)) { + logger.warn("Convert to session read exception, request {} SESSION Lsn {}, responseLSN {}", entity.getResourceAddress(), entity.requestContext.sessionToken.convertToString(), responses.get(0).lsn); + notFoundException.responseHeaders().put(WFConstants.BackendHeaders.SUB_STATUS, Integer.toString(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)); + } + return Mono.error(notFoundException); + } catch (CosmosClientException e) { + return Mono.error(e); + } + } catch (CosmosClientException dce) { + return Mono.error(dce); + } + + } + + // else + HashMap responseHeaders = new HashMap<>(); + responseHeaders.put(WFConstants.BackendHeaders.SUB_STATUS, Integer.toString(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)); + ISessionToken requestSessionToken = entity.requestContext.sessionToken; + logger.warn("Fail the session read {}, request session token {}", entity.getResourceAddress(), requestSessionToken == null ? "" : requestSessionToken.convertToString()); + return Mono.error(new NotFoundException(RMResources.ReadSessionNotAvailable, responseHeaders, null)); + }); + } + + ReadMode deduceReadMode(RxDocumentServiceRequest request, + ValueHolder targetConsistencyLevel, + ValueHolder useSessionToken) throws CosmosClientException { + targetConsistencyLevel.v = RequestHelper.GetConsistencyLevelToUse(this.serviceConfigReader, request); + useSessionToken.v = (targetConsistencyLevel.v == ConsistencyLevel.SESSION); + + if (request.getDefaultReplicaIndex() != null) { + // Don't use session token - this is used by internal scenarios which technically don't intend session read when they target + // request to specific replica. + useSessionToken.v = false; + return ReadMode.Primary; //Let the addressResolver decides which replica to connect to. + } + + switch (targetConsistencyLevel.v) { + case EVENTUAL: + return ReadMode.Any; + + case CONSISTENT_PREFIX: + return ReadMode.Any; + + case SESSION: + return ReadMode.Any; + + case BOUNDED_STALENESS: + return ReadMode.BoundedStaleness; + + case STRONG: + return ReadMode.Strong; + + default: + throw new IllegalStateException("INVALID Consistency Level " + targetConsistencyLevel.v); + } + } + + public int getMaxReplicaSetSize(RxDocumentServiceRequest entity) { + boolean isMasterResource = ReplicatedResourceClient.isReadingFromMaster(entity.getResourceType(), entity.getOperationType()); + if (isMasterResource) { + return this.serviceConfigReader.getSystemReplicationPolicy().getMaxReplicaSetSize(); + } else { + return this.serviceConfigReader.getUserReplicationPolicy().getMaxReplicaSetSize(); + } + } + + public int getMinReplicaSetSize(RxDocumentServiceRequest entity) { + boolean isMasterResource = ReplicatedResourceClient.isReadingFromMaster(entity.getResourceType(), entity.getOperationType()); + if (isMasterResource) { + return this.serviceConfigReader.getSystemReplicationPolicy().getMinReplicaSetSize(); + } else { + return this.serviceConfigReader.getUserReplicationPolicy().getMinReplicaSetSize(); + } + } + + public StoreReader createStoreReader(TransportClient transportClient, + AddressSelector addressSelector, + ISessionContainer sessionContainer) { + return new StoreReader(transportClient, + addressSelector, + sessionContainer); + } + + public QuorumReader createQuorumReader(TransportClient transportClient, + AddressSelector addressSelector, + StoreReader storeReader, + GatewayServiceConfigurationReader serviceConfigurationReader, + IAuthorizationTokenProvider authorizationTokenProvider) { + return new QuorumReader(transportClient, + addressSelector, + storeReader, + serviceConfigurationReader, + authorizationTokenProvider, + configs); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriter.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriter.java new file mode 100644 index 0000000000000..2202c5c5ccfff --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriter.java @@ -0,0 +1,394 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.Integers; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.SessionTokenHelper; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import org.apache.commons.collections4.ComparatorUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.net.URI; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +/* + * ConsistencyWriter has two modes for writing - local quorum-acked write and globally strong write. + * + * The determination of whether a request is a local quorum-acked write or a globally strong write is through several factors: + * 1. Request.RequestContext.OriginalRequestConsistencyLevel - ensure that original request's consistency level, if set, is strong. + * 2. DEFAULT consistency level of the accoutn should be strong. + * 3. NUMBER of read regions returned by write response > 0. + * + * For quorum-acked write: + * We send single request to primary of a single partition, which will take care of replicating to its secondaries. Once write quorum number of replicas commits the write, the write request returns to the user with success. There is no additional handling for this case. + * + * For globally strong write: + * Similarly, we send single request to primary of write region, which will take care of replicating to its secondaries, one of which is XPPrimary. XPPrimary will then replicate to all remote regions, which will all ack from within their region. In the write region, the request returns from the backend once write quorum number of replicas commits the write - but at this time, the response cannot be returned to caller, since linearizability guarantees will be violated. ConsistencyWriter will continuously issue barrier head requests against the partition in question, until GlobalCommittedLsn is at least as big as the lsn of the original response. + * 1. Issue write request to write region + * 2. Receive response from primary of write region, look at GlobalCommittedLsn and LSN headers. + * 3. If GlobalCommittedLSN == LSN, return response to caller + * 4. If GlobalCommittedLSN < LSN, cache LSN in request as SelectedGlobalCommittedLSN, and issue barrier requests against any/all replicas. + * 5. Each barrier response will contain its own LSN and GlobalCommittedLSN, check for any response that satisfies GlobalCommittedLSN >= SelectedGlobalCommittedLSN + * 6. Return to caller on success. + */ +public class ConsistencyWriter { + private final static int MAX_NUMBER_OF_WRITE_BARRIER_READ_RETRIES = 30; + private final static int DELAY_BETWEEN_WRITE_BARRIER_CALLS_IN_MS = 30; + private final static int MAX_SHORT_BARRIER_RETRIES_FOR_MULTI_REGION = 4; + private final static int SHORT_BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION = 10; + + private final Logger logger = LoggerFactory.getLogger(ConsistencyWriter.class); + private final TransportClient transportClient; + private final AddressSelector addressSelector; + private final ISessionContainer sessionContainer; + private final IAuthorizationTokenProvider authorizationTokenProvider; + private final boolean useMultipleWriteLocations; + private final GatewayServiceConfigurationReader serviceConfigReader; + private final StoreReader storeReader; + + public ConsistencyWriter( + AddressSelector addressSelector, + ISessionContainer sessionContainer, + TransportClient transportClient, + IAuthorizationTokenProvider authorizationTokenProvider, + GatewayServiceConfigurationReader serviceConfigReader, + boolean useMultipleWriteLocations) { + this.transportClient = transportClient; + this.addressSelector = addressSelector; + this.sessionContainer = sessionContainer; + this.authorizationTokenProvider = authorizationTokenProvider; + this.useMultipleWriteLocations = useMultipleWriteLocations; + this.serviceConfigReader = serviceConfigReader; + this.storeReader = new StoreReader(transportClient, addressSelector, null /*we need store reader only for global strong, no session is needed*/); + } + + public Mono writeAsync( + RxDocumentServiceRequest entity, + TimeoutHelper timeout, + boolean forceRefresh) { + + if (timeout.isElapsed()) { + return Mono.error(new RequestTimeoutException()); + } + + String sessionToken = entity.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + + return this.writePrivateAsync(entity, timeout, forceRefresh).doOnEach( + arg -> { + try { + SessionTokenHelper.setOriginalSessionToken(entity, sessionToken); + } catch (Throwable throwable) { + logger.error("Unexpected failure in handling orig [{}]: new [{}]", arg, throwable.getMessage(), throwable); + } + } + ); + } + + Mono writePrivateAsync( + RxDocumentServiceRequest request, + TimeoutHelper timeout, + boolean forceRefresh) { + if (timeout.isElapsed()) { + return Mono.error(new RequestTimeoutException()); + } + + request.requestContext.timeoutHelper = timeout; + + if (request.requestContext.requestChargeTracker == null) { + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + } + + if (request.requestContext.cosmosResponseDiagnostics == null) { + request.requestContext.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + + request.requestContext.forceRefreshAddressCache = forceRefresh; + + if (request.requestContext.globalStrongWriteResponse == null) { + + Mono> replicaAddressesObs = this.addressSelector.resolveAddressesAsync(request, forceRefresh); + AtomicReference primaryURI = new AtomicReference<>(); + + return replicaAddressesObs.flatMap(replicaAddresses -> { + try { + List contactedReplicas = new ArrayList<>(); + replicaAddresses.forEach(replicaAddress -> contactedReplicas.add(HttpUtils.toURI(replicaAddress.getPhysicalUri()))); + BridgeInternal.setContactedReplicas(request.requestContext.cosmosResponseDiagnostics, contactedReplicas); + return Mono.just(AddressSelector.getPrimaryUri(request, replicaAddresses)); + } catch (GoneException e) { + // RxJava1 doesn't allow throwing checked exception from Observable operators + return Mono.error(e); + } + }).flatMap(primaryUri -> { + try { + primaryURI.set(primaryUri); + if (this.useMultipleWriteLocations && + RequestHelper.GetConsistencyLevelToUse(this.serviceConfigReader, request) == ConsistencyLevel.SESSION) { + // Set session token to ensure session consistency for write requests + // when writes can be issued to multiple locations + SessionTokenHelper.setPartitionLocalSessionToken(request, this.sessionContainer); + } else { + // When writes can only go to single location, there is no reason + // to session session token to the server. + SessionTokenHelper.validateAndRemoveSessionToken(request); + } + + } catch (Exception e) { + return Mono.error(e); + } + + return this.transportClient.invokeResourceOperationAsync(primaryUri, request) + .doOnError( + t -> { + try { + CosmosClientException ex = Utils.as(t, CosmosClientException.class); + try { + BridgeInternal.recordResponse(request.requestContext.cosmosResponseDiagnostics, request, + storeReader.createStoreResult(null, ex, false, false, primaryUri)); + } catch (CosmosClientException e) { + logger.error("Error occurred while recording response", e); + } + String value = ex.responseHeaders().get(HttpConstants.HttpHeaders.WRITE_REQUEST_TRIGGER_ADDRESS_REFRESH); + if (!Strings.isNullOrWhiteSpace(value)) { + Integer result = Integers.tryParse(value); + if (result != null && result == 1) { + startBackgroundAddressRefresh(request); + } + } + } catch (Throwable throwable) { + logger.error("Unexpected failure in handling orig [{}]", t.getMessage(), t); + logger.error("Unexpected failure in handling orig [{}] : new [{}]", t.getMessage(), throwable.getMessage(), throwable); + } + } + ); + + }).flatMap(response -> { + try { + BridgeInternal.recordResponse(request.requestContext.cosmosResponseDiagnostics, request, + storeReader.createStoreResult(response, null, false, false, primaryURI.get())); + } catch (CosmosClientException e) { + logger.error("Error occurred while recording response", e); + } + return barrierForGlobalStrong(request, response); + }); + } else { + + Mono barrierRequestObs = BarrierRequestHelper.createAsync(request, this.authorizationTokenProvider, null, request.requestContext.globalCommittedSelectedLSN); + return barrierRequestObs.flatMap(barrierRequest -> waitForWriteBarrierAsync(barrierRequest, request.requestContext.globalCommittedSelectedLSN) + .flatMap(v -> { + + if (!v) { + logger.warn("ConsistencyWriter: Write barrier has not been met for global strong request. SelectedGlobalCommittedLsn: {}", request.requestContext.globalCommittedSelectedLSN); + return Mono.error(new GoneException(RMResources.GlobalStrongWriteBarrierNotMet)); + } + + return Mono.just(request); + })).map(req -> req.requestContext.globalStrongWriteResponse); + } + } + + boolean isGlobalStrongRequest(RxDocumentServiceRequest request, StoreResponse response) { + if (this.serviceConfigReader.getDefaultConsistencyLevel() == ConsistencyLevel.STRONG) { + int numberOfReadRegions = -1; + String headerValue = null; + if ((headerValue = response.getHeaderValue(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS)) != null) { + numberOfReadRegions = Integer.parseInt(headerValue); + } + + if (numberOfReadRegions > 0 && this.serviceConfigReader.getDefaultConsistencyLevel() == ConsistencyLevel.STRONG) { + return true; + } + } + + return false; + } + + Mono barrierForGlobalStrong(RxDocumentServiceRequest request, StoreResponse response) { + try { + if (ReplicatedResourceClient.isGlobalStrongEnabled() && this.isGlobalStrongRequest(request, response)) { + Utils.ValueHolder lsn = Utils.ValueHolder.initialize(-1l); + Utils.ValueHolder globalCommittedLsn = Utils.ValueHolder.initialize(-1l); + + getLsnAndGlobalCommittedLsn(response, lsn, globalCommittedLsn); + if (lsn.v == -1 || globalCommittedLsn.v == -1) { + logger.error("ConsistencyWriter: lsn {} or GlobalCommittedLsn {} is not set for global strong request", + lsn, globalCommittedLsn); + throw new GoneException(RMResources.Gone); + } + + request.requestContext.globalStrongWriteResponse = response; + request.requestContext.globalCommittedSelectedLSN = lsn.v; + + //if necessary we would have already refreshed cache by now. + request.requestContext.forceRefreshAddressCache = false; + + logger.debug("ConsistencyWriter: globalCommittedLsn {}, lsn {}", globalCommittedLsn, lsn); + //barrier only if necessary, i.e. when write region completes write, but read regions have not. + + if (globalCommittedLsn.v < lsn.v) { + Mono barrierRequestObs = BarrierRequestHelper.createAsync(request, + this.authorizationTokenProvider, + null, + request.requestContext.globalCommittedSelectedLSN); + + return barrierRequestObs.flatMap(barrierRequest -> { + Mono barrierWait = this.waitForWriteBarrierAsync(barrierRequest, request.requestContext.globalCommittedSelectedLSN); + + return barrierWait.flatMap(res -> { + if (!res) { + logger.error("ConsistencyWriter: Write barrier has not been met for global strong request. SelectedGlobalCommittedLsn: {}", + request.requestContext.globalCommittedSelectedLSN); + // RxJava1 doesn't allow throwing checked exception + return Mono.error(new GoneException(RMResources.GlobalStrongWriteBarrierNotMet)); + } + + return Mono.just(request.requestContext.globalStrongWriteResponse); + }); + + }); + + } else { + return Mono.just(request.requestContext.globalStrongWriteResponse); + } + } else { + return Mono.just(response); + } + + } catch (CosmosClientException e) { + // RxJava1 doesn't allow throwing checked exception from Observable operators + return Mono.error(e); + } + } + + private Mono waitForWriteBarrierAsync(RxDocumentServiceRequest barrierRequest, long selectedGlobalCommittedLsn) { + AtomicInteger writeBarrierRetryCount = new AtomicInteger(ConsistencyWriter.MAX_NUMBER_OF_WRITE_BARRIER_READ_RETRIES); + AtomicLong maxGlobalCommittedLsnReceived = new AtomicLong(0); + return Flux.defer(() -> { + if (barrierRequest.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new RequestTimeoutException()); + } + + Mono> storeResultListObs = this.storeReader.readMultipleReplicaAsync( + barrierRequest, + true /*allowPrimary*/, + 1 /*any replica with correct globalCommittedLsn is good enough*/, + false /*requiresValidLsn*/, + false /*useSessionToken*/, + ReadMode.Strong, + false /*checkMinLsn*/, + false /*forceReadAll*/); + return storeResultListObs.flatMap( + responses -> { + if (responses != null && responses.stream().anyMatch(response -> response.globalCommittedLSN >= selectedGlobalCommittedLsn)) { + return Mono.just(Boolean.TRUE); + } + + //get max global committed lsn from current batch of responses, then update if greater than max of all batches. + long maxGlobalCommittedLsn = (responses != null || !responses.isEmpty()) ? + (Long) responses.stream().map(s -> s.globalCommittedLSN).max(ComparatorUtils.NATURAL_COMPARATOR).get() : + 0L; + maxGlobalCommittedLsnReceived.set(maxGlobalCommittedLsnReceived.get() > maxGlobalCommittedLsn ? + maxGlobalCommittedLsnReceived.get() : maxGlobalCommittedLsn); + + //only refresh on first barrier call, set to false for subsequent attempts. + barrierRequest.requestContext.forceRefreshAddressCache = false; + + //trace on last retry. + if (writeBarrierRetryCount.getAndDecrement() == 0) { + logger.debug("ConsistencyWriter: WaitForWriteBarrierAsync - Last barrier multi-region strong. Responses: {}", + responses.stream().map(StoreResult::toString).collect(Collectors.joining("; "))); + } + + return Mono.empty(); + }).flux(); + }).repeatWhen(s -> { + if (writeBarrierRetryCount.get() == 0) { + return Flux.empty(); + } else { + + if ((ConsistencyWriter.MAX_NUMBER_OF_WRITE_BARRIER_READ_RETRIES - writeBarrierRetryCount.get()) > ConsistencyWriter.MAX_SHORT_BARRIER_RETRIES_FOR_MULTI_REGION) { + return Flux.just(0L).delayElements(Duration.ofMillis(ConsistencyWriter.DELAY_BETWEEN_WRITE_BARRIER_CALLS_IN_MS)); + } else { + return Flux.just(0L).delayElements(Duration.ofMillis(ConsistencyWriter.SHORT_BARRIER_RETRY_INTERVAL_IN_MS_FOR_MULTI_REGION)); + } + } + }).take(1) + .switchIfEmpty(Mono.defer(() -> { + // after retries exhausted print this log and return false + logger.debug("ConsistencyWriter: Highest global committed lsn received for write barrier call is {}", maxGlobalCommittedLsnReceived); + + return Mono.just(false); + })) + .map(r -> r) + .single(); + } + + static void getLsnAndGlobalCommittedLsn(StoreResponse response, Utils.ValueHolder lsn, Utils.ValueHolder globalCommittedLsn) { + lsn.v = -1L; + globalCommittedLsn.v = -1L; + + String headerValue; + + if ((headerValue = response.getHeaderValue(WFConstants.BackendHeaders.LSN)) != null) { + lsn.v = Long.parseLong(headerValue); + } + + if ((headerValue = response.getHeaderValue(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN)) != null) { + globalCommittedLsn.v = Long.parseLong(headerValue); + } + } + + void startBackgroundAddressRefresh(RxDocumentServiceRequest request) { + this.addressSelector.resolvePrimaryUriAsync(request, true) + .publishOn(Schedulers.elastic()) + .subscribe( + r -> { + }, + e -> logger.warn( + "Background refresh of the primary address failed with {}", e.getMessage(), e) + ); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/CustomHeaders.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/CustomHeaders.java new file mode 100644 index 0000000000000..7f89468297bb2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/CustomHeaders.java @@ -0,0 +1,32 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +public final class CustomHeaders { + + public static final class HttpHeaders { + // Specify whether to exclude system properties while storing the document + public static final String EXCLUDE_SYSTEM_PROPERTIES = "x-ms-exclude-system-properties"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ErrorUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ErrorUtils.java new file mode 100644 index 0000000000000..0408e7e7b9dc7 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ErrorUtils.java @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.net.URI; + +public class ErrorUtils { + private static final Logger logger = LoggerFactory.getLogger(ErrorUtils.class); + + static Mono getErrorResponseAsync(HttpResponse responseMessage, HttpRequest request) { + Mono responseAsString = ResponseUtils.toString(responseMessage.body()); + if (request.httpMethod() == HttpMethod.DELETE) { + return Mono.just(StringUtils.EMPTY); + } + return responseAsString; + } + + static void logGoneException(URI physicalAddress, String activityId) { + logger.trace("Listener not found. Store Physical Address {} ActivityId {}", + physicalAddress, activityId); + } + + protected static void logGoneException(String physicalAddress, String activityId) { + logger.trace("Listener not found. Store Physical Address {} ActivityId {}", + physicalAddress, activityId); + } + + static void logException(URI physicalAddress, String activityId) { + logger.trace("Store Request Failed. Store Physical Address {} ActivityId {}", + physicalAddress, activityId); + } + + protected static void logException(String physicalAddress, String activityId) { + logger.trace("Store Request Failed. Store Physical Address {} ActivityId {}", + physicalAddress, activityId); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCache.java new file mode 100644 index 0000000000000..e07c3d8c7253a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCache.java @@ -0,0 +1,541 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.internal.AuthorizationTokenType; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.caches.AsyncCache; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class GatewayAddressCache implements IAddressCache { + private final static Logger logger = LoggerFactory.getLogger(GatewayAddressCache.class); + private final static String protocolFilterFormat = "%s eq %s"; + private final static int DefaultBatchSize = 50; + + private final static int DefaultSuboptimalPartitionForceRefreshIntervalInSeconds = 600; + private final ServiceConfig serviceConfig = ServiceConfig.getInstance(); + + private final String databaseFeedEntryUrl = PathsHelper.generatePath(ResourceType.Database, "", true); + private final URL serviceEndpoint; + private final URL addressEndpoint; + + private final AsyncCache serverPartitionAddressCache; + private final ConcurrentHashMap suboptimalServerPartitionTimestamps; + private final long suboptimalPartitionForceRefreshIntervalInSeconds; + + private final String protocolScheme; + private final String protocolFilter; + private final IAuthorizationTokenProvider tokenProvider; + private final HashMap defaultRequestHeaders; + private final HttpClient httpClient; + + private volatile Pair masterPartitionAddressCache; + private volatile Instant suboptimalMasterPartitionTimestamp; + + public GatewayAddressCache( + URL serviceEndpoint, + Protocol protocol, + IAuthorizationTokenProvider tokenProvider, + UserAgentContainer userAgent, + HttpClient httpClient, + long suboptimalPartitionForceRefreshIntervalInSeconds) { + try { + this.addressEndpoint = new URL(serviceEndpoint, Paths.ADDRESS_PATH_SEGMENT); + } catch (MalformedURLException e) { + logger.error("serviceEndpoint {} is invalid", serviceEndpoint, e); + assert false; + throw new IllegalStateException(e); + } + this.tokenProvider = tokenProvider; + this.serviceEndpoint = serviceEndpoint; + this.serverPartitionAddressCache = new AsyncCache<>(); + this.suboptimalServerPartitionTimestamps = new ConcurrentHashMap<>(); + this.suboptimalMasterPartitionTimestamp = Instant.MAX; + + this.suboptimalPartitionForceRefreshIntervalInSeconds = suboptimalPartitionForceRefreshIntervalInSeconds; + + this.protocolScheme = protocol.scheme(); + this.protocolFilter = String.format(GatewayAddressCache.protocolFilterFormat, + Constants.Properties.PROTOCOL, + this.protocolScheme); + + this.httpClient = httpClient; + + if (userAgent == null) { + userAgent = new UserAgentContainer(); + } + + defaultRequestHeaders = new HashMap<>(); + defaultRequestHeaders.put(HttpConstants.HttpHeaders.USER_AGENT, userAgent.getUserAgent()); + + // Set requested API version header for version enforcement. + defaultRequestHeaders.put(HttpConstants.HttpHeaders.VERSION, HttpConstants.Versions.CURRENT_VERSION); + } + + public GatewayAddressCache( + URL serviceEndpoint, + Protocol protocol, + IAuthorizationTokenProvider tokenProvider, + UserAgentContainer userAgent, + HttpClient httpClient) { + this(serviceEndpoint, + protocol, + tokenProvider, + userAgent, + httpClient, + DefaultSuboptimalPartitionForceRefreshIntervalInSeconds); + } + + private URL getServiceEndpoint() { + return this.serviceEndpoint; + } + + @Override + public Mono tryGetAddresses(RxDocumentServiceRequest request, + PartitionKeyRangeIdentity partitionKeyRangeIdentity, + boolean forceRefreshPartitionAddresses) { + + com.azure.data.cosmos.internal.Utils.checkNotNullOrThrow(request, "request", ""); + com.azure.data.cosmos.internal.Utils.checkNotNullOrThrow(partitionKeyRangeIdentity, "partitionKeyRangeIdentity", ""); + + if (StringUtils.equals(partitionKeyRangeIdentity.getPartitionKeyRangeId(), + PartitionKeyRange.MASTER_PARTITION_KEY_RANGE_ID)) { + + // if that's master partition return master partition address! + return this.resolveMasterAsync(request, forceRefreshPartitionAddresses, request.properties).map(Pair::getRight); + } + + Instant suboptimalServerPartitionTimestamp = this.suboptimalServerPartitionTimestamps.get(partitionKeyRangeIdentity); + + if (suboptimalServerPartitionTimestamp != null) { + boolean forceRefreshDueToSuboptimalPartitionReplicaSet = Duration.between(suboptimalServerPartitionTimestamp, Instant.now()).getSeconds() + > this.suboptimalPartitionForceRefreshIntervalInSeconds; + + if (forceRefreshDueToSuboptimalPartitionReplicaSet) { + // Compares the existing value for the specified key with a specified value, + // and if they are equal, updates the key with a third value. + Instant newValue = this.suboptimalServerPartitionTimestamps.computeIfPresent(partitionKeyRangeIdentity, + (key, oldVal) -> { + if (suboptimalServerPartitionTimestamp.equals(oldVal)) { + return Instant.MAX; + } else { + return oldVal; + } + }); + + if (!newValue.equals(suboptimalServerPartitionTimestamp)) { + // the value was replaced; + forceRefreshPartitionAddresses = true; + } + } + } + + final boolean forceRefreshPartitionAddressesModified = forceRefreshPartitionAddresses; + + if (forceRefreshPartitionAddressesModified) { + this.serverPartitionAddressCache.refresh( + partitionKeyRangeIdentity, + () -> this.getAddressesForRangeId( + request, + partitionKeyRangeIdentity.getCollectionRid(), + partitionKeyRangeIdentity.getPartitionKeyRangeId(), + true)); + + this.suboptimalServerPartitionTimestamps.remove(partitionKeyRangeIdentity); + } + + Mono addressesObs = this.serverPartitionAddressCache.getAsync( + partitionKeyRangeIdentity, + null, + () -> this.getAddressesForRangeId( + request, + partitionKeyRangeIdentity.getCollectionRid(), + partitionKeyRangeIdentity.getPartitionKeyRangeId(), + false)); + + return addressesObs.map( + addresses -> { + if (notAllReplicasAvailable(addresses)) { + this.suboptimalServerPartitionTimestamps.putIfAbsent(partitionKeyRangeIdentity, Instant.now()); + } + + return addresses; + }).onErrorResume(ex -> { + CosmosClientException dce = com.azure.data.cosmos.internal.Utils.as(ex, CosmosClientException.class); + if (dce == null) { + if (forceRefreshPartitionAddressesModified) { + this.suboptimalServerPartitionTimestamps.remove(partitionKeyRangeIdentity); + } + return Mono.error(ex); + } else { + if (Exceptions.isStatusCode(dce, HttpConstants.StatusCodes.NOTFOUND) || + Exceptions.isStatusCode(dce, HttpConstants.StatusCodes.GONE) || + Exceptions.isSubStatusCode(dce, HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE)) { + //remove from suboptimal cache in case the collection+pKeyRangeId combo is gone. + this.suboptimalServerPartitionTimestamps.remove(partitionKeyRangeIdentity); + return null; + } + return Mono.error(ex); + } + + }); + } + + public Mono> getServerAddressesViaGatewayAsync( + RxDocumentServiceRequest request, + String collectionRid, + List partitionKeyRangeIds, + boolean forceRefresh) { + String entryUrl = PathsHelper.generatePath(ResourceType.Document, collectionRid, true); + HashMap addressQuery = new HashMap<>(); + + addressQuery.put(HttpConstants.QueryStrings.URL, HttpUtils.urlEncode(entryUrl)); + + HashMap headers = new HashMap<>(defaultRequestHeaders); + if (forceRefresh) { + headers.put(HttpConstants.HttpHeaders.FORCE_REFRESH, Boolean.TRUE.toString()); + } + + addressQuery.put(HttpConstants.QueryStrings.FILTER, HttpUtils.urlEncode(this.protocolFilter)); + + addressQuery.put(HttpConstants.QueryStrings.PARTITION_KEY_RANGE_IDS, String.join(",", partitionKeyRangeIds)); + headers.put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + String token; + + token = this.tokenProvider.getUserAuthorizationToken( + collectionRid, + ResourceType.Document, + HttpConstants.HttpMethods.GET, + headers, + AuthorizationTokenType.PrimaryMasterKey, + request.properties); + + if (token == null && request.getIsNameBased()) { + // User doesn't have rid based resource token. Maybe user has name based. + String collectionAltLink = PathsHelper.getCollectionPath(request.getResourceAddress()); + token = this.tokenProvider.getUserAuthorizationToken( + collectionAltLink, + ResourceType.Document, + HttpConstants.HttpMethods.GET, + headers, + AuthorizationTokenType.PrimaryMasterKey, + request.properties); + } + + token = HttpUtils.urlEncode(token); + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, token); + URL targetEndpoint = Utils.setQuery(this.addressEndpoint.toString(), Utils.createQuery(addressQuery)); + String identifier = logAddressResolutionStart(request, targetEndpoint); + + HttpHeaders httpHeaders = new HttpHeaders(headers.size()); + for (Map.Entry entry : headers.entrySet()) { + httpHeaders.set(entry.getKey(), entry.getValue()); + } + + HttpRequest httpRequest; + try { + httpRequest = new HttpRequest(HttpMethod.GET, targetEndpoint.toURI(), targetEndpoint.getPort(), httpHeaders); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(targetEndpoint.toString(), e); + } + Mono httpResponseMono = this.httpClient.send(httpRequest); + + Mono dsrObs = HttpClientUtils.parseResponseAsync(httpResponseMono, httpRequest); + return dsrObs.map( + dsr -> { + logAddressResolutionEnd(request, identifier); + return dsr.getQueryResponse(Address.class); + }); + } + + public void dispose() { + // TODO We will implement this in future once we will move to httpClient to CompositeHttpClient + //https://msdata.visualstudio.com/CosmosDB/_workitems/edit/340842 + } + + private Mono> resolveMasterAsync(RxDocumentServiceRequest request, boolean forceRefresh, Map properties) { + Pair masterAddressAndRangeInitial = this.masterPartitionAddressCache; + + forceRefresh = forceRefresh || + (masterAddressAndRangeInitial != null && + notAllReplicasAvailable(masterAddressAndRangeInitial.getRight()) && + Duration.between(this.suboptimalMasterPartitionTimestamp, Instant.now()).getSeconds() > this.suboptimalPartitionForceRefreshIntervalInSeconds); + + if (forceRefresh || this.masterPartitionAddressCache == null) { + Mono> masterReplicaAddressesObs = this.getMasterAddressesViaGatewayAsync( + request, + ResourceType.Database, + null, + databaseFeedEntryUrl, + forceRefresh, + false, + properties); + + return masterReplicaAddressesObs.map( + masterAddresses -> { + Pair masterAddressAndRangeRes = + this.toPartitionAddressAndRange("", masterAddresses); + this.masterPartitionAddressCache = masterAddressAndRangeRes; + + if (notAllReplicasAvailable(masterAddressAndRangeRes.getRight()) + && this.suboptimalMasterPartitionTimestamp.equals(Instant.MAX)) { + this.suboptimalMasterPartitionTimestamp = Instant.now(); + } else { + this.suboptimalMasterPartitionTimestamp = Instant.MAX; + } + + return masterPartitionAddressCache; + }) + .doOnError( + e -> { + this.suboptimalMasterPartitionTimestamp = Instant.MAX; + }); + } else { + if (notAllReplicasAvailable(masterAddressAndRangeInitial.getRight()) + && this.suboptimalMasterPartitionTimestamp.equals(Instant.MAX)) { + this.suboptimalMasterPartitionTimestamp = Instant.now(); + } + + return Mono.just(masterAddressAndRangeInitial); + } + } + + private Mono getAddressesForRangeId( + RxDocumentServiceRequest request, + String collectionRid, + String partitionKeyRangeId, + boolean forceRefresh) { + Mono> addressResponse = this.getServerAddressesViaGatewayAsync(request, collectionRid, Collections.singletonList(partitionKeyRangeId), forceRefresh); + + Mono>> addressInfos = + addressResponse.map( + addresses -> + addresses.stream().filter(addressInfo -> + this.protocolScheme.equals(addressInfo.getProtocolScheme())) + .collect(Collectors.groupingBy( + Address::getParitionKeyRangeId)) + .values().stream() + .map(groupedAddresses -> toPartitionAddressAndRange(collectionRid, addresses)) + .collect(Collectors.toList())); + + Mono>> result = addressInfos.map(addressInfo -> addressInfo.stream() + .filter(a -> + StringUtils.equals(a.getLeft().getPartitionKeyRangeId(), partitionKeyRangeId)) + .collect(Collectors.toList())); + + return result.flatMap( + list -> { + if (list.isEmpty()) { + + String errorMessage = String.format( + RMResources.PartitionKeyRangeNotFound, + partitionKeyRangeId, + collectionRid); + + PartitionKeyRangeGoneException e = new PartitionKeyRangeGoneException(errorMessage); + BridgeInternal.setResourceAddress(e, collectionRid); + + return Mono.error(e); + } else { + return Mono.just(list.get(0).getRight()); + } + }); + } + + public Mono> getMasterAddressesViaGatewayAsync( + RxDocumentServiceRequest request, + ResourceType resourceType, + String resourceAddress, + String entryUrl, + boolean forceRefresh, + boolean useMasterCollectionResolver, + Map properties) { + HashMap queryParameters = new HashMap<>(); + queryParameters.put(HttpConstants.QueryStrings.URL, HttpUtils.urlEncode(entryUrl)); + HashMap headers = new HashMap<>(defaultRequestHeaders); + + if (forceRefresh) { + headers.put(HttpConstants.HttpHeaders.FORCE_REFRESH, Boolean.TRUE.toString()); + } + + if (useMasterCollectionResolver) { + headers.put(HttpConstants.HttpHeaders.USE_MASTER_COLLECTION_RESOLVER, Boolean.TRUE.toString()); + } + + queryParameters.put(HttpConstants.QueryStrings.FILTER, HttpUtils.urlEncode(this.protocolFilter)); + headers.put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + String token = this.tokenProvider.getUserAuthorizationToken( + resourceAddress, + resourceType, + HttpConstants.HttpMethods.GET, + headers, + AuthorizationTokenType.PrimaryMasterKey, + properties); + + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, HttpUtils.urlEncode(token)); + URL targetEndpoint = Utils.setQuery(this.addressEndpoint.toString(), Utils.createQuery(queryParameters)); + String identifier = logAddressResolutionStart(request, targetEndpoint); + + HttpHeaders defaultHttpHeaders = new HttpHeaders(headers.size()); + for (Map.Entry entry : headers.entrySet()) { + defaultHttpHeaders.set(entry.getKey(), entry.getValue()); + } + + HttpRequest httpRequest; + try { + httpRequest = new HttpRequest(HttpMethod.GET, targetEndpoint.toURI(), targetEndpoint.getPort(), defaultHttpHeaders); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(targetEndpoint.toString(), e); + } + + Mono httpResponseMono = this.httpClient.send(httpRequest); + Mono dsrObs = HttpClientUtils.parseResponseAsync(httpResponseMono, httpRequest); + + return dsrObs.map( + dsr -> { + logAddressResolutionEnd(request, identifier); + return dsr.getQueryResponse(Address.class); + }); + } + + private Pair toPartitionAddressAndRange(String collectionRid, List

    addresses) { + Address address = addresses.get(0); + + AddressInformation[] addressInfos = + addresses.stream().map(addr -> + GatewayAddressCache.toAddressInformation(addr) + ).collect(Collectors.toList()).toArray(new AddressInformation[addresses.size()]); + return Pair.of(new PartitionKeyRangeIdentity(collectionRid, address.getParitionKeyRangeId()), addressInfos); + } + + private static AddressInformation toAddressInformation(Address address) { + return new AddressInformation(true, address.IsPrimary(), address.getPhyicalUri(), address.getProtocolScheme()); + } + + public Mono openAsync( + DocumentCollection collection, + List partitionKeyRangeIdentities) { + List>> tasks = new ArrayList<>(); + int batchSize = GatewayAddressCache.DefaultBatchSize; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + OperationType.Read, + // collection.AltLink, + collection.resourceId(), + ResourceType.DocumentCollection, + // AuthorizationTokenType.PrimaryMasterKey + Collections.emptyMap()); + for (int i = 0; i < partitionKeyRangeIdentities.size(); i += batchSize) { + + int endIndex = i + batchSize; + endIndex = endIndex < partitionKeyRangeIdentities.size() + ? endIndex : partitionKeyRangeIdentities.size(); + + tasks.add(this.getServerAddressesViaGatewayAsync( + request, + collection.resourceId(), + + partitionKeyRangeIdentities.subList(i, endIndex). + stream().map(PartitionKeyRangeIdentity::getPartitionKeyRangeId).collect(Collectors.toList()), + false).flux()); + } + + return Flux.concat(tasks) + .doOnNext(list -> { + List> addressInfos = list.stream() + .filter(addressInfo -> this.protocolScheme.equals(addressInfo.getProtocolScheme())) + .collect(Collectors.groupingBy(Address::getParitionKeyRangeId)) + .values().stream().map(addresses -> toPartitionAddressAndRange(collection.resourceId(), addresses)) + .collect(Collectors.toList()); + + for (Pair addressInfo : addressInfos) { + this.serverPartitionAddressCache.set( + new PartitionKeyRangeIdentity(collection.resourceId(), addressInfo.getLeft().getPartitionKeyRangeId()), + addressInfo.getRight()); + } + }).then(); + } + + private boolean notAllReplicasAvailable(AddressInformation[] addressInformations) { + return addressInformations.length < ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize; + } + + private static String logAddressResolutionStart(RxDocumentServiceRequest request, URL targetEndpointUrl) { + try { + if (request.requestContext.cosmosResponseDiagnostics != null) { + return BridgeInternal.recordAddressResolutionStart(request.requestContext.cosmosResponseDiagnostics, targetEndpointUrl.toURI()); + } + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + return null; + } + + private static void logAddressResolutionEnd(RxDocumentServiceRequest request, String identifier) { + if (request.requestContext.cosmosResponseDiagnostics != null) { + BridgeInternal.recordAddressResolutionEnd(request.requestContext.cosmosResponseDiagnostics, identifier); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReader.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReader.java new file mode 100644 index 0000000000000..e02e7ef88b20b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReader.java @@ -0,0 +1,182 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.BaseAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.GlobalEndpointManager; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.ReplicationPolicy; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.handler.codec.http.HttpMethod; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * This class will read the service configuration from the gateway. + * + * As .Net does code sharing between the SDK and GW there are two implementation to IServiceConfigurationReader + * GatewayServiceConfigurationReader which is for SDK + * DatabaseAccountConfigurationReader which is for GW + * Some of the APIs are not relevant in SDK and due to that in .Net the SDK implementation one throws not-implemented. + * + * In java, as we don't do code sharing + * and we got rid of the interface which is not needed and only implemented the methods in GatewayServiceConfigurationReader + */ +public class GatewayServiceConfigurationReader { + + public static final String GATEWAY_READER_NOT_INITIALIZED = "GatewayServiceConfigurationReader has not been initialized"; + + public ReplicationPolicy userReplicationPolicy; + private ReplicationPolicy systemReplicationPolicy; + private ConsistencyLevel consistencyLevel; + private volatile boolean initialized; + private URI serviceEndpoint; + private final ConnectionPolicy connectionPolicy; + private Map queryEngineConfiguration; + private final BaseAuthorizationTokenProvider baseAuthorizationTokenProvider; + private final boolean hasAuthKeyResourceToken; + private final String authKeyResourceToken; + private HttpClient httpClient; + + public GatewayServiceConfigurationReader(URI serviceEndpoint, boolean hasResourceToken, String resourceToken, + ConnectionPolicy connectionPolicy, BaseAuthorizationTokenProvider baseAuthorizationTokenProvider, + HttpClient httpClient) { + this.serviceEndpoint = serviceEndpoint; + this.baseAuthorizationTokenProvider = baseAuthorizationTokenProvider; + this.hasAuthKeyResourceToken = hasResourceToken; + this.authKeyResourceToken = resourceToken; + this.connectionPolicy = connectionPolicy; + this.httpClient = httpClient; + } + + public ReplicationPolicy getUserReplicationPolicy() { + this.throwIfNotInitialized(); + return this.userReplicationPolicy; + } + + public ReplicationPolicy getSystemReplicationPolicy() { + this.throwIfNotInitialized(); + return this.systemReplicationPolicy; + } + + public boolean enableAuthorization() { + return true; + } + + public ConsistencyLevel getDefaultConsistencyLevel() { + this.throwIfNotInitialized(); + return this.consistencyLevel; + } + + public void setDefaultConsistencyLevel(ConsistencyLevel value) { + this.throwIfNotInitialized(); + this.consistencyLevel = value; + } + + public Map getQueryEngineConfiguration() { + this.throwIfNotInitialized(); + return this.queryEngineConfiguration; + } + + private Mono getDatabaseAccountAsync(URI serviceEndpoint) { + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.set(HttpConstants.HttpHeaders.VERSION, HttpConstants.Versions.CURRENT_VERSION); + + UserAgentContainer userAgentContainer = new UserAgentContainer(); + String userAgentSuffix = this.connectionPolicy.userAgentSuffix(); + if (userAgentSuffix != null && userAgentSuffix.length() > 0) { + userAgentContainer.setSuffix(userAgentSuffix); + } + + httpHeaders.set(HttpConstants.HttpHeaders.USER_AGENT, userAgentContainer.getUserAgent()); + httpHeaders.set(HttpConstants.HttpHeaders.API_TYPE, Constants.Properties.SQL_API_TYPE); + String authorizationToken; + if (this.hasAuthKeyResourceToken || baseAuthorizationTokenProvider == null) { + authorizationToken = HttpUtils.urlEncode(this.authKeyResourceToken); + } else { + // Retrieve the document service properties. + String xDate = Utils.nowAsRFC1123(); + httpHeaders.set(HttpConstants.HttpHeaders.X_DATE, xDate); + Map header = new HashMap<>(); + header.put(HttpConstants.HttpHeaders.X_DATE, xDate); + authorizationToken = baseAuthorizationTokenProvider + .generateKeyAuthorizationSignature(HttpConstants.HttpMethods.GET, serviceEndpoint, header); + } + httpHeaders.set(HttpConstants.HttpHeaders.AUTHORIZATION, authorizationToken); + + HttpRequest httpRequest = new HttpRequest(HttpMethod.GET, serviceEndpoint, serviceEndpoint.getPort(), httpHeaders); + Mono httpResponse = httpClient.send(httpRequest); + return toDatabaseAccountObservable(httpResponse, httpRequest); + } + + public Mono initializeReaderAsync() { + try { + return GlobalEndpointManager.getDatabaseAccountFromAnyLocationsAsync(this.serviceEndpoint.toURL(), + + new ArrayList<>(this.connectionPolicy.preferredLocations()), url -> { + try { + return getDatabaseAccountAsync(url.toURI()); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("URI " + url); + } + }).doOnSuccess(databaseAccount -> { + userReplicationPolicy = databaseAccount.getReplicationPolicy(); + systemReplicationPolicy = databaseAccount.getSystemReplicationPolicy(); + queryEngineConfiguration = databaseAccount.getQueryEngineConfiuration(); + consistencyLevel = databaseAccount.getConsistencyPolicy().defaultConsistencyLevel(); + initialized = true; + }); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(this.serviceEndpoint.toString(), e); + } + } + + private Mono toDatabaseAccountObservable(Mono httpResponse, HttpRequest httpRequest) { + + return HttpClientUtils.parseResponseAsync(httpResponse, httpRequest) + .map(rxDocumentServiceResponse -> rxDocumentServiceResponse.getResource(DatabaseAccount.class)); + } + + private void throwIfNotInitialized() { + if (!this.initialized) { + throw new IllegalArgumentException(GATEWAY_READER_NOT_INITIALIZED); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolver.java new file mode 100644 index 0000000000000..0e5b8f918317e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolver.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.GlobalEndpointManager; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.caches.RxPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +; + +public class GlobalAddressResolver implements IAddressResolver { + private final static int MaxBackupReadRegions = 3; + private final GlobalEndpointManager endpointManager; + private final Protocol protocol; + private final IAuthorizationTokenProvider tokenProvider; + private final UserAgentContainer userAgentContainer; + private final RxCollectionCache collectionCache; + private final RxPartitionKeyRangeCache routingMapProvider; + private final int maxEndpoints; + private final GatewayServiceConfigurationReader serviceConfigReader; + final Map addressCacheByEndpoint; + + private GatewayAddressCache gatewayAddressCache; + private AddressResolver addressResolver; + private HttpClient httpClient; + + public GlobalAddressResolver( + HttpClient httpClient, + GlobalEndpointManager endpointManager, + Protocol protocol, + IAuthorizationTokenProvider tokenProvider, + RxCollectionCache collectionCache, + RxPartitionKeyRangeCache routingMapProvider, + UserAgentContainer userAgentContainer, + GatewayServiceConfigurationReader serviceConfigReader, + ConnectionPolicy connectionPolicy) { + + this.httpClient = httpClient; + this.endpointManager = endpointManager; + this.protocol = protocol; + this.tokenProvider = tokenProvider; + this.userAgentContainer = userAgentContainer; + this.collectionCache = collectionCache; + this.routingMapProvider = routingMapProvider; + this.serviceConfigReader = serviceConfigReader; + + int maxBackupReadEndpoints = (connectionPolicy.enableReadRequestsFallback() == null || connectionPolicy.enableReadRequestsFallback()) ? GlobalAddressResolver.MaxBackupReadRegions : 0; + this.maxEndpoints = maxBackupReadEndpoints + 2; // for write and alternate write endpoint (during failover) + this.addressCacheByEndpoint = new ConcurrentHashMap<>(); + + for (URL endpoint : endpointManager.getWriteEndpoints()) { + this.getOrAddEndpoint(endpoint); + } + for (URL endpoint : endpointManager.getReadEndpoints()) { + this.getOrAddEndpoint(endpoint); + } + } + + Mono openAsync(DocumentCollection collection) { + Mono routingMap = this.routingMapProvider.tryLookupAsync(collection.id(), null, null); + return routingMap.flatMap(collectionRoutingMap -> { + + List ranges = ((List)collectionRoutingMap.getOrderedPartitionKeyRanges()).stream().map(range -> + new PartitionKeyRangeIdentity(collection.resourceId(), range.id())).collect(Collectors.toList()); + List> tasks = new ArrayList<>(); + for (EndpointCache endpointCache : this.addressCacheByEndpoint.values()) { + tasks.add(endpointCache.addressCache.openAsync(collection, ranges)); + } + // TODO: Not sure if this will work. + return Mono.whenDelayError(tasks); + }).switchIfEmpty(Mono.defer(Mono::empty)); + } + + @Override + public Mono resolveAsync(RxDocumentServiceRequest request, boolean forceRefresh) { + IAddressResolver resolver = this.getAddressResolver(request); + return resolver.resolveAsync(request, forceRefresh); + } + + public void dispose() { + for (EndpointCache endpointCache : this.addressCacheByEndpoint.values()) { + endpointCache.addressCache.dispose(); + } + } + + private IAddressResolver getAddressResolver(RxDocumentServiceRequest rxDocumentServiceRequest) { + URL endpoint = this.endpointManager.resolveServiceEndpoint(rxDocumentServiceRequest); + return this.getOrAddEndpoint(endpoint).addressResolver; + } + + private EndpointCache getOrAddEndpoint(URL endpoint) { + EndpointCache endpointCache = this.addressCacheByEndpoint.computeIfAbsent(endpoint , key -> { + GatewayAddressCache gatewayAddressCache = new GatewayAddressCache(endpoint, protocol, this.tokenProvider, this.userAgentContainer, this.httpClient); + AddressResolver addressResolver = new AddressResolver(); + addressResolver.initializeCaches(this.collectionCache, this.routingMapProvider, gatewayAddressCache); + EndpointCache cache = new EndpointCache(); + cache.addressCache = gatewayAddressCache; + cache.addressResolver = addressResolver; + return cache; + }); + + if (this.addressCacheByEndpoint.size() > this.maxEndpoints) { + List allEndpoints = new ArrayList(this.endpointManager.getWriteEndpoints()); + allEndpoints.addAll(this.endpointManager.getReadEndpoints()); + Collections.reverse(allEndpoints); + LinkedList endpoints = new LinkedList<>(allEndpoints); + while (this.addressCacheByEndpoint.size() > this.maxEndpoints) { + if (endpoints.size() > 0) { + URL dequeueEnpoint = endpoints.pop(); + if (this.addressCacheByEndpoint.get(dequeueEnpoint) != null) { + this.addressCacheByEndpoint.remove(dequeueEnpoint); + } + } else { + break; + } + } + } + return endpointCache; + } + + static class EndpointCache { + GatewayAddressCache addressCache; + AddressResolver addressResolver; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicy.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicy.java new file mode 100644 index 0000000000000..5cfeb3ae1cea4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicy.java @@ -0,0 +1,215 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.RetryWithException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IRetryPolicy; +import com.azure.data.cosmos.internal.Quadruple; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.apache.commons.lang3.time.StopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +public class GoneAndRetryWithRetryPolicy implements IRetryPolicy { + + private final static Logger logger = LoggerFactory.getLogger(GoneAndRetryWithRetryPolicy.class); + private final static int DEFAULT_WAIT_TIME_IN_SECONDS = 30; + private final static int MAXIMUM_BACKOFF_TIME_IN_SECONDS = 15; + private final static int INITIAL_BACKOFF_TIME = 1; + private final static int BACK_OFF_MULTIPLIER = 2; + + private final RxDocumentServiceRequest request; + private volatile int attemptCount = 1; + private volatile int attemptCountInvalidPartition = 1; + private volatile int currentBackoffSeconds = GoneAndRetryWithRetryPolicy.INITIAL_BACKOFF_TIME; + private volatile RetryWithException lastRetryWithException; + private final StopWatch durationTimer = new StopWatch(); + private final int waitTimeInSeconds; + //TODO once this is moved to IRetryPolicy, remove from here. + public static Quadruple INITIAL_ARGUMENT_VALUE_POLICY_ARG = Quadruple.with(false, false, + Duration.ofSeconds(60), 0); + + public GoneAndRetryWithRetryPolicy(RxDocumentServiceRequest request, Integer waitTimeInSeconds) { + this.request = request; + startStopWatch(this.durationTimer); + if (waitTimeInSeconds != null) { + this.waitTimeInSeconds = waitTimeInSeconds; + } else { + this.waitTimeInSeconds = DEFAULT_WAIT_TIME_IN_SECONDS; + } + } + + @Override + public Mono shouldRetry(Exception exception) { + CosmosClientException exceptionToThrow = null; + Duration backoffTime = Duration.ofSeconds(0); + Duration timeout = Duration.ofSeconds(0); + boolean forceRefreshAddressCache = false; + if (!(exception instanceof GoneException) && + !(exception instanceof RetryWithException) && + !(exception instanceof PartitionIsMigratingException) && + !(exception instanceof InvalidPartitionException && + (this.request.getPartitionKeyRangeIdentity() == null || + this.request.getPartitionKeyRangeIdentity().getCollectionRid() == null)) && + !(exception instanceof PartitionKeyRangeIsSplittingException)) { + logger.debug("Operation will NOT be retried. Current attempt {}, Exception: {} ", this.attemptCount, + exception); + stopStopWatch(this.durationTimer); + return Mono.just(ShouldRetryResult.noRetry()); + } else if (exception instanceof RetryWithException) { + this.lastRetryWithException = (RetryWithException) exception; + } + long remainingSeconds = this.waitTimeInSeconds - this.durationTimer.getTime() / 1000; + int currentRetryAttemptCount = this.attemptCount; + if (this.attemptCount++ > 1) { + if (remainingSeconds <= 0) { + if (exception instanceof GoneException) { + if (this.lastRetryWithException != null) { + logger.warn( + "Received gone exception after backoff/retry including at least one RetryWithException. " + + "Will fail the request with RetryWithException. GoneException: {}. RetryWithException: {}", + exception, this.lastRetryWithException); + exceptionToThrow = this.lastRetryWithException; + } else { + logger.warn("Received gone exception after backoff/retry. Will fail the request. {}", + exception.toString()); + exceptionToThrow = BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.SERVICE_UNAVAILABLE, + exception); + } + + } else if (exception instanceof PartitionKeyRangeGoneException) { + if (this.lastRetryWithException != null) { + logger.warn( + "Received partition key range gone exception after backoff/retry including at least one RetryWithException." + + "Will fail the request with RetryWithException. GoneException: {}. RetryWithException: {}", + exception, this.lastRetryWithException); + exceptionToThrow = this.lastRetryWithException; + } else { + logger.warn( + "Received partition key range gone exception after backoff/retry. Will fail the request. {}", + exception.toString()); + exceptionToThrow = BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.SERVICE_UNAVAILABLE, + exception); + } + } else if (exception instanceof InvalidPartitionException) { + if (this.lastRetryWithException != null) { + logger.warn( + "Received InvalidPartitionException after backoff/retry including at least one RetryWithException. " + + "Will fail the request with RetryWithException. InvalidPartitionException: {}. RetryWithException: {}", + exception, this.lastRetryWithException); + } else { + logger.warn( + "Received invalid collection partition exception after backoff/retry. Will fail the request. {}", + exception.toString()); + exceptionToThrow = BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.SERVICE_UNAVAILABLE, + exception); + } + } else { + logger.warn("Received retrywith exception after backoff/retry. Will fail the request. {}", + exception.toString()); + } + stopStopWatch(this.durationTimer); + return Mono.just(ShouldRetryResult.error(exceptionToThrow)); + } + backoffTime = Duration.ofSeconds(Math.min(Math.min(this.currentBackoffSeconds, remainingSeconds), + GoneAndRetryWithRetryPolicy.MAXIMUM_BACKOFF_TIME_IN_SECONDS)); + this.currentBackoffSeconds *= GoneAndRetryWithRetryPolicy.BACK_OFF_MULTIPLIER; + logger.info("BackoffTime: {} seconds.", backoffTime.getSeconds()); + } + + // Calculate the remaining time based after accounting for the backoff that we + // will perform + long timeoutInMillSec = remainingSeconds*1000 - backoffTime.toMillis(); + timeout = timeoutInMillSec > 0 ? Duration.ofMillis(timeoutInMillSec) + : Duration.ofSeconds(GoneAndRetryWithRetryPolicy.MAXIMUM_BACKOFF_TIME_IN_SECONDS); + if (exception instanceof GoneException) { + logger.warn("Received gone exception, will retry, {}", exception.toString()); + forceRefreshAddressCache = true; // indicate we are in retry. + } else if (exception instanceof PartitionIsMigratingException) { + logger.warn("Received PartitionIsMigratingException, will retry, {}", exception.toString()); + this.request.forceCollectionRoutingMapRefresh = true; + forceRefreshAddressCache = true; + } else if (exception instanceof InvalidPartitionException) { + this.request.requestContext.quorumSelectedLSN = -1; + this.request.requestContext.resolvedPartitionKeyRange = null; + this.request.requestContext.quorumSelectedStoreResponse = null; + this.request.requestContext.globalCommittedSelectedLSN = -1; + if (this.attemptCountInvalidPartition++ > 2) { + // for second InvalidPartitionException, stop retrying. + logger.warn("Received second InvalidPartitionException after backoff/retry. Will fail the request. {}", + exception.toString()); + return Mono.just(ShouldRetryResult + .error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.SERVICE_UNAVAILABLE, exception))); + } + + if (this.request != null) { + logger.warn("Received invalid collection exception, will retry, {}", exception.toString()); + this.request.forceNameCacheRefresh = true; + } else { + logger.error("Received unexpected invalid collection exception, request should be non-null.", + exception); + return Mono.just(ShouldRetryResult + .error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR, exception))); + } + forceRefreshAddressCache = false; + } else if (exception instanceof PartitionKeyRangeIsSplittingException) { + this.request.requestContext.resolvedPartitionKeyRange = null; + this.request.requestContext.quorumSelectedLSN = -1; + this.request.requestContext.quorumSelectedStoreResponse = null; + logger.info("Received partition key range splitting exception, will retry, {}", exception.toString()); + this.request.forcePartitionKeyRangeRefresh = true; + forceRefreshAddressCache = false; + } else { + logger.warn("Received retrywith exception, will retry, {}", exception); + // For RetryWithException, prevent the caller + // from refreshing any caches. + forceRefreshAddressCache = false; + } + return Mono.just(ShouldRetryResult.retryAfter(backoffTime, + Quadruple.with(forceRefreshAddressCache, true, timeout, currentRetryAttemptCount))); + } + + private void stopStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.stop(); + } + } + + private void startStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.start(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientUtils.java new file mode 100644 index 0000000000000..87e53b3647c40 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientUtils.java @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import reactor.core.publisher.Mono; + +public class HttpClientUtils { + + static Mono parseResponseAsync(Mono httpResponse, HttpRequest httpRequest) { + return httpResponse.flatMap(response -> { + if (response.statusCode() < HttpConstants.StatusCodes.MINIMUM_STATUSCODE_AS_ERROR_GATEWAY) { + + return ResponseUtils.toStoreResponse(response, httpRequest).map(RxDocumentServiceResponse::new); + + // TODO: to break the dependency between RxDocumentServiceResponse and StoreResponse + // we should factor out the RxDocumentServiceResponse(StoreResponse) constructor to a helper class + + } else { + return HttpClientUtils + .createDocumentClientException(response).flatMap(Mono::error); + } + }); + } + + private static Mono createDocumentClientException(HttpResponse httpResponse) { + Mono readStream = ResponseUtils.toString(httpResponse.body()); + + return readStream.map(body -> { + CosmosError cosmosError = BridgeInternal.createCosmosError(body); + + // TODO: we should set resource address in the Document Client Exception + return BridgeInternal.createCosmosClientException(httpResponse.statusCode(), cosmosError, + httpResponse.headers().toMap()); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClient.java new file mode 100644 index 0000000000000..8e1cbdad9cdc5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClient.java @@ -0,0 +1,995 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConflictException; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.ForbiddenException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.LockedException; +import com.azure.data.cosmos.MethodNotAllowedException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.PreconditionFailedException; +import com.azure.data.cosmos.RequestEntityTooLargeException; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.RetryWithException; +import com.azure.data.cosmos.ServiceUnavailableException; +import com.azure.data.cosmos.UnauthorizedException; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Integers; +import com.azure.data.cosmos.internal.Lists; +import com.azure.data.cosmos.internal.Longs; +import com.azure.data.cosmos.internal.MutableVolatile; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RuntimeConstants; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpClientConfig; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.time.Instant; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static com.azure.data.cosmos.internal.Utils.trimBeginningAndEndingSlashes; +/* + * The following code only support Document Write without any error handling support. + */ +public class HttpTransportClient extends TransportClient { + private final Logger logger = LoggerFactory.getLogger(HttpTransportClient.class); + private final HttpClient httpClient; + private final Map defaultHeaders; + private final Configs configs; + + HttpClient createHttpClient(int requestTimeout) { + // TODO: use one instance of SSL context everywhere + HttpClientConfig httpClientConfig = new HttpClientConfig(this.configs); + httpClientConfig.withRequestTimeoutInMillis(requestTimeout * 1000); + httpClientConfig.withPoolSize(configs.getDirectHttpsMaxConnectionLimit()); + + return HttpClient.createFixed(httpClientConfig); + } + + public HttpTransportClient(Configs configs, int requestTimeout, UserAgentContainer userAgent) { + this.configs = configs; + this.httpClient = createHttpClient(requestTimeout); + + this.defaultHeaders = new HashMap<>(); + + // Set requested API version header for version enforcement. + this.defaultHeaders.put(HttpConstants.HttpHeaders.VERSION, HttpConstants.Versions.CURRENT_VERSION); + this.defaultHeaders.put(HttpConstants.HttpHeaders.CACHE_CONTROL, HttpConstants.HeaderValues.NoCache); + + if (userAgent == null) { + userAgent = new UserAgentContainer(); + } + + this.defaultHeaders.put(HttpConstants.HttpHeaders.USER_AGENT, userAgent.getUserAgent()); + this.defaultHeaders.put(HttpConstants.HttpHeaders.ACCEPT, RuntimeConstants.MediaTypes.JSON); + } + + @Override + public void close() { + httpClient.shutdown(); + } + + public Mono invokeStoreAsync( + URI physicalAddress, + RxDocumentServiceRequest request) { + + try { + ResourceOperation resourceOperation = new ResourceOperation(request.getOperationType(), request.getResourceType()); + // uuid correlation manager + UUID activityId = UUID.fromString(request.getActivityId()); + + if (resourceOperation.operationType == OperationType.Recreate) { + Map errorResponseHeaders = new HashMap<>(); + errorResponseHeaders.put(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "1"); + + logger.error("Received Recreate request on Http client"); + throw new InternalServerErrorException(RMResources.InternalServerError, null, errorResponseHeaders, null); + } + + HttpRequest httpRequest = prepareHttpMessage(activityId, physicalAddress, resourceOperation, request); + + MutableVolatile sendTimeUtc = new MutableVolatile<>(); + + Mono httpResponseMono = this.httpClient + .send(httpRequest) + .doOnSubscribe(subscription -> { + sendTimeUtc.v = Instant.now(); + this.beforeRequest( + activityId, + httpRequest.uri(), + request.getResourceType(), + httpRequest.headers()); + }) + .onErrorResume(t -> { + Exception exception = Utils.as(t, Exception.class); + if (exception == null) { + logger.error("critical failure", t); + t.printStackTrace(); + assert false : "critical failure"; + return Mono.error(t); + } + + //Trace.CorrelationManager.ActivityId = activityId; + if (WebExceptionUtility.isWebExceptionRetriable(exception)) { + logger.debug("Received retriable exception {} " + + "sending the request to {}, will re-resolve the address " + + "send time UTC: {}", + exception, + physicalAddress, + sendTimeUtc); + + GoneException goneException = new GoneException( + String.format( + RMResources.ExceptionMessage, + RMResources.Gone), + exception, + null, + physicalAddress); + + return Mono.error(goneException); + } else if (request.isReadOnlyRequest()) { + logger.trace("Received exception {} on readonly request" + + "sending the request to {}, will reresolve the address " + + "send time UTC: {}", + exception, + physicalAddress, + sendTimeUtc); + + GoneException goneException = new GoneException( + String.format( + RMResources.ExceptionMessage, + RMResources.Gone), + exception, + null, + physicalAddress); + + return Mono.error(goneException); + } else { + // We can't throw a GoneException here because it will cause retry and we don't + // know if the request failed before or after the message got sent to the server. + // So in order to avoid duplicating the request we will not retry. + // TODO: a possible solution for this is to add the ability to send a request to the server + // to check if the previous request was received or not and act accordingly. + ServiceUnavailableException serviceUnavailableException = new ServiceUnavailableException( + String.format( + RMResources.ExceptionMessage, + RMResources.ServiceUnavailable), + exception, + null, + physicalAddress.toString()); + serviceUnavailableException.responseHeaders().put(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "1"); + serviceUnavailableException.responseHeaders().put(HttpConstants.HttpHeaders.WRITE_REQUEST_TRIGGER_ADDRESS_REFRESH, "1"); + return Mono.error(serviceUnavailableException); + }}) + .doOnSuccess(httpClientResponse -> { + Instant receivedTimeUtc = Instant.now(); + double durationInMilliSeconds = (receivedTimeUtc.toEpochMilli() - sendTimeUtc.v.toEpochMilli()); + this.afterRequest( + activityId, + httpClientResponse.statusCode(), + durationInMilliSeconds, + httpClientResponse.headers()); + }) + .doOnError(e -> { + Instant receivedTimeUtc = Instant.now(); + double durationInMilliSeconds = (receivedTimeUtc.toEpochMilli() - sendTimeUtc.v.toEpochMilli()); + this.afterRequest( + activityId, + 0, + durationInMilliSeconds, + null); + }); + + return httpResponseMono.flatMap(rsp -> processHttpResponse(request.getResourceAddress(), + httpRequest, activityId.toString(), rsp, physicalAddress)); + + } catch (Exception e) { + return Mono.error(e); + } + } + + private void beforeRequest(UUID activityId, URI uri, ResourceType resourceType, HttpHeaders requestHeaders) { + // TODO: perf counters + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + } + + private void afterRequest(UUID activityId, + int statusCode, + double durationInMilliSeconds, + HttpHeaders responseHeaders) { + // TODO: perf counters + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + } + + private static void addHeader(HttpHeaders requestHeaders, String headerName, RxDocumentServiceRequest request) { + String headerValue = request.getHeaders().get(headerName); + if (!Strings.isNullOrEmpty(headerValue)) { + requestHeaders.set(headerName, headerValue); + } + } + + private static void addHeader(HttpHeaders requestHeaders, String headerName, String headerValue) { + if (!Strings.isNullOrEmpty(headerValue)) { + requestHeaders.set(headerName, headerValue); + } + } + + private String getMatch(RxDocumentServiceRequest request, ResourceOperation resourceOperation) { + switch (resourceOperation.operationType) { + case Delete: + case ExecuteJavaScript: + case Replace: + case Update: + case Upsert: + return request.getHeaders().get(HttpConstants.HttpHeaders.IF_MATCH); + + case Read: + case ReadFeed: + return request.getHeaders().get(HttpConstants.HttpHeaders.IF_NONE_MATCH); + + default: + return null; + } + } + + private HttpRequest prepareHttpMessage( + UUID activityId, + URI physicalAddress, + ResourceOperation resourceOperation, + RxDocumentServiceRequest request) throws Exception { + + HttpRequest httpRequestMessage; + URI requestUri; + HttpMethod method; + + // The StreamContent created below will own and dispose its underlying stream, but we may need to reuse the stream on the + // RxDocumentServiceRequest for future requests. Hence we need to clone without incurring copy cost, so that when + // HttpRequestMessage -> StreamContent -> MemoryStream all get disposed, the original stream will be left open. + switch (resourceOperation.operationType) { + case Create: + requestUri = getResourceFeedUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.POST; + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + break; + + case ExecuteJavaScript: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.POST; + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + break; + + case Delete: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.DELETE; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + break; + + case Read: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.GET; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + break; + + case ReadFeed: + requestUri = getResourceFeedUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.GET; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + break; + + case Replace: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.PUT; + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + break; + + case Update: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = new HttpMethod("PATCH"); + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + break; + + case Query: + case SqlQuery: + requestUri = getResourceFeedUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.POST; + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + HttpTransportClient.addHeader(httpRequestMessage.headers(), HttpConstants.HttpHeaders.CONTENT_TYPE, request); + break; + + case Upsert: + requestUri = getResourceFeedUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.POST; + assert request.getContent() != null; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + httpRequestMessage.withBody(request.getContent()); + break; + + case Head: + requestUri = getResourceEntryUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.HEAD; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + break; + + case HeadFeed: + requestUri = getResourceFeedUri(resourceOperation.resourceType, physicalAddress, request); + method = HttpMethod.HEAD; + httpRequestMessage = new HttpRequest(method, requestUri.toString(), physicalAddress.getPort()); + break; + + default: + assert false : "Unsupported operation type"; + throw new IllegalStateException(); + } + + Map documentServiceRequestHeaders = request.getHeaders(); + HttpHeaders httpRequestHeaders = httpRequestMessage.headers(); + + // add default headers + for(Map.Entry entry: defaultHeaders.entrySet()) { + HttpTransportClient.addHeader(httpRequestHeaders, entry.getKey(), entry.getValue()); + } + + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.VERSION, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.USER_AGENT, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PAGE_SIZE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PRE_TRIGGER_INCLUDE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PRE_TRIGGER_EXCLUDE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POST_TRIGGER_INCLUDE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POST_TRIGGER_EXCLUDE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.AUTHORIZATION, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.INDEXING_DIRECTIVE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.MIGRATE_COLLECTION_DIRECTIVE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.SESSION_TOKEN, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PREFER, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.RESOURCE_TOKEN_EXPIRY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.ENABLE_SCAN_IN_QUERY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.EMIT_VERBOSE_TRACES_IN_QUERY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CAN_CHARGE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CAN_THROTTLE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.ENABLE_LOW_PRECISION_ORDER_BY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.ENABLE_LOGGING, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.IS_READ_ONLY_SCRIPT, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CONTENT_SERIALIZATION_FORMAT, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CONTINUATION, request.getContinuation()); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.ACTIVITY_ID, activityId.toString()); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PARTITION_KEY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.PARTITION_KEY_RANGE_ID, request); + + String dateHeader = HttpUtils.getDateHeader(documentServiceRequestHeaders); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.X_DATE, dateHeader); + HttpTransportClient.addHeader(httpRequestHeaders, "Match", this.getMatch(request, resourceOperation)); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.IF_MODIFIED_SINCE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.A_IM, request); + if (!request.getIsNameBased()) { + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.RESOURCE_ID, request.getResourceId()); + } + + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.ENTITY_ID, request.entityId); + + String fanoutRequestHeader = request.getHeaders().get(WFConstants.BackendHeaders.IS_FANOUT_REQUEST); + HttpTransportClient.addHeader(httpRequestMessage.headers(), WFConstants.BackendHeaders.IS_FANOUT_REQUEST, fanoutRequestHeader); + + if (request.getResourceType() == ResourceType.DocumentCollection) { + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.COLLECTION_PARTITION_INDEX, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.COLLECTION_PARTITION_INDEX)); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.COLLECTION_SERVICE_INDEX, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.COLLECTION_SERVICE_INDEX)); + } + + if (documentServiceRequestHeaders.get(WFConstants.BackendHeaders.BIND_REPLICA_DIRECTIVE) != null) { + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.BIND_REPLICA_DIRECTIVE, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.BIND_REPLICA_DIRECTIVE)); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.PRIMARY_MASTER_KEY, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.PRIMARY_MASTER_KEY)); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.SECONDARY_MASTER_KEY, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.SECONDARY_MASTER_KEY)); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.PRIMARY_READONLY_KEY, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.PRIMARY_READONLY_KEY)); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.SECONDARY_READONLY_KEY, documentServiceRequestHeaders.get(WFConstants.BackendHeaders.SECONDARY_READONLY_KEY)); + } + + if (documentServiceRequestHeaders.get(HttpConstants.HttpHeaders.CAN_OFFER_REPLACE_COMPLETE) != null) { + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CAN_OFFER_REPLACE_COMPLETE, documentServiceRequestHeaders.get(HttpConstants.HttpHeaders.CAN_OFFER_REPLACE_COMPLETE)); + } + + //Query + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.IS_QUERY, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.QUERY, request); + + // Upsert + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.IS_UPSERT, request); + + // SupportSpatialLegacyCoordinates + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.SUPPORT_SPATIAL_LEGACY_COORDINATES, request); + + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.PARTITION_COUNT, request); + + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.COLLECTION_RID, request); + + // Filter by schema + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.FILTER_BY_SCHEMA_RESOURCE_ID, request); + + // UsePolygonsSmallerThanAHemisphere + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.USE_POLYGONS_SMALLER_THAN_AHEMISPHERE, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.GATEWAY_SIGNATURE, request); + + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POPULATE_QUOTA_INFO, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POPULATE_QUERY_METRICS, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.FORCE_QUERY_SCAN, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB, request); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.REMOTE_STORAGE_TYPE, request); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.SHARE_THROUGHPUT, request); + + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POPULATE_PARTITION_STATISTICS, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.POPULATE_COLLECTION_THROUGHPUT_INFO, request); + + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.REMAINING_TIME_IN_MS_ON_CLIENT_REQUEST, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.CLIENT_RETRY_ATTEMPT_COUNT, request); + + // target lsn for head requests. + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.TARGET_LSN, request); + HttpTransportClient.addHeader(httpRequestHeaders, HttpConstants.HttpHeaders.TARGET_GLOBAL_COMMITTED_LSN, request); + + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.FEDERATION_ID_FOR_AUTH, request); + + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.FANOUT_OPERATION_STATE, request); + HttpTransportClient.addHeader(httpRequestHeaders, WFConstants.BackendHeaders.ALLOW_TENTATIVE_WRITES, request); + + HttpTransportClient.addHeader(httpRequestHeaders, CustomHeaders.HttpHeaders.EXCLUDE_SYSTEM_PROPERTIES, request); + + return httpRequestMessage; + } + + static URI getResourceFeedUri(ResourceType resourceType, URI physicalAddress, RxDocumentServiceRequest request) throws Exception { + switch (resourceType) { + case Attachment: + return getAttachmentFeedUri(physicalAddress, request); + case DocumentCollection: + return getCollectionFeedUri(physicalAddress, request); + case Conflict: + return getConflictFeedUri(physicalAddress, request); + case Database: + return getDatabaseFeedUri(physicalAddress); + case Document: + return getDocumentFeedUri(physicalAddress, request); + case Permission: + return getPermissionFeedUri(physicalAddress, request); + case StoredProcedure: + return getStoredProcedureFeedUri(physicalAddress, request); + case Trigger: + return getTriggerFeedUri(physicalAddress, request); + case User: + return getUserFeedUri(physicalAddress, request); + + case UserDefinedFunction: + return getUserDefinedFunctionFeedUri(physicalAddress, request); + case Schema: + return getSchemaFeedUri(physicalAddress, request); + case Offer: + return getOfferFeedUri(physicalAddress, request); + +// Other types: Replica, Module, ModuleCommand, Record, UserDefinedType not applicable to SDK. + + default: + assert false : "Unexpected resource type: " + resourceType; + throw new NotFoundException(); + } + } + + private static URI getResourceEntryUri(ResourceType resourceType, URI physicalAddress, RxDocumentServiceRequest request) throws Exception { + switch (resourceType) { + case Attachment: + return getAttachmentEntryUri(physicalAddress, request); + case DocumentCollection: + return getCollectionEntryUri(physicalAddress, request); + case Conflict: + return getConflictEntryUri(physicalAddress, request); + case Database: + return getDatabaseEntryUri(physicalAddress, request); + case Document: + return getDocumentEntryUri(physicalAddress, request); + case Permission: + return getPermissionEntryUri(physicalAddress, request); + case StoredProcedure: + return getStoredProcedureEntryUri(physicalAddress, request); + case Trigger: + return getTriggerEntryUri(physicalAddress, request); + case User: + return getUserEntryUri(physicalAddress, request); + case UserDefinedFunction: + return getUserDefinedFunctionEntryUri(physicalAddress, request); + case Schema: + return getSchemaEntryUri(physicalAddress, request); + case Offer: + return getOfferEntryUri(physicalAddress, request); + +// Other types: Replica, Module, ModuleCommand, Record, UserDefinedType not applicable to SDK. + + default: + assert false: "Unexpected resource type: " + resourceType; + throw new IllegalStateException(); + } + } + + private static URI createURI(URI baseAddress, String resourcePath) { + return baseAddress.resolve(HttpUtils.urlEncode(trimBeginningAndEndingSlashes(resourcePath))); + } + + static URI getRootFeedUri(URI baseAddress) { + return baseAddress; + } + + private static URI getDatabaseFeedUri(URI baseAddress) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Database, StringUtils.EMPTY, true)); + } + + private static URI getDatabaseEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Database, request, false)); + } + + private static URI getCollectionFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.DocumentCollection, request, true)); + } + + private static URI getStoredProcedureFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.StoredProcedure, request, true)); + } + + private static URI getTriggerFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Trigger, request, true)); + } + + private static URI getUserDefinedFunctionFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.UserDefinedFunction, request, true)); + } + + private static URI getCollectionEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.DocumentCollection, request, false)); + } + + private static URI getStoredProcedureEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.StoredProcedure, request, false)); + } + + private static URI getTriggerEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Trigger, request, false)); + } + + private static URI getUserDefinedFunctionEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.UserDefinedFunction, request, false)); + } + + private static URI getDocumentFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Document, request, true)); + } + + private static URI getDocumentEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Document, request, false)); + } + + private static URI getConflictFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Conflict, request, true)); + } + + private static URI getConflictEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Conflict, request, false)); + } + + private static URI getAttachmentFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Attachment, request, true)); + } + + private static URI getAttachmentEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Attachment, request, false)); + } + + private static URI getUserFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.User, request, true)); + } + + private static URI getUserEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.User, request, false)); + } + + private static URI getPermissionFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Permission, request, true)); + } + + private static URI getPermissionEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Permission, request, false)); + } + + private static URI getOfferFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Offer, request, true)); + } + + private static URI getSchemaFeedUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Schema, request, true)); + } + + private static URI getSchemaEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Schema, request, false)); + } + + private static URI getOfferEntryUri(URI baseAddress, RxDocumentServiceRequest request) { + return createURI(baseAddress, PathsHelper.generatePath(ResourceType.Offer, request, false)); + } + + static String getHeader(String[] names, String[] values, String name) { + for (int idx = 0; idx < names.length; idx++) { + if (Strings.areEqual(names[idx], name)) { + return values[idx]; + } + } + + return null; + } + + private Mono processHttpResponse(String resourceAddress, HttpRequest httpRequest, String activityId, HttpResponse response, URI physicalAddress) { + if (response == null) { + InternalServerErrorException exception = + new InternalServerErrorException( + String.format( + RMResources.ExceptionMessage, + RMResources.InvalidBackendResponse), + null, + physicalAddress); + exception.responseHeaders().put(HttpConstants.HttpHeaders.ACTIVITY_ID, + activityId); + exception.responseHeaders().put(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "1"); + + return Mono.error(exception); + } + + // If the status code is < 300 or 304 NotModified (we treat not modified as success) then it means that it's a success code and shouldn't throw. + if (response.statusCode() < HttpConstants.StatusCodes.MINIMUM_STATUSCODE_AS_ERROR_GATEWAY || + response.statusCode() == HttpConstants.StatusCodes.NOT_MODIFIED) { + return ResponseUtils.toStoreResponse(response, httpRequest); + } + else { + return this.createErrorResponseFromHttpResponse(resourceAddress, activityId, httpRequest, response); + } + } + + private Mono createErrorResponseFromHttpResponse(String resourceAddress, String activityId, + HttpRequest request, + HttpResponse response) { + int statusCode = response.statusCode(); + Mono errorMessageObs = ErrorUtils.getErrorResponseAsync(response, request); + + return errorMessageObs.flatMap( + errorMessage -> { + long responseLSN = -1; + + List lsnValues = null; + String[] headerValues = response.headers().values(WFConstants.BackendHeaders.LSN); + if (headerValues != null) { + lsnValues = com.google.common.collect.Lists.newArrayList(headerValues); + } + + if (lsnValues != null) { + String temp = lsnValues.isEmpty() ? null : lsnValues.get(0); + responseLSN = Longs.tryParse(temp, responseLSN); + } + + String responsePartitionKeyRangeId = null; + List partitionKeyRangeIdValues = null; + headerValues = response.headers().values(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID); + if (headerValues != null) { + partitionKeyRangeIdValues = com.google.common.collect.Lists.newArrayList(headerValues); + } + if (partitionKeyRangeIdValues != null) { + responsePartitionKeyRangeId = Lists.firstOrDefault(partitionKeyRangeIdValues, null); + } + + CosmosClientException exception; + + switch (statusCode) { + case HttpConstants.StatusCodes.UNAUTHORIZED: + exception = new UnauthorizedException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Unauthorized : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.FORBIDDEN: + exception = new ForbiddenException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Forbidden : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.NOTFOUND: + // HTTP.SYS returns NotFound (404) if the URI + // is not registered. This is really an indication that + // the replica which registered the URI is not + // available at the server. We detect this case by + // the presence of Content-Type header in the response + // and map it to HTTP Gone (410), which is the more + // appropriate response for this case. + if (response.body() != null && response.headers() != null && response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE) != null && + !Strings.isNullOrEmpty(response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE)) && + Strings.containsIgnoreCase(response.headers().value(HttpConstants.HttpHeaders.CONTENT_TYPE), RuntimeConstants.MediaTypes.TEXT_HTML)) { + // Have the request URL in the exception message for debugging purposes. + exception = new GoneException( + String.format( + RMResources.ExceptionMessage, + RMResources.Gone), + request.uri().toString()); + exception.responseHeaders().put(HttpConstants.HttpHeaders.ACTIVITY_ID, + activityId); + + break; + } else { + exception = new NotFoundException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.NotFound : errorMessage), + response.headers(), + request.uri()); + break; + } + + case HttpConstants.StatusCodes.BADREQUEST: + exception = new BadRequestException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.BadRequest : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.METHOD_NOT_ALLOWED: + exception = new MethodNotAllowedException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.MethodNotAllowed : errorMessage), + null, + response.headers(), + request.uri().toString()); + break; + + case HttpConstants.StatusCodes.GONE: { + + // TODO: update perf counter + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + ErrorUtils.logGoneException(request.uri(), activityId); + + Integer nSubStatus = 0; + String valueSubStatus = response.headers().value(WFConstants.BackendHeaders.SUB_STATUS); + if (!Strings.isNullOrEmpty(valueSubStatus)) { + if ((nSubStatus = Integers.tryParse(valueSubStatus)) == null) { + exception = new InternalServerErrorException( + String.format( + RMResources.ExceptionMessage, + RMResources.InvalidBackendResponse), + response.headers(), + request.uri()); + break; + } + } + + if (nSubStatus == HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE) { + exception = new InvalidPartitionException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage), + response.headers(), + request.uri().toString()); + break; + } else if (nSubStatus == HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE) { + exception = new PartitionKeyRangeGoneException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage), + response.headers(), + request.uri().toString()); + break; + } else if (nSubStatus == HttpConstants.SubStatusCodes.COMPLETING_SPLIT) { + exception = new PartitionKeyRangeIsSplittingException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage), + response.headers(), + request.uri().toString()); + break; + } else if (nSubStatus == HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION) { + exception = new PartitionIsMigratingException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Gone : errorMessage), + response.headers(), + request.uri().toString()); + break; + } else { + // Have the request URL in the exception message for debugging purposes. + exception = new GoneException( + String.format( + RMResources.ExceptionMessage, + RMResources.Gone), + response.headers(), + request.uri()); + + exception.responseHeaders().put(HttpConstants.HttpHeaders.ACTIVITY_ID, + activityId); + break; + } + } + + case HttpConstants.StatusCodes.CONFLICT: + exception = new ConflictException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.EntityAlreadyExists : errorMessage), + response.headers(), + request.uri().toString()); + break; + + case HttpConstants.StatusCodes.PRECONDITION_FAILED: + exception = new PreconditionFailedException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.PreconditionFailed : errorMessage), + response.headers(), + request.uri().toString()); + break; + + case HttpConstants.StatusCodes.REQUEST_ENTITY_TOO_LARGE: + exception = new RequestEntityTooLargeException( + String.format( + RMResources.ExceptionMessage, + String.format( + RMResources.RequestEntityTooLarge, + HttpConstants.HttpHeaders.PAGE_SIZE)), + response.headers(), + request.uri().toString()); + break; + + case HttpConstants.StatusCodes.LOCKED: + exception = new LockedException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.Locked : errorMessage), + response.headers(), + request.uri().toString()); + break; + + case HttpConstants.StatusCodes.SERVICE_UNAVAILABLE: + exception = new ServiceUnavailableException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.ServiceUnavailable : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.REQUEST_TIMEOUT: + exception = new RequestTimeoutException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.RequestTimeout : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.RETRY_WITH: + exception = new RetryWithException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.RetryWith : errorMessage), + response.headers(), + request.uri()); + break; + + case HttpConstants.StatusCodes.TOO_MANY_REQUESTS: + exception = + new RequestRateTooLargeException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.TooManyRequests : errorMessage), + response.headers(), + request.uri()); + + List values = null; + headerValues = response.headers().values(HttpConstants.HttpHeaders.RETRY_AFTER_IN_MILLISECONDS); + if (headerValues != null) { + values = com.google.common.collect.Lists.newArrayList(headerValues); + } + if (values == null || values.isEmpty()) { + logger.warn("RequestRateTooLargeException being thrown without RetryAfter."); + } else { + exception.responseHeaders().put(HttpConstants.HttpHeaders.RETRY_AFTER_IN_MILLISECONDS, values.get(0)); + } + + break; + + case HttpConstants.StatusCodes.INTERNAL_SERVER_ERROR: + exception = new InternalServerErrorException( + String.format( + RMResources.ExceptionMessage, + Strings.isNullOrEmpty(errorMessage) ? RMResources.InternalServerError : errorMessage), + response.headers(), + request.uri()); + break; + + default: + logger.error("Unrecognized status code {} returned by backend. ActivityId {}", statusCode, activityId); + ErrorUtils.logException(request.uri(), activityId); + exception = new InternalServerErrorException( + String.format( + RMResources.ExceptionMessage, + RMResources.InvalidBackendResponse), + response.headers(), + request.uri()); + break; + } + + BridgeInternal.setLSN(exception, responseLSN); + BridgeInternal.setPartitionKeyRangeId(exception, responsePartitionKeyRangeId); + BridgeInternal.setResourceAddress(exception, resourceAddress); + BridgeInternal.setRequestHeaders(exception, HttpUtils.asMap(request.headers())); + + return Mono.error(exception); + } + ); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtils.java new file mode 100644 index 0000000000000..1d3bc513800f5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtils.java @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.Constants.UrlEncodingInfo; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +public class HttpUtils { + + private static Logger log = LoggerFactory.getLogger(HttpUtils.class); + + public static String urlEncode(String url) { + try { + return URLEncoder.encode(url, UrlEncodingInfo.UTF_8).replaceAll(UrlEncodingInfo.PLUS_SYMBOL_ESCAPED, UrlEncodingInfo.SINGLE_SPACE_URI_ENCODING); + } catch (UnsupportedEncodingException e) { + log.error("failed to encode {}", url, e); + throw new IllegalArgumentException("failed to encode url " + url, e); + } + } + + public static String urlDecode(String url) { + try { + return URLDecoder.decode(url.replaceAll(UrlEncodingInfo.PLUS_SYMBOL_ESCAPED, UrlEncodingInfo.PLUS_SYMBOL_URI_ENCODING), UrlEncodingInfo.UTF_8); + } catch (UnsupportedEncodingException e) { + log.error("failed to decode {}", url, e); + throw new IllegalArgumentException("failed to decode url " + url, e); + } + } + + public static URI toURI(String uri) { + try { + return new URI(uri); + } catch (Exception e) { + log.error("failed to parse {}", uri, e); + throw new IllegalArgumentException("failed to parse uri " + uri, e); + } + } + + public static Map asMap(HttpHeaders headers) { + if (headers == null) { + return new HashMap<>(); + } + HashMap map = new HashMap<>(headers.size()); + for (Entry entry : headers.toMap().entrySet()) { + if (entry.getKey().equals(HttpConstants.HttpHeaders.OWNER_FULL_NAME)) { + map.put(entry.getKey(), HttpUtils.urlDecode(entry.getValue())); + } else { + map.put(entry.getKey(), entry.getValue()); + } + } + return map; + } + + public static String getDateHeader(Map headerValues) { + if (headerValues == null) { + return StringUtils.EMPTY; + } + + // Since Date header is overridden by some proxies/http client libraries, we support + // an additional date header 'x-ms-date' and prefer that to the regular 'date' header. + String date = headerValues.get(HttpConstants.HttpHeaders.X_DATE); + if (Strings.isNullOrEmpty(date)) { + date = headerValues.get(HttpConstants.HttpHeaders.HTTP_DATE); + } + + return date != null ? date : StringUtils.EMPTY; + } + + public static List> unescape(Set> headers) { + List> result = new ArrayList<>(headers.size()); + for (Entry entry : headers) { + if (entry.getKey().equals(HttpConstants.HttpHeaders.OWNER_FULL_NAME)) { + String unescapedUrl = HttpUtils.urlDecode(entry.getValue()); + entry = new AbstractMap.SimpleEntry<>(entry.getKey(), unescapedUrl); + } + result.add(entry); + } + return result; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressCache.java new file mode 100644 index 0000000000000..9a507d14f0305 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressCache.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import reactor.core.publisher.Mono; + +public interface IAddressCache { + + /** + * Resolves physical addresses by either PartitionKeyRangeIdentity. + * + * + * @param request Request is needed only by GatewayAddressCache in the only case when request is name based and user has name based auth token. + * PartitionkeyRangeIdentity can be used to locate auth token in this case. + * @param partitionKeyRangeIdentity target partition key range Id + * @param forceRefreshPartitionAddresses Whether addresses need to be refreshed as previously resolved addresses were determined to be outdated. + * @return Physical addresses. + */ + Mono tryGetAddresses( + RxDocumentServiceRequest request, + PartitionKeyRangeIdentity partitionKeyRangeIdentity, + boolean forceRefreshPartitionAddresses); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressResolver.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressResolver.java new file mode 100644 index 0000000000000..e8a783002b926 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IAddressResolver.java @@ -0,0 +1,33 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import reactor.core.publisher.Mono; + +public interface IAddressResolver { + Mono resolveAsync( + RxDocumentServiceRequest request, + boolean forceRefreshPartitionAddresses); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IStoreClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IStoreClient.java new file mode 100644 index 0000000000000..e06cd8c72e993 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/IStoreClient.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.IRetryPolicy; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import reactor.core.publisher.Mono; + +import java.util.function.Function; + +public interface IStoreClient { + + Mono processMessageAsync( + RxDocumentServiceRequest request, + IRetryPolicy retryPolicy, + Function> prepareRequestAsyncDelegate); + + default Mono processMessageAsync( + RxDocumentServiceRequest request, + Function> prepareRequestAsyncDelegate) { + return processMessageAsync(request, null, prepareRequestAsyncDelegate); + } + + default Mono processMessageAsync( + RxDocumentServiceRequest request, + IRetryPolicy retryPolicy) { + return processMessageAsync(request, retryPolicy, null); + } + + default Mono processMessageAsync( + RxDocumentServiceRequest request) { + return processMessageAsync(request, null, null); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Protocol.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Protocol.java new file mode 100644 index 0000000000000..326f48939b542 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/Protocol.java @@ -0,0 +1,46 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import org.apache.commons.text.WordUtils; + +public enum Protocol { + HTTPS, TCP; + + String scheme() { + switch (this) { + case HTTPS: + return "https"; + case TCP: + return "rntbd"; + default: + throw new IllegalStateException(); + } + } + + @Override + public String toString() { + return WordUtils.capitalizeFully(this.name()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QueryRequestPerformanceActivity.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QueryRequestPerformanceActivity.java new file mode 100644 index 0000000000000..e0805afffc0ed --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QueryRequestPerformanceActivity.java @@ -0,0 +1,29 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +// TODO troubleshooting info +// https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 +public class QueryRequestPerformanceActivity { +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReader.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReader.java new file mode 100644 index 0000000000000..923f70a6ab604 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReader.java @@ -0,0 +1,810 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.JavaStreamUtils; +import com.azure.data.cosmos.internal.MutableVolatile; +import com.azure.data.cosmos.internal.Quadruple; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; + +// +//================================================================================================================= +// STRONG read logic: +//================================================================================================================= +// +// ------------------- PerformPrimaryRead------------------------------------------------------------- +// | ^ | +// [RetryOnSecondary] | | +// | [QuorumNotSelected] | +// \/ | \/ +// Start-------------------------->SecondaryQuorumRead-------------[QuorumMet]-------------------------------->Result +// | ^ +// [QuorumSelected] | +// | | +// \/ | +// PrimaryReadBarrier------------------------------------------------------------- +// +//================================================================================================================= +// BOUNDED_STALENESS quorum read logic: +//================================================================================================================= +// +// ------------------- PerformPrimaryRead------------------------------------------------------------- +// | ^ | +// [RetryOnSecondary] | | +// | [QuorumNotSelected] | +// \/ | \/ +// Start-------------------------->SecondaryQuorumRead-------------[QuorumMet]-------------------------------->Result +// | ^ +// [QuorumSelected] | +// | | +// | | +// --------------------------------------------------------------------------- +// +/** + * QuorumReader wraps the client side quorum logic on top of the StoreReader + */ +public class QuorumReader { + private final static Logger logger = LoggerFactory.getLogger(QuorumReader.class); + + private final int maxNumberOfReadBarrierReadRetries; + private final int maxNumberOfPrimaryReadRetries; + private final int maxNumberOfReadQuorumRetries; + private final int delayBetweenReadBarrierCallsInMs; + + private final int maxBarrierRetriesForMultiRegion; + private final int barrierRetryIntervalInMsForMultiRegion; + + private final int maxShortBarrierRetriesForMultiRegion; + private final int shortBarrierRetryIntervalInMsForMultiRegion; + + private final StoreReader storeReader; + private final GatewayServiceConfigurationReader serviceConfigReader; + private final IAuthorizationTokenProvider authorizationTokenProvider; + + public QuorumReader( + Configs configs, + TransportClient transportClient, + AddressSelector addressSelector, + StoreReader storeReader, + GatewayServiceConfigurationReader serviceConfigReader, + IAuthorizationTokenProvider authorizationTokenProvider) { + this.storeReader = storeReader; + this.serviceConfigReader = serviceConfigReader; + this.authorizationTokenProvider = authorizationTokenProvider; + + this.maxNumberOfReadBarrierReadRetries = configs.getMaxNumberOfReadBarrierReadRetries(); + this.maxNumberOfPrimaryReadRetries = configs.getMaxNumberOfPrimaryReadRetries(); + this.maxNumberOfReadQuorumRetries = configs.getMaxNumberOfReadQuorumRetries(); + this.delayBetweenReadBarrierCallsInMs = configs.getDelayBetweenReadBarrierCallsInMs(); + this.maxBarrierRetriesForMultiRegion = configs.getMaxBarrierRetriesForMultiRegion(); + this.barrierRetryIntervalInMsForMultiRegion = configs.getBarrierRetryIntervalInMsForMultiRegion(); + this.maxShortBarrierRetriesForMultiRegion = configs.getMaxShortBarrierRetriesForMultiRegion(); + this.shortBarrierRetryIntervalInMsForMultiRegion = configs.getShortBarrierRetryIntervalInMsForMultiRegion(); + } + + public QuorumReader( + TransportClient transportClient, + AddressSelector addressSelector, + StoreReader storeReader, + GatewayServiceConfigurationReader serviceConfigReader, + IAuthorizationTokenProvider authorizationTokenProvider, + Configs configs) { + this(configs, transportClient, addressSelector, storeReader, serviceConfigReader, authorizationTokenProvider); + } + + public Mono readStrongAsync( + RxDocumentServiceRequest entity, + int readQuorumValue, + ReadMode readMode) { + final MutableVolatile shouldRetryOnSecondary = new MutableVolatile<>(false); + final MutableVolatile hasPerformedReadFromPrimary = new MutableVolatile<>(false); + + return Flux.defer( + // the following will be repeated till the repeat().takeUntil(.) condition is satisfied. + () -> { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new GoneException()); + } + + shouldRetryOnSecondary.v = false; + Mono secondaryQuorumReadResultObs = + this.readQuorumAsync(entity, readQuorumValue, false, readMode); + + return secondaryQuorumReadResultObs.flux().flatMap( + secondaryQuorumReadResult -> { + + switch (secondaryQuorumReadResult.quorumResult) { + case QuorumMet: + try { + return Flux.just(secondaryQuorumReadResult.getResponse()); + } catch (CosmosClientException e) { + return Flux.error(e); + } + + case QuorumSelected: + Mono barrierRequestObs = BarrierRequestHelper.createAsync( + entity, + this.authorizationTokenProvider, + secondaryQuorumReadResult.selectedLsn, + secondaryQuorumReadResult.globalCommittedSelectedLsn); + + return barrierRequestObs.flux().flatMap(barrierRequest -> { + Mono readBarrierObs = this.waitForReadBarrierAsync( + barrierRequest, + true /* include primary */, + readQuorumValue, + secondaryQuorumReadResult.selectedLsn, + secondaryQuorumReadResult.globalCommittedSelectedLsn, + readMode); + + return readBarrierObs.flux().flatMap( + readBarrier -> { + + if (readBarrier) { + try { + return Flux.just(secondaryQuorumReadResult.getResponse()); + } catch (Exception e) { + return Flux.error(e); + } + } + + // else barrier was not successful + logger.warn( + "QuorumSelected: Could not converge on the LSN {} GlobalCommittedLSN {} after primary read barrier with read quorum {} for strong read, Responses: {}", + secondaryQuorumReadResult.selectedLsn, + secondaryQuorumReadResult.globalCommittedSelectedLsn, + readQuorumValue, + String.join(";", secondaryQuorumReadResult.storeResponses) + ); + + entity.requestContext.quorumSelectedStoreResponse = secondaryQuorumReadResult.selectedResponse; + entity.requestContext.storeResponses = secondaryQuorumReadResult.storeResponses; + entity.requestContext.quorumSelectedLSN = secondaryQuorumReadResult.selectedLsn; + entity.requestContext.globalCommittedSelectedLSN = secondaryQuorumReadResult.globalCommittedSelectedLsn; + + return Flux.empty(); + } + ); + }); + + case QuorumNotSelected: + if (hasPerformedReadFromPrimary.v) { + logger.warn("QuorumNotSelected: Primary read already attempted. Quorum could not be selected after retrying on secondaries."); + return Flux.error(new GoneException(RMResources.ReadQuorumNotMet)); + } + + logger.warn("QuorumNotSelected: Quorum could not be selected with read quorum of {}", readQuorumValue); + Mono responseObs = this.readPrimaryAsync(entity, readQuorumValue, false); + + return responseObs.flux().flatMap( + response -> { + if (response.isSuccessful && response.shouldRetryOnSecondary) { + assert false : "QuorumNotSelected: PrimaryResult has both Successful and shouldRetryOnSecondary flags set"; + logger.error("PrimaryResult has both Successful and shouldRetryOnSecondary flags set"); + } else if (response.isSuccessful) { + logger.debug("QuorumNotSelected: ReadPrimary successful"); + try { + return Flux.just(response.getResponse()); + } catch (CosmosClientException e) { + return Flux.error(e); + } + } else if (response.shouldRetryOnSecondary) { + shouldRetryOnSecondary.v = true; + logger.warn("QuorumNotSelected: ReadPrimary did not succeed. Will retry on secondary."); + hasPerformedReadFromPrimary.v = true; + } else { + logger.warn("QuorumNotSelected: Could not get successful response from ReadPrimary"); + return Flux.error(new GoneException(String.format(RMResources.ReadQuorumNotMet, readQuorumValue))); + } + + return Flux.empty(); + + } + ); + + default: + logger.error("Unknown ReadQuorum result {}", secondaryQuorumReadResult.quorumResult.toString()); + return Flux.error(new InternalServerErrorException(RMResources.InternalServerError)); + } + + }); + }).repeat(maxNumberOfReadQuorumRetries) + .takeUntil(dummy -> !shouldRetryOnSecondary.v) + .concatWith(Flux.defer(() -> { + logger.warn("Could not complete read quorum with read quorum value of {}", readQuorumValue); + + return Flux.error(new GoneException( + String.format( + RMResources.ReadQuorumNotMet, + readQuorumValue))); + })) + .take(1) + .single(); + } + + private Mono readQuorumAsync( + RxDocumentServiceRequest entity, + int readQuorum, + boolean includePrimary, + ReadMode readMode) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + return ensureQuorumSelectedStoreResponse(entity, readQuorum, includePrimary, readMode).flatMap( + res -> { + if (res.getLeft() != null) { + // no need for barrier + return Mono.just(res.getKey()); + } + + long readLsn = res.getValue().getValue0(); + long globalCommittedLSN = res.getValue().getValue1(); + StoreResult storeResult = res.getValue().getValue2(); + List storeResponses = res.getValue().getValue3(); + + // ReadBarrier required + Mono barrierRequestObs = BarrierRequestHelper.createAsync(entity, this.authorizationTokenProvider, readLsn, globalCommittedLSN); + return barrierRequestObs.flatMap( + barrierRequest -> { + Mono waitForObs = this.waitForReadBarrierAsync(barrierRequest, false, readQuorum, readLsn, globalCommittedLSN, readMode); + return waitForObs.flatMap( + waitFor -> { + if (!waitFor) { + return Mono.just(new ReadQuorumResult( + entity.requestContext.requestChargeTracker, + ReadQuorumResultKind.QuorumSelected, + readLsn, + globalCommittedLSN, + storeResult, + storeResponses)); + } + + return Mono.just(new ReadQuorumResult( + entity.requestContext.requestChargeTracker, + ReadQuorumResultKind.QuorumMet, + readLsn, + globalCommittedLSN, + storeResult, + storeResponses)); + } + ); + } + ); + } + ); + } + + private Mono>>> ensureQuorumSelectedStoreResponse(RxDocumentServiceRequest entity, int readQuorum, boolean includePrimary, ReadMode readMode) { + + if (entity.requestContext.quorumSelectedStoreResponse == null) { + Mono> responseResultObs = this.storeReader.readMultipleReplicaAsync( + entity, includePrimary, readQuorum, true /*required valid LSN*/, false, readMode); + + return responseResultObs.flatMap( + responseResult -> { + List storeResponses = responseResult.stream().map(response -> response.toString()).collect(Collectors.toList()); + int responseCount = (int) responseResult.stream().filter(response -> response.isValid).count(); + if (responseCount < readQuorum) { + return Mono.just(Pair.of(new ReadQuorumResult(entity.requestContext.requestChargeTracker, + ReadQuorumResultKind.QuorumNotSelected, + -1, -1, null, storeResponses), null)); + } + + //either request overrides consistency level with strong, or request does not override and account default consistency level is strong + boolean isGlobalStrongReadCandidate = + (ReplicatedResourceClient.isGlobalStrongEnabled() && this.serviceConfigReader.getDefaultConsistencyLevel() == ConsistencyLevel.STRONG) && + (entity.requestContext.originalRequestConsistencyLevel == null || entity.requestContext.originalRequestConsistencyLevel == ConsistencyLevel.STRONG); + + ValueHolder readLsn = new ValueHolder(-1); + ValueHolder globalCommittedLSN = new ValueHolder(-1); + ValueHolder storeResult = new ValueHolder(null); + + if (this.isQuorumMet( + responseResult, + readQuorum, + false, + isGlobalStrongReadCandidate, + readLsn, + globalCommittedLSN, + storeResult)) { + return Mono.just(Pair.of(new ReadQuorumResult( + entity.requestContext.requestChargeTracker, + ReadQuorumResultKind.QuorumMet, + readLsn.v, + globalCommittedLSN.v, + storeResult.v, + storeResponses), null)); + } + + // at this point, if refresh were necessary, we would have refreshed it in ReadMultipleReplicaAsync + // so set to false here to avoid further refrehses for this request. + entity.requestContext.forceRefreshAddressCache = false; + + Quadruple> state = Quadruple.with(readLsn.v, globalCommittedLSN.v, storeResult.v, storeResponses); + return Mono.just(Pair.of(null, state)); + } + ); + } else { + + ValueHolder readLsn = ValueHolder.initialize(entity.requestContext.quorumSelectedLSN); + ValueHolder globalCommittedLSN = ValueHolder.initialize(entity.requestContext.globalCommittedSelectedLSN); + ValueHolder storeResult = ValueHolder.initialize(entity.requestContext.quorumSelectedStoreResponse); + List storeResponses = entity.requestContext.storeResponses; + Quadruple> state = Quadruple.with(readLsn.v, globalCommittedLSN.v, storeResult.v, storeResponses); + + return Mono.just(Pair.of(null, state)); + } + } + + /** + * READ and get response from Primary + * + * @param entity + * @param readQuorum + * @param useSessionToken + * @return + */ + private Mono readPrimaryAsync( + RxDocumentServiceRequest entity, + int readQuorum, + boolean useSessionToken) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + // We would have already refreshed address before reaching here. Avoid performing here. + entity.requestContext.forceRefreshAddressCache = false; + + Mono storeResultObs = this.storeReader.readPrimaryAsync( + entity, true /*required valid LSN*/, useSessionToken); + + return storeResultObs.flatMap( + storeResult -> { + if (!storeResult.isValid) { + try { + return Mono.error(storeResult.getException()); + } catch (InternalServerErrorException e) { + return Mono.error(e); + } + } + + if (storeResult.currentReplicaSetSize <= 0 || storeResult.lsn < 0 || storeResult.quorumAckedLSN < 0) { + String message = String.format( + "INVALID value received from response header. CurrentReplicaSetSize %d, StoreLSN %d, QuorumAckedLSN %d", + storeResult.currentReplicaSetSize, storeResult.lsn, storeResult.quorumAckedLSN); + + // might not be returned if primary is still building the secondary replicas (during churn) + logger.error(message); + + // throw exception instead of returning inconsistent result. + return Mono.error(new GoneException(String.format(RMResources.ReadQuorumNotMet, readQuorum))); + + } + + if (storeResult.currentReplicaSetSize > readQuorum) { + logger.warn( + "Unexpected response. Replica Set size is {} which is greater than min value {}", storeResult.currentReplicaSetSize, readQuorum); + return Mono.just(new ReadPrimaryResult(entity.requestContext.requestChargeTracker, /*isSuccessful */ false, + /* shouldRetryOnSecondary: */ true, /* response: */ null)); + } + + // To accommodate for store latency, where an LSN may be acked by not persisted in the store, we compare the quorum acked LSN and store LSN. + // In case of sync replication, the store LSN will follow the quorum committed LSN + // In case of async replication (if enabled for bounded staleness), the store LSN can be ahead of the quorum committed LSN if the primary is able write to faster than secondary acks. + // We pick higher of the 2 LSN and wait for the other to reach that LSN. + if (storeResult.lsn != storeResult.quorumAckedLSN) { + logger.warn("Store LSN {} and quorum acked LSN {} don't match", storeResult.lsn, storeResult.quorumAckedLSN); + long higherLsn = storeResult.lsn > storeResult.quorumAckedLSN ? storeResult.lsn : storeResult.quorumAckedLSN; + + Mono waitForLsnRequestObs = BarrierRequestHelper.createAsync(entity, this.authorizationTokenProvider, higherLsn, null); + return waitForLsnRequestObs.flatMap( + waitForLsnRequest -> { + Mono primaryWaitForLsnResponseObs = this.waitForPrimaryLsnAsync(waitForLsnRequest, higherLsn, readQuorum); + return primaryWaitForLsnResponseObs.map( + primaryWaitForLsnResponse -> { + if (primaryWaitForLsnResponse == PrimaryReadOutcome.QuorumNotMet) { + return new ReadPrimaryResult( + entity.requestContext.requestChargeTracker, /*(isSuccessful: */ false, /* shouldRetryOnSecondary: */ false, /* response: */null); + } else if (primaryWaitForLsnResponse == PrimaryReadOutcome.QuorumInconclusive) { + return new ReadPrimaryResult( + entity.requestContext.requestChargeTracker, /* isSuccessful: */ false, /* shouldRetryOnSecondary: */ + true, /* response: */ null); + } + + return new ReadPrimaryResult( + entity.requestContext.requestChargeTracker, /* isSuccessful: */ true, /* shouldRetryOnSecondary: */ false, /*response: */ storeResult); + } + ); + } + ); + } + + return Mono.just(new ReadPrimaryResult( + /* requestChargeTracker: */ entity.requestContext.requestChargeTracker, /* isSuccessful: */ true, /* shouldRetryOnSecondary:*/ false, + /*response: */ storeResult)); + } + ); + } + + private Mono waitForPrimaryLsnAsync( + RxDocumentServiceRequest barrierRequest, + long lsnToWaitFor, + int readQuorum) { + + return Flux.defer(() -> { + if (barrierRequest.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new GoneException()); + } + + // We would have already refreshed address before reaching here. Avoid performing here. + barrierRequest.requestContext.forceRefreshAddressCache = false; + + Mono storeResultObs = this.storeReader.readPrimaryAsync(barrierRequest, true /*required valid LSN*/, false); + + return storeResultObs.flux().flatMap( + storeResult -> { + if (!storeResult.isValid) { + try { + return Flux.error(storeResult.getException()); + } catch (InternalServerErrorException e) { + return Flux.error(e); + } + } + + if (storeResult.currentReplicaSetSize > readQuorum) { + logger.warn( + "Unexpected response. Replica Set size is {} which is greater than min value {}", storeResult.currentReplicaSetSize, readQuorum); + return Flux.just(PrimaryReadOutcome.QuorumInconclusive); + } + + // Java this will move to the repeat logic + if (storeResult.lsn < lsnToWaitFor || storeResult.quorumAckedLSN < lsnToWaitFor) { + logger.warn( + "Store LSN {} or quorum acked LSN {} are lower than expected LSN {}", storeResult.lsn, storeResult.quorumAckedLSN, lsnToWaitFor); + + return Flux.just(0L).delayElements(Duration.ofMillis(delayBetweenReadBarrierCallsInMs)).flatMap(dummy -> Flux.empty()); + } + + return Flux.just(PrimaryReadOutcome.QuorumMet); + } + ); + }).repeat(maxNumberOfPrimaryReadRetries) // Loop for store and quorum LSN to match + .defaultIfEmpty(PrimaryReadOutcome.QuorumNotMet) + .take(1) + .single(); + + } + + private Mono waitForReadBarrierAsync( + RxDocumentServiceRequest barrierRequest, + boolean allowPrimary, + final int readQuorum, + final long readBarrierLsn, + final long targetGlobalCommittedLSN, + ReadMode readMode) { + AtomicInteger readBarrierRetryCount = new AtomicInteger(maxNumberOfReadBarrierReadRetries); + AtomicInteger readBarrierRetryCountMultiRegion = new AtomicInteger(maxBarrierRetriesForMultiRegion); + + AtomicLong maxGlobalCommittedLsn = new AtomicLong(0); + + return Flux.defer(() -> { + + if (barrierRequest.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new GoneException()); + } + + Mono> responsesObs = this.storeReader.readMultipleReplicaAsync( + barrierRequest, allowPrimary, readQuorum, + true /*required valid LSN*/, false /*useSessionToken*/, readMode, false /*checkMinLSN*/, true /*forceReadAll*/); + + return responsesObs.flux().flatMap( + responses -> { + + long maxGlobalCommittedLsnInResponses = responses.size() > 0 ? responses.stream() + .mapToLong(response -> response.globalCommittedLSN).max().getAsLong() : 0; + + + if ((responses.stream().filter(response -> response.lsn >= readBarrierLsn).count() >= readQuorum) && + (!(targetGlobalCommittedLSN > 0) || maxGlobalCommittedLsnInResponses >= targetGlobalCommittedLSN)) { + return Flux.just(true); + } + + maxGlobalCommittedLsn.set(maxGlobalCommittedLsn.get() > maxGlobalCommittedLsnInResponses ? + maxGlobalCommittedLsn.get() : maxGlobalCommittedLsnInResponses); + + //only refresh on first barrier call, set to false for subsequent attempts. + barrierRequest.requestContext.forceRefreshAddressCache = false; + + if (readBarrierRetryCount.decrementAndGet() == 0) { + logger.debug("QuorumReader: waitForReadBarrierAsync - Last barrier for single-region requests. Responses: {}", + JavaStreamUtils.toString(responses, "; ")); + + // retries exhausted + return Flux.just(false); + + } else { + // delay + //await Task.Delay(QuorumReader.delayBetweenReadBarrierCallsInMs); + return Flux.empty(); + + } + } + ); + }).repeatWhen(obs -> obs.flatMap(aVoid -> Flux.just(0L).delayElements(Duration.ofMillis(delayBetweenReadBarrierCallsInMs)))) + .take(1) // Retry loop + .flatMap(barrierRequestSucceeded -> + Flux.defer(() -> { + + if (barrierRequestSucceeded) { + return Flux.just(true); + } + + // we will go into global strong read barrier mode for global strong requests after regular barrier calls have been exhausted. + if (targetGlobalCommittedLSN > 0) { + return Flux.defer(() -> { + + if (barrierRequest.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new GoneException()); + } + + Mono> responsesObs = this.storeReader.readMultipleReplicaAsync( + barrierRequest, allowPrimary, readQuorum, + true /*required valid LSN*/, false /*useSessionToken*/, readMode, false /*checkMinLSN*/, true /*forceReadAll*/); + + return responsesObs.flux().flatMap( + responses -> { + long maxGlobalCommittedLsnInResponses = responses.size() > 0 ? responses.stream() + .mapToLong(response -> response.globalCommittedLSN).max().getAsLong() : 0; + + if ((responses.stream().filter(response -> response.lsn >= readBarrierLsn).count() >= readQuorum) && + maxGlobalCommittedLsnInResponses >= targetGlobalCommittedLSN) { + return Flux.just(true); + } + + maxGlobalCommittedLsn.set(maxGlobalCommittedLsn.get() > maxGlobalCommittedLsnInResponses ? + maxGlobalCommittedLsn.get() : maxGlobalCommittedLsnInResponses); + + //trace on last retry. + if (readBarrierRetryCountMultiRegion.getAndDecrement() == 0) { + logger.debug("QuorumReader: waitForReadBarrierAsync - Last barrier for mult-region strong requests. Responses: {}", + JavaStreamUtils.toString(responses, "; ")); + return Flux.just(false); + } else { + return Flux.empty(); + } + } + ); + + }).repeatWhen(obs -> obs.flatMap(aVoid -> { + + if ((maxBarrierRetriesForMultiRegion - readBarrierRetryCountMultiRegion.get()) > maxShortBarrierRetriesForMultiRegion) { + return Flux.just(0L).delayElements(Duration.ofMillis(barrierRetryIntervalInMsForMultiRegion)); + } else { + return Flux.just(0L).delayElements(Duration.ofMillis(shortBarrierRetryIntervalInMsForMultiRegion)); + } + + }) + // stop predicate, simulating while loop + ).take(1); + } + + return Flux.empty(); + })). + concatWith( + Flux.defer(() -> { + logger.debug("QuorumReader: waitForReadBarrierAsync - TargetGlobalCommittedLsn: {}, MaxGlobalCommittedLsn: {}.", targetGlobalCommittedLSN, maxGlobalCommittedLsn); + return Flux.just(false); + }) + ).take(1).single(); + } + + private boolean isQuorumMet( + List readResponses, + int readQuorum, + boolean isPrimaryIncluded, + boolean isGlobalStrongRead, + ValueHolder readLsn, + ValueHolder globalCommittedLSN, + ValueHolder selectedResponse) { + long maxLsn = 0; + long minLsn = Long.MAX_VALUE; + int replicaCountMaxLsn = 0; + List validReadResponses = readResponses.stream().filter(response -> response.isValid).collect(Collectors.toList()); + int validResponsesCount = validReadResponses.size(); + + if (validResponsesCount == 0) { + readLsn.v = 0l; + globalCommittedLSN.v = -1l; + selectedResponse.v = null; + + return false; + } + + assert !validReadResponses.isEmpty(); + long numberOfReadRegions = validReadResponses.stream().map(res -> res.numberOfReadRegions).max(Comparator.naturalOrder()).get(); + boolean checkForGlobalStrong = isGlobalStrongRead && numberOfReadRegions > 0; + + // Pick any R replicas in the response and check if they are at the same LSN + for (StoreResult response : validReadResponses) { + if (response.lsn == maxLsn) { + replicaCountMaxLsn++; + } else if (response.lsn > maxLsn) { + replicaCountMaxLsn = 1; + maxLsn = response.lsn; + } + + if (response.lsn < minLsn) { + minLsn = response.lsn; + } + } + + final long maxLsnFinal = maxLsn; + selectedResponse.v = validReadResponses.stream().filter(s -> s.lsn == maxLsnFinal).findFirst().get(); + + readLsn.v = selectedResponse.v.itemLSN == -1 ? + maxLsn : Math.min(selectedResponse.v.itemLSN, maxLsn); + globalCommittedLSN.v = checkForGlobalStrong ? readLsn.v : -1l; + + long maxGlobalCommittedLSN = validReadResponses.stream().mapToLong(res -> res.globalCommittedLSN).max().getAsLong(); + + logger.debug("QuorumReader: MaxLSN {} ReplicaCountMaxLSN {} bCheckGlobalStrong {} MaxGlobalCommittedLSN {} NumberOfReadRegions {} SelectedResponseItemLSN {}", + maxLsn, replicaCountMaxLsn, checkForGlobalStrong, maxGlobalCommittedLSN, numberOfReadRegions, selectedResponse.v.itemLSN); + + // quorum is met if one of the following conditions are satisfied: + // 1. readLsn is greater than zero + // AND the number of responses that have the same LSN as the selected response is greater than or equal to the read quorum + // AND if applicable, the max GlobalCommittedLSN of all responses is greater than or equal to the lsn of the selected response. + + // 2. if the request is a point-read request, + // AND there are more than one response in the readResponses + // AND the LSN of the returned resource of the selected response is less than or equal to the minimum lsn of the all the responses, + // AND if applicable, the LSN of the returned resource of the selected response is less than or equal to the minimum globalCommittedLsn of all the responses. + // This means that the returned resource is old enough to have been committed by at least all the received responses, + // which should be larger than or equal to the read quorum, which therefore means we have strong consistency. + boolean isQuorumMet = false; + + if ((readLsn.v > 0 && replicaCountMaxLsn >= readQuorum) && + (!checkForGlobalStrong || maxGlobalCommittedLSN >= maxLsn)) { + isQuorumMet = true; + } + + if (!isQuorumMet && validResponsesCount >= readQuorum && selectedResponse.v.itemLSN != -1 && + (minLsn != Long.MAX_VALUE && selectedResponse.v.itemLSN <= minLsn) && + (!checkForGlobalStrong || (selectedResponse.v.itemLSN <= maxGlobalCommittedLSN))) { + isQuorumMet = true; + } + + return isQuorumMet; + } + + private enum ReadQuorumResultKind { + QuorumMet, + QuorumSelected, + QuorumNotSelected + } + + private abstract class ReadResult { + private final StoreResult response; + private final RequestChargeTracker requestChargeTracker; + + protected ReadResult(RequestChargeTracker requestChargeTracker, StoreResult response) { + this.requestChargeTracker = requestChargeTracker; + this.response = response; + } + + public StoreResponse getResponse() throws CosmosClientException { + if (!this.isValidResult()) { + logger.error("getResponse called for invalid result"); + throw new InternalServerErrorException(RMResources.InternalServerError); + } + + return this.response.toResponse(requestChargeTracker); + } + + protected abstract boolean isValidResult(); + } + + private class ReadQuorumResult extends ReadResult { + public ReadQuorumResult( + RequestChargeTracker requestChargeTracker, + ReadQuorumResultKind QuorumResult, + long selectedLsn, + long globalCommittedSelectedLsn, + StoreResult selectedResponse, + List storeResponses) { + super(requestChargeTracker, selectedResponse); + + this.quorumResult = QuorumResult; + this.selectedLsn = selectedLsn; + this.globalCommittedSelectedLsn = globalCommittedSelectedLsn; + this.selectedResponse = selectedResponse; + this.storeResponses = storeResponses; + } + + public final ReadQuorumResultKind quorumResult; + + /** + * Response selected to lock on the LSN. This is the response with the highest LSN + */ + public final StoreResult selectedResponse; + + /** + * ALL store responses from Quorum READ. + */ + public final List storeResponses; + + public final long selectedLsn; + + public final long globalCommittedSelectedLsn; + + protected boolean isValidResult() { + return this.quorumResult == ReadQuorumResultKind.QuorumMet || this.quorumResult == ReadQuorumResultKind.QuorumSelected; + } + } + + private class ReadPrimaryResult extends ReadResult { + public final boolean shouldRetryOnSecondary; + public final boolean isSuccessful; + + public ReadPrimaryResult(RequestChargeTracker requestChargeTracker, boolean isSuccessful, boolean shouldRetryOnSecondary, StoreResult response) { + super(requestChargeTracker, response); + this.isSuccessful = isSuccessful; + this.shouldRetryOnSecondary = shouldRetryOnSecondary; + } + + protected boolean isValidResult() { + return isSuccessful; + } + } + + private enum PrimaryReadOutcome { + QuorumNotMet, // Primary LSN is not committed. + QuorumInconclusive, // Secondary replicas are available. Must read R secondary's to deduce current quorum. + QuorumMet, + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReadMode.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReadMode.java new file mode 100644 index 0000000000000..2368f4b5d5668 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReadMode.java @@ -0,0 +1,32 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +public enum ReadMode { + Primary, // Test hook + Strong, + BoundedStaleness, + Any +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClient.java new file mode 100644 index 0000000000000..ff9df5aa91b55 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClient.java @@ -0,0 +1,195 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.internal.BackoffRetryUtility; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.Quadruple; +import com.azure.data.cosmos.internal.ReplicatedResourceClientUtils; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * ReplicatedResourceClient uses the ConsistencyReader to make requests to + * backend + */ +public class ReplicatedResourceClient { + private final Logger logger = LoggerFactory.getLogger(ReplicatedResourceClient.class); + private static final int GONE_AND_RETRY_WITH_TIMEOUT_IN_SECONDS = 30; + private static final int STRONG_GONE_AND_RETRY_WITH_RETRY_TIMEOUT_SECONDS = 60; + private static final int MIN_BACKOFF_FOR_FAILLING_BACK_TO_OTHER_REGIONS_FOR_READ_REQUESTS_IN_SECONDS = 1; + + private final AddressSelector addressSelector; + private final ConsistencyReader consistencyReader; + private final ConsistencyWriter consistencyWriter; + private final Protocol protocol; + private final TransportClient transportClient; + private final boolean enableReadRequestsFallback; + private final GatewayServiceConfigurationReader serviceConfigReader; + private final Configs configs; + + public ReplicatedResourceClient( + Configs configs, + AddressSelector addressSelector, + ISessionContainer sessionContainer, + TransportClient transportClient, + GatewayServiceConfigurationReader serviceConfigReader, + IAuthorizationTokenProvider authorizationTokenProvider, + boolean enableReadRequestsFallback, + boolean useMultipleWriteLocations) { + this.configs = configs; + this.protocol = configs.getProtocol(); + this.addressSelector = addressSelector; + if (protocol != Protocol.HTTPS && protocol != Protocol.TCP) { + throw new IllegalArgumentException("protocol"); + } + + this.transportClient = transportClient; + this.serviceConfigReader = serviceConfigReader; + + this.consistencyReader = new ConsistencyReader(configs, + this.addressSelector, + sessionContainer, + transportClient, + serviceConfigReader, + authorizationTokenProvider); + this.consistencyWriter = new ConsistencyWriter( + this.addressSelector, + sessionContainer, + transportClient, + authorizationTokenProvider, + serviceConfigReader, + useMultipleWriteLocations); + this.enableReadRequestsFallback = enableReadRequestsFallback; + } + + public static boolean isReadingFromMaster(ResourceType resourceType, OperationType operationType) { + return ReplicatedResourceClientUtils.isReadingFromMaster(resourceType, operationType); + } + + public static boolean isMasterResource(ResourceType resourceType) { + return ReplicatedResourceClientUtils.isMasterResource(resourceType); + } + + public static boolean isGlobalStrongEnabled() { + return true; + } + + public Mono invokeAsync(RxDocumentServiceRequest request, + Function> prepareRequestAsyncDelegate) { + BiFunction, RxDocumentServiceRequest, Mono> mainFuncDelegate = ( + Quadruple forceRefreshAndTimeout, + RxDocumentServiceRequest documentServiceRequest) -> { + documentServiceRequest.getHeaders().put(HttpConstants.HttpHeaders.CLIENT_RETRY_ATTEMPT_COUNT, + forceRefreshAndTimeout.getValue3().toString()); + documentServiceRequest.getHeaders().put(HttpConstants.HttpHeaders.REMAINING_TIME_IN_MS_ON_CLIENT_REQUEST, + Long.toString(forceRefreshAndTimeout.getValue2().toMillis())); + return invokeAsync(request, new TimeoutHelper(forceRefreshAndTimeout.getValue2()), + forceRefreshAndTimeout.getValue1(), forceRefreshAndTimeout.getValue0()); + + }; + Function, Mono> funcDelegate = ( + Quadruple forceRefreshAndTimeout) -> { + if (prepareRequestAsyncDelegate != null) { + return prepareRequestAsyncDelegate.apply(request).flatMap(responseReq -> mainFuncDelegate.apply(forceRefreshAndTimeout, responseReq)); + } else { + return mainFuncDelegate.apply(forceRefreshAndTimeout, request); + } + + }; + + Function, Mono> inBackoffFuncDelegate = null; + + // we will enable fallback to other regions if the following conditions are met: + // 1. request is a read operation AND + // 2. enableReadRequestsFallback is set to true. (can only ever be true if + // direct mode, on client) + if (request.isReadOnlyRequest() && this.enableReadRequestsFallback) { + if (request.requestContext.cosmosResponseDiagnostics == null) { + request.requestContext.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + RxDocumentServiceRequest freshRequest = request.clone(); + inBackoffFuncDelegate = (Quadruple forceRefreshAndTimeout) -> { + RxDocumentServiceRequest readRequestClone = freshRequest.clone(); + + if (prepareRequestAsyncDelegate != null) { + return prepareRequestAsyncDelegate.apply(readRequestClone).flatMap(responseReq -> { + logger.trace("Executing inBackoffAlternateCallbackMethod on readRegionIndex {}", forceRefreshAndTimeout.getValue3()); + responseReq.requestContext.RouteToLocation(forceRefreshAndTimeout.getValue3(), true); + return invokeAsync(responseReq, new TimeoutHelper(forceRefreshAndTimeout.getValue2()), + forceRefreshAndTimeout.getValue1(), + forceRefreshAndTimeout.getValue0()); + }); + } else { + logger.trace("Executing inBackoffAlternateCallbackMethod on readRegionIndex {}", forceRefreshAndTimeout.getValue3()); + readRequestClone.requestContext.RouteToLocation(forceRefreshAndTimeout.getValue3(), true); + return invokeAsync(readRequestClone, new TimeoutHelper(forceRefreshAndTimeout.getValue2()), + forceRefreshAndTimeout.getValue1(), + forceRefreshAndTimeout.getValue0()); + } + + }; + } + + int retryTimeout = this.serviceConfigReader.getDefaultConsistencyLevel() == ConsistencyLevel.STRONG ? + ReplicatedResourceClient.STRONG_GONE_AND_RETRY_WITH_RETRY_TIMEOUT_SECONDS : + ReplicatedResourceClient.GONE_AND_RETRY_WITH_TIMEOUT_IN_SECONDS; + + return BackoffRetryUtility.executeAsync(funcDelegate, new GoneAndRetryWithRetryPolicy(request, retryTimeout), + inBackoffFuncDelegate, Duration.ofSeconds( + ReplicatedResourceClient.MIN_BACKOFF_FOR_FAILLING_BACK_TO_OTHER_REGIONS_FOR_READ_REQUESTS_IN_SECONDS)); + } + + private Mono invokeAsync(RxDocumentServiceRequest request, TimeoutHelper timeout, + boolean isInRetry, boolean forceRefresh) { + + if (request.getOperationType().equals(OperationType.ExecuteJavaScript)) { + if (request.isReadOnlyScript()) { + return this.consistencyReader.readAsync(request, timeout, isInRetry, forceRefresh); + } else { + return this.consistencyWriter.writeAsync(request, timeout, forceRefresh); + } + } else if (request.getOperationType().isWriteOperation()) { + return this.consistencyWriter.writeAsync(request, timeout, forceRefresh); + } else if (request.isReadOnlyRequest()) { + return this.consistencyReader.readAsync(request, timeout, isInRetry, forceRefresh); + } else { + throw new IllegalArgumentException( + String.format("Unexpected operation type %s", request.getOperationType())); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RequestHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RequestHelper.java new file mode 100644 index 0000000000000..ad18b133b6d0b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RequestHelper.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import org.apache.commons.lang3.EnumUtils; + +public class RequestHelper { + public static ConsistencyLevel GetConsistencyLevelToUse(GatewayServiceConfigurationReader serviceConfigReader, + RxDocumentServiceRequest request) throws CosmosClientException { + ConsistencyLevel consistencyLevelToUse = serviceConfigReader.getDefaultConsistencyLevel(); + + String requestConsistencyLevelHeaderValue = request.getHeaders().get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL); + + if (!Strings.isNullOrEmpty(requestConsistencyLevelHeaderValue)) { + ConsistencyLevel requestConsistencyLevel = EnumUtils.getEnum(ConsistencyLevel.class, Strings.fromCamelCaseToUpperCase(requestConsistencyLevelHeaderValue)); + if (requestConsistencyLevel == null) { + throw new BadRequestException( + String.format( + RMResources.InvalidHeaderValue, + requestConsistencyLevelHeaderValue, + HttpConstants.HttpHeaders.CONSISTENCY_LEVEL)); + } + + consistencyLevelToUse = requestConsistencyLevel; + } + + return consistencyLevelToUse; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResourceOperation.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResourceOperation.java new file mode 100644 index 0000000000000..230fa1d6ae0b7 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResourceOperation.java @@ -0,0 +1,39 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; + +public class ResourceOperation { + public final OperationType operationType; + public final ResourceType resourceType; + + public ResourceOperation( + OperationType operationType, + ResourceType resourceType) { + this.operationType = operationType; + this.resourceType = resourceType; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResponseUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResponseUtils.java new file mode 100644 index 0000000000000..6cecf893b76bc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ResponseUtils.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.StringUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +class ResponseUtils { + private final static int INITIAL_RESPONSE_BUFFER_SIZE = 1024; + + public static Mono toString(Flux contentObservable) { + return contentObservable + .reduce( + new ByteArrayOutputStream(INITIAL_RESPONSE_BUFFER_SIZE), + (out, bb) -> { + try { + bb.readBytes(out, bb.readableBytes()); + return out; + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .map(out -> new String(out.toByteArray(), StandardCharsets.UTF_8)); + } + + static Mono toStoreResponse(HttpResponse httpClientResponse, HttpRequest httpRequest) { + + HttpHeaders httpResponseHeaders = httpClientResponse.headers(); + + Mono contentObservable; + + if (httpRequest.httpMethod() == HttpMethod.DELETE) { + // for delete we don't expect any body + contentObservable = Mono.just(StringUtils.EMPTY); + } else { + contentObservable = toString(httpClientResponse.body()); + } + + return contentObservable.flatMap(content -> { + try { + // transforms to Mono + StoreResponse rsp = new StoreResponse(httpClientResponse.statusCode(), HttpUtils.unescape(httpResponseHeaders.toMap().entrySet()), content); + return Mono.just(rsp); + } catch (Exception e) { + return Mono.error(e); + } + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClient.java new file mode 100644 index 0000000000000..28cb645ee9f5b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClient.java @@ -0,0 +1,381 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdEndpoint; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdMetrics; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdObjectMapper; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestArgs; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestRecord; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdServiceEndpoint; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import io.netty.handler.ssl.SslContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import reactor.core.publisher.SignalType; + +import java.io.IOException; +import java.net.URI; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +@JsonSerialize(using = RntbdTransportClient.JsonSerializer.class) +public final class RntbdTransportClient extends TransportClient { + + // region Fields + + private static final AtomicLong instanceCount = new AtomicLong(); + private static final Logger logger = LoggerFactory.getLogger(RntbdTransportClient.class); + private static final String namePrefix = RntbdTransportClient.class.getSimpleName() + '-'; + + private final AtomicBoolean closed = new AtomicBoolean(); + private final RntbdEndpoint.Provider endpointProvider; + private final RntbdMetrics metrics; + private final String name; + + // endregion + + // region Constructors + + RntbdTransportClient(final RntbdEndpoint.Provider endpointProvider) { + this.name = RntbdTransportClient.namePrefix + RntbdTransportClient.instanceCount.incrementAndGet(); + this.endpointProvider = endpointProvider; + this.metrics = new RntbdMetrics(this.name); + } + + RntbdTransportClient(final Options options, final SslContext sslContext) { + this(new RntbdServiceEndpoint.Provider(options, sslContext)); + } + + RntbdTransportClient(final Configs configs, final int requestTimeoutInSeconds, final UserAgentContainer userAgent) { + this(new Options.Builder(requestTimeoutInSeconds).userAgent(userAgent).build(), configs.getSslContext()); + } + + // endregion + + // region Methods + + @Override + public void close() { + + logger.debug("\n [{}] CLOSE", this); + + if (this.closed.compareAndSet(false, true)) { + this.endpointProvider.close(); + this.metrics.close(); + return; + } + + logger.debug("\n [{}]\n already closed", this); + } + + @Override + public Mono invokeStoreAsync(final URI physicalAddress, final RxDocumentServiceRequest request) { + + checkNotNull(physicalAddress, "physicalAddress"); + checkNotNull(request, "request"); + this.throwIfClosed(); + + final RntbdRequestArgs requestArgs = new RntbdRequestArgs(request, physicalAddress); + + if (logger.isDebugEnabled()) { + requestArgs.traceOperation(logger, null, "invokeStoreAsync"); + logger.debug("\n [{}]\n {}\n INVOKE_STORE_ASYNC", this, requestArgs); + } + + final RntbdEndpoint endpoint = this.endpointProvider.get(physicalAddress); + this.metrics.incrementRequestCount(); + + final RntbdRequestRecord requestRecord = endpoint.request(requestArgs); + + requestRecord.whenComplete((response, error) -> { + this.metrics.incrementResponseCount(); + if (error != null) { + this.metrics.incrementErrorResponseCount(); + } + }); + + return Mono.fromFuture(requestRecord).doFinally(signal -> { + if (signal == SignalType.CANCEL) { + requestRecord.cancel(false); + } + }); + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + private void throwIfClosed() { + checkState(!this.closed.get(), "%s is closed", this); + } + + // endregion + + // region Types + + static final class JsonSerializer extends StdSerializer { + + public JsonSerializer() { + this(null); + } + + public JsonSerializer(Class type) { + super(type); + } + + @Override + public void serialize(RntbdTransportClient value, JsonGenerator generator, SerializerProvider provider) throws IOException { + + generator.writeStartObject(); + + generator.writeArrayFieldStart(value.name); + + value.endpointProvider.list().forEach(endpoint -> { + try { + generator.writeObject(endpoint); + } catch (IOException error) { + logger.error("failed to serialize {} due to ", endpoint.getName(), error); + } + }); + + generator.writeEndArray(); + + generator.writeObjectField("config", value.endpointProvider.config()); + generator.writeObjectField("metrics", value.metrics); + generator.writeEndObject(); + } + } + + public static final class Options { + + // region Fields + + private final String certificateHostNameOverride; + private final int maxChannelsPerEndpoint; + private final int maxRequestsPerChannel; + private final Duration connectionTimeout; + private final int partitionCount; + private final Duration receiveHangDetectionTime; + private final Duration requestTimeout; + private final Duration sendHangDetectionTime; + private final UserAgentContainer userAgent; + + // endregion + + // region Constructors + + private Options(Builder builder) { + + this.certificateHostNameOverride = builder.certificateHostNameOverride; + this.maxChannelsPerEndpoint = builder.maxChannelsPerEndpoint; + this.maxRequestsPerChannel = builder.maxRequestsPerChannel; + this.connectionTimeout = builder.connectionTimeout == null ? builder.requestTimeout : builder.connectionTimeout; + this.partitionCount = builder.partitionCount; + this.requestTimeout = builder.requestTimeout; + this.receiveHangDetectionTime = builder.receiveHangDetectionTime; + this.sendHangDetectionTime = builder.sendHangDetectionTime; + this.userAgent = builder.userAgent; + } + + // endregion + + // region Accessors + + public String getCertificateHostNameOverride() { + return this.certificateHostNameOverride; + } + + public int getMaxChannelsPerEndpoint() { + return this.maxChannelsPerEndpoint; + } + + public int getMaxRequestsPerChannel() { + return this.maxRequestsPerChannel; + } + + public Duration getConnectionTimeout() { + return this.connectionTimeout; + } + + public int getPartitionCount() { + return this.partitionCount; + } + + public Duration getReceiveHangDetectionTime() { + return this.receiveHangDetectionTime; + } + + public Duration getRequestTimeout() { + return this.requestTimeout; + } + + public Duration getSendHangDetectionTime() { + return this.sendHangDetectionTime; + } + + public UserAgentContainer getUserAgent() { + return this.userAgent; + } + + // endregion + + // region Methods + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + // endregion + + // region Types + + public static class Builder { + + // region Fields + + private static final UserAgentContainer DEFAULT_USER_AGENT_CONTAINER = new UserAgentContainer(); + private static final Duration SIXTY_FIVE_SECONDS = Duration.ofSeconds(65L); + private static final Duration TEN_SECONDS = Duration.ofSeconds(10L); + + // Required parameters + + private String certificateHostNameOverride = null; + + // Optional parameters + + private int maxChannelsPerEndpoint = 10; + private int maxRequestsPerChannel = 30; + private Duration connectionTimeout = null; + private int partitionCount = 1; + private Duration receiveHangDetectionTime = SIXTY_FIVE_SECONDS; + private Duration requestTimeout; + private Duration sendHangDetectionTime = TEN_SECONDS; + private UserAgentContainer userAgent = DEFAULT_USER_AGENT_CONTAINER; + + // endregion + + // region Constructors + + public Builder(Duration requestTimeout) { + this.requestTimeout(requestTimeout); + } + + public Builder(int requestTimeoutInSeconds) { + this(Duration.ofSeconds(requestTimeoutInSeconds)); + } + + // endregion + + // region Methods + + public Options build() { + return new Options(this); + } + + public Builder certificateHostNameOverride(final String value) { + this.certificateHostNameOverride = value; + return this; + } + + public Builder connectionTimeout(final Duration value) { + checkArgument(value == null || value.compareTo(Duration.ZERO) > 0, "value: %s", value); + this.connectionTimeout = value; + return this; + } + + public Builder maxRequestsPerChannel(final int value) { + checkArgument(value > 0, "value: %s", value); + this.maxRequestsPerChannel = value; + return this; + } + + public Builder maxChannelsPerEndpoint(final int value) { + checkArgument(value > 0, "value: %s", value); + this.maxChannelsPerEndpoint = value; + return this; + } + + public Builder partitionCount(final int value) { + checkArgument(value > 0, "value: %s", value); + this.partitionCount = value; + return this; + } + + public Builder receiveHangDetectionTime(final Duration value) { + + checkNotNull(value, "value: null"); + checkArgument(value.compareTo(Duration.ZERO) > 0, "value: %s", value); + + this.receiveHangDetectionTime = value; + return this; + } + + public Builder requestTimeout(final Duration value) { + + checkNotNull(value, "value: null"); + checkArgument(value.compareTo(Duration.ZERO) > 0, "value: %s", value); + + this.requestTimeout = value; + return this; + } + + public Builder sendHangDetectionTime(final Duration value) { + + checkNotNull(value, "value: null"); + checkArgument(value.compareTo(Duration.ZERO) > 0, "value: %s", value); + + this.sendHangDetectionTime = value; + return this; + } + + public Builder userAgent(final UserAgentContainer value) { + checkNotNull(value, "value: null"); + this.userAgent = value; + return this; + } + + // endregion + } + + // endregion + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerProperties.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerProperties.java new file mode 100644 index 0000000000000..bf79099d9e495 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerProperties.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +final public class ServerProperties { + + final private String agent, version; + + public ServerProperties(String agent, String version) { + this.agent = agent; + this.version = version; + } + + public String getAgent() { + return this.agent; + } + + public String getVersion() { + return this.version; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerStoreModel.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerStoreModel.java new file mode 100644 index 0000000000000..2c0731145e505 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServerStoreModel.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.RxStoreModel; +import com.azure.data.cosmos.internal.Strings; +import org.apache.commons.lang3.EnumUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class ServerStoreModel implements RxStoreModel { + private final StoreClient storeClient; + + public ServerStoreModel(StoreClient storeClient) { + this.storeClient = storeClient; + } + + public Flux processMessage(RxDocumentServiceRequest request) { + String requestConsistencyLevelHeaderValue = request.getHeaders().get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL); + + request.requestContext.originalRequestConsistencyLevel = null; + + if (!Strings.isNullOrEmpty(requestConsistencyLevelHeaderValue)) { + ConsistencyLevel requestConsistencyLevel; + + if ((requestConsistencyLevel = EnumUtils.getEnum(ConsistencyLevel.class, Strings.fromCamelCaseToUpperCase(requestConsistencyLevelHeaderValue))) == null) { + return Flux.error(new BadRequestException( + String.format( + RMResources.InvalidHeaderValue, + requestConsistencyLevelHeaderValue, + HttpConstants.HttpHeaders.CONSISTENCY_LEVEL))); + } + + request.requestContext.originalRequestConsistencyLevel = requestConsistencyLevel; + } + + if (ReplicatedResourceClient.isMasterResource(request.getResourceType())) { + request.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.STRONG.toString()); + } + + Mono response = this.storeClient.processMessageAsync(request); + return response.flux(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServiceConfig.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServiceConfig.java new file mode 100644 index 0000000000000..c3c4c5c31bd7d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/ServiceConfig.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +class ServiceConfig { + final static ServiceConfig instance = new ServiceConfig(); + public SystemReplicationPolicy systemReplicationPolicy = new SystemReplicationPolicy(); + public SystemReplicationPolicy userReplicationPolicy = new SystemReplicationPolicy(); + + public static ServiceConfig getInstance() { + return instance; + } + + class SystemReplicationPolicy { + public static final int MaxReplicaSetSize = 4; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClient.java new file mode 100644 index 0000000000000..f12f4d6f17e8e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClient.java @@ -0,0 +1,238 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.internal.BackoffRetryUtility; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.IRetryPolicy; +import com.azure.data.cosmos.internal.ISessionToken; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.SessionContainer; +import com.azure.data.cosmos.internal.SessionTokenHelper; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import org.apache.commons.lang3.math.NumberUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * Instantiated to issue direct connectivity requests to the backend on: + * - GATEWAY (for gateway mode clients) + * - Client (for direct mode clients) + * StoreClient uses the ReplicatedResourceClient to make requests to the backend. + */ +public class StoreClient implements IStoreClient { + private final Logger logger = LoggerFactory.getLogger(StoreClient.class); + private final GatewayServiceConfigurationReader serviceConfigurationReader; + + private final SessionContainer sessionContainer; + private final ReplicatedResourceClient replicatedResourceClient; + private final TransportClient transportClient; + private final String ZERO_PARTITION_KEY_RANGE = "0"; + + public StoreClient( + Configs configs, + IAddressResolver addressResolver, + SessionContainer sessionContainer, + GatewayServiceConfigurationReader serviceConfigurationReader, IAuthorizationTokenProvider userTokenProvider, + TransportClient transportClient, + boolean useMultipleWriteLocations) { + this.transportClient = transportClient; + this.sessionContainer = sessionContainer; + this.serviceConfigurationReader = serviceConfigurationReader; + this.replicatedResourceClient = new ReplicatedResourceClient( + configs, + new AddressSelector(addressResolver, configs.getProtocol()), + sessionContainer, + this.transportClient, + serviceConfigurationReader, + userTokenProvider, + false, + useMultipleWriteLocations); + } + + @Override + public Mono processMessageAsync(RxDocumentServiceRequest request, IRetryPolicy retryPolicy, Function> prepareRequestAsyncDelegate) { + if (request == null) { + throw new NullPointerException("request"); + } + + Callable> storeResponseDelegate = () -> this.replicatedResourceClient.invokeAsync(request, prepareRequestAsyncDelegate); + + Mono storeResponse; + try { + storeResponse = retryPolicy != null + ? BackoffRetryUtility.executeRetry(storeResponseDelegate, retryPolicy) + : storeResponseDelegate.call(); + } catch (Exception e) { + return Mono.error(e); + } + + storeResponse = storeResponse.doOnError(e -> { + try { + CosmosClientException exception = Utils.as(e, CosmosClientException.class); + + if (exception == null) { + return; + } + + exception = BridgeInternal.setCosmosResponseDiagnostics(exception, request.requestContext.cosmosResponseDiagnostics); + + handleUnsuccessfulStoreResponse(request, exception); + } catch (Throwable throwable) { + logger.error("Unexpected failure in handling orig [{}]", e.getMessage(), e); + logger.error("Unexpected failure in handling orig [{}] : new [{}]", e.getMessage(), throwable.getMessage(), throwable); + } + } + ); + + return storeResponse.flatMap(sr -> { + try { + return Mono.just(this.completeResponse(sr, request)); + } catch (Exception e) { + return Mono.error(e); + } + }); + } + + private void handleUnsuccessfulStoreResponse(RxDocumentServiceRequest request, CosmosClientException exception) { + this.updateResponseHeader(request, exception.responseHeaders()); + if ((!ReplicatedResourceClient.isMasterResource(request.getResourceType())) && + (Exceptions.isStatusCode(exception, HttpConstants.StatusCodes.PRECONDITION_FAILED) || Exceptions.isStatusCode(exception, HttpConstants.StatusCodes.CONFLICT) || + (Exceptions.isStatusCode(exception, HttpConstants.StatusCodes.NOTFOUND) && + !Exceptions.isSubStatusCode(exception, HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)))) { + this.captureSessionToken(request, exception.responseHeaders()); + } + } + + private RxDocumentServiceResponse completeResponse( + StoreResponse storeResponse, + RxDocumentServiceRequest request) throws InternalServerErrorException { + if (storeResponse.getResponseHeaderNames().length != storeResponse.getResponseHeaderValues().length) { + throw new InternalServerErrorException(RMResources.InvalidBackendResponse); + } + + Map headers = new HashMap<>(storeResponse.getResponseHeaderNames().length); + for (int idx = 0; idx < storeResponse.getResponseHeaderNames().length; idx++) { + String name = storeResponse.getResponseHeaderNames()[idx]; + String value = storeResponse.getResponseHeaderValues()[idx]; + + headers.put(name, value); + } + + this.updateResponseHeader(request, headers); + this.captureSessionToken(request, headers); + storeResponse.setCosmosResponseDiagnostics(request.requestContext.cosmosResponseDiagnostics); + return new RxDocumentServiceResponse(storeResponse); + } + + private long getLSN(Map headers) { + long defaultValue = -1; + String value = headers.get(WFConstants.BackendHeaders.LSN); + + if (!Strings.isNullOrEmpty(value)) { + return NumberUtils.toLong(value, defaultValue); + + } + + return defaultValue; + } + + private void updateResponseHeader(RxDocumentServiceRequest request, Map headers) { + String requestConsistencyLevel = request.getHeaders().get(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL); + + boolean sessionConsistency = + this.serviceConfigurationReader.getDefaultConsistencyLevel() == ConsistencyLevel.SESSION || + (!Strings.isNullOrEmpty(requestConsistencyLevel) + && Strings.areEqualIgnoreCase(requestConsistencyLevel, ConsistencyLevel.SESSION.toString())); + + long storeLSN = this.getLSN(headers); + if (storeLSN == -1) { + return; + } + + String partitionKeyRangeId = headers.get(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID); + + if (Strings.isNullOrEmpty(partitionKeyRangeId)) { + String inputSession = request.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (!Strings.isNullOrEmpty(inputSession) + && inputSession.indexOf(ISessionToken.PARTITION_KEY_RANGE_SESSION_SEPARATOR) >= 1) { + partitionKeyRangeId = inputSession.substring(0, + inputSession.indexOf(ISessionToken.PARTITION_KEY_RANGE_SESSION_SEPARATOR)); + } else { + partitionKeyRangeId = ZERO_PARTITION_KEY_RANGE; + } + } + + ISessionToken sessionToken = null; + String sessionTokenResponseHeader = headers.get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (!Strings.isNullOrEmpty(sessionTokenResponseHeader)) { + sessionToken = SessionTokenHelper.parse(sessionTokenResponseHeader); + } + + if (sessionToken != null) { + headers.put(HttpConstants.HttpHeaders.SESSION_TOKEN, String.format( + "%s:%s", + partitionKeyRangeId, + sessionToken.convertToString())); + } + + headers.remove(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID); + } + + private void captureSessionToken(RxDocumentServiceRequest request, Map headers) { + if (request.getResourceType() == ResourceType.DocumentCollection + && request.getOperationType() == OperationType.Delete) { + String resourceId; + if (request.getIsNameBased()) { + resourceId = headers.get(HttpConstants.HttpHeaders.OWNER_ID); + } else { + resourceId = request.getResourceId(); + } + this.sessionContainer.clearTokenByResourceId(resourceId); + } else { + this.sessionContainer.setSessionToken(request, headers); + } + } + + // TODO RNTBD support + // https://msdata.visualstudio.com/CosmosDB/SDK/_workitems/edit/262496 +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClientFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClientFactory.java new file mode 100644 index 0000000000000..6888f4908506d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreClientFactory.java @@ -0,0 +1,93 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.SessionContainer; +import com.azure.data.cosmos.internal.UserAgentContainer; + +// TODO: DANOBLE: no support for ICommunicationEventSource ask Ji +// Links: +// https://msdata.visualstudio.com/CosmosDB/SDK/_workitems/edit/262496 + +public class StoreClientFactory implements AutoCloseable { + private final Configs configs; + private final int maxConcurrentConnectionOpenRequests; + private final int requestTimeoutInSeconds; + private final Protocol protocol; + private final TransportClient transportClient; + private volatile boolean isClosed; + + public StoreClientFactory( + Configs configs, + int requestTimeoutInSeconds, + int maxConcurrentConnectionOpenRequests, + UserAgentContainer userAgent) { + + this.configs = configs; + this.protocol = configs.getProtocol(); + this.requestTimeoutInSeconds = requestTimeoutInSeconds; + this.maxConcurrentConnectionOpenRequests = maxConcurrentConnectionOpenRequests; + + if (protocol == Protocol.HTTPS) { + this.transportClient = new HttpTransportClient(configs, requestTimeoutInSeconds, userAgent); + } else if (protocol == Protocol.TCP){ + this.transportClient = new RntbdTransportClient(configs, requestTimeoutInSeconds, userAgent); + } else { + throw new IllegalArgumentException(String.format("protocol: %s", this.protocol)); + } + } + + public void close() throws Exception { + this.transportClient.close(); + this.isClosed = true; + } + + // TODO wew don't have support for the following yet + // TODO enableReadRequestsFallback ask Ji + // TODO useFallbackClient ask Ji + public StoreClient createStoreClient( + IAddressResolver addressResolver, + SessionContainer sessionContainer, + GatewayServiceConfigurationReader serviceConfigurationReader, + IAuthorizationTokenProvider authorizationTokenProvider, + boolean useMultipleWriteLocations) { + this.throwIfClosed(); + + return new StoreClient(configs, + addressResolver, + sessionContainer, + serviceConfigurationReader, + authorizationTokenProvider, + this.transportClient, + useMultipleWriteLocations); + } + + private void throwIfClosed() { + if (isClosed) { + throw new IllegalStateException("storeClient already closed!"); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreReader.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreReader.java new file mode 100644 index 0000000000000..ec2415fc96ea2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreReader.java @@ -0,0 +1,893 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.ISessionToken; +import com.azure.data.cosmos.internal.Integers; +import com.azure.data.cosmos.internal.MutableVolatile; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.SessionTokenHelper; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.Exceptions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static com.azure.data.cosmos.internal.Exceptions.isSubStatusCode; + +public class StoreReader { + private final Logger logger = LoggerFactory.getLogger(StoreReader.class); + private final TransportClient transportClient; + private final AddressSelector addressSelector; + private final ISessionContainer sessionContainer; + private String lastReadAddress; + + public StoreReader( + TransportClient transportClient, + AddressSelector addressSelector, + ISessionContainer sessionContainer) { + this.transportClient = transportClient; + this.addressSelector = addressSelector; + this.sessionContainer = sessionContainer; + } + + public Mono> readMultipleReplicaAsync( + RxDocumentServiceRequest entity, + boolean includePrimary, + int replicaCountToRead, + boolean requiresValidLsn, + boolean useSessionToken, + ReadMode readMode) { + return readMultipleReplicaAsync(entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode, false, false); + } + + /** + * Makes requests to multiple replicas at once and returns responses + * @param entity RxDocumentServiceRequest + * @param includePrimary flag to indicate whether to indicate primary replica in the reads + * @param replicaCountToRead number of replicas to read from + * @param requiresValidLsn flag to indicate whether a valid lsn is required to consider a response as valid + * @param useSessionToken flag to indicate whether to use session token + * @param readMode READ mode + * @param checkMinLSN set minimum required session lsn + * @param forceReadAll reads from all available replicas to gather result from readsToRead number of replicas + * @return ReadReplicaResult which indicates the LSN and whether Quorum was Met / Not Met etc + */ + public Mono> readMultipleReplicaAsync( + RxDocumentServiceRequest entity, + boolean includePrimary, + int replicaCountToRead, + boolean requiresValidLsn, + boolean useSessionToken, + ReadMode readMode, + boolean checkMinLSN, + boolean forceReadAll) { + + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + String originalSessionToken = entity.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + + if (entity.requestContext.cosmosResponseDiagnostics == null) { + entity.requestContext.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + + Mono readQuorumResultObs = this.readMultipleReplicasInternalAsync( + entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode, checkMinLSN, forceReadAll); + + return readQuorumResultObs.flatMap(readQuorumResult -> { + if (entity.requestContext.performLocalRefreshOnGoneException && + readQuorumResult.retryWithForceRefresh && + !entity.requestContext.forceRefreshAddressCache) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + entity.requestContext.forceRefreshAddressCache = true; + + return this.readMultipleReplicasInternalAsync( + entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode, false /*checkMinLSN*/, forceReadAll) + .map(r -> r.responses); + } else { + return Mono.just(readQuorumResult.responses); + } + }).flux().doAfterTerminate(() -> SessionTokenHelper.setOriginalSessionToken(entity, originalSessionToken)).single(); + } + + private Flux earlyResultIfNotEnoughReplicas(List replicaAddresses, + RxDocumentServiceRequest request, + int replicaCountToRead) { + if (replicaAddresses.size() < replicaCountToRead) { + // if not enough replicas, return ReadReplicaResult + if (!request.requestContext.forceRefreshAddressCache) { + return Flux.just(new ReadReplicaResult(true /*retryWithForceRefresh*/, Collections.emptyList())); + } else { + return Flux.just(new ReadReplicaResult(false /*retryWithForceRefresh*/, Collections.emptyList())); + } + } else { + // if there are enough replicas, move on + return Flux.empty(); + } + } + + private Flux toStoreResult(RxDocumentServiceRequest request, + Pair, URI> storeRespAndURI, + ReadMode readMode, + boolean requiresValidLsn) { + + return storeRespAndURI.getLeft() + .flatMap(storeResponse -> { + try { + StoreResult storeResult = this.createStoreResult( + storeResponse, + null, requiresValidLsn, + readMode != ReadMode.Strong, + storeRespAndURI.getRight()); + + BridgeInternal.getContactedReplicas(request.requestContext.cosmosResponseDiagnostics).add(storeRespAndURI.getRight()); + return Flux.just(storeResult); + } catch (Exception e) { + // RxJava1 doesn't allow throwing checked exception from Observable operators + return Flux.error(e); + } + } + ).onErrorResume(t -> { + + try { + logger.debug("Exception {} is thrown while doing readMany", t); + Exception storeException = Utils.as(t, Exception.class); + if (storeException == null) { + return Flux.error(t); + } + +// Exception storeException = readTask.Exception != null ? readTask.Exception.InnerException : null; + StoreResult storeResult = this.createStoreResult( + null, + storeException, requiresValidLsn, + readMode != ReadMode.Strong, + null); + if (storeException instanceof TransportException) { + BridgeInternal.getFailedReplicas(request.requestContext.cosmosResponseDiagnostics).add(storeRespAndURI.getRight()); + } + return Flux.just(storeResult); + } catch (Exception e) { + // RxJava1 doesn't allow throwing checked exception from Observable operators + return Flux.error(e); + } + }); + } + + private Flux> readFromReplicas(List resultCollector, + List resolveApiResults, + final AtomicInteger replicasToRead, + RxDocumentServiceRequest entity, + boolean includePrimary, + int replicaCountToRead, + boolean requiresValidLsn, + boolean useSessionToken, + ReadMode readMode, + boolean checkMinLSN, + boolean forceReadAll, + final MutableVolatile requestSessionToken, + final MutableVolatile hasGoneException, + boolean enforceSessionCheck, + final MutableVolatile shortCircut) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Flux.error(new GoneException()); + } + List, URI>> readStoreTasks = new ArrayList<>(); + int uriIndex = StoreReader.generateNextRandom(resolveApiResults.size()); + + while (resolveApiResults.size() > 0) { + uriIndex = uriIndex % resolveApiResults.size(); + URI uri = resolveApiResults.get(uriIndex); + Pair, URI> res; + try { + res = this.readFromStoreAsync(resolveApiResults.get(uriIndex), + entity); + + } catch (Exception e) { + res = Pair.of(Mono.error(e), uri); + } + + readStoreTasks.add(Pair.of(res.getLeft().flux(), res.getRight())); + resolveApiResults.remove(uriIndex); + + + if (!forceReadAll && readStoreTasks.size() == replicasToRead.get()) { + break; + } + } + + replicasToRead.set(readStoreTasks.size() >= replicasToRead.get() ? 0 : replicasToRead.get() - readStoreTasks.size()); + + + List> storeResult = readStoreTasks + .stream() + .map(item -> toStoreResult(entity, item, readMode, requiresValidLsn)) + .collect(Collectors.toList()); + Flux allStoreResults = Flux.merge(storeResult); + + return allStoreResults.collectList().onErrorResume(e -> { + if (Exceptions.isMultiple(e)) { + logger.info("Captured composite exception"); + List exceptions = Exceptions.unwrapMultiple(e); + assert !exceptions.isEmpty(); + return Mono.error(exceptions.get(0)); + } + + return Mono.error(e); + }).map(newStoreResults -> { + for (StoreResult srr : newStoreResults) { + + entity.requestContext.requestChargeTracker.addCharge(srr.requestCharge); + BridgeInternal.recordResponse(entity.requestContext.cosmosResponseDiagnostics, entity, srr); + if (srr.isValid) { + + try { + + if (requestSessionToken.v == null + || (srr.sessionToken != null && requestSessionToken.v.isValid(srr.sessionToken)) + || (!enforceSessionCheck && !srr.isNotFoundException)) { + resultCollector.add(srr); + } + + } catch (Exception e) { + // TODO: what to do on exception? + } + } + + hasGoneException.v = hasGoneException.v || (srr.isGoneException && !srr.isInvalidPartitionException); + + if (resultCollector.size() >= replicaCountToRead) { + if (hasGoneException.v && !entity.requestContext.performedBackgroundAddressRefresh) { + this.startBackgroundAddressRefresh(entity); + entity.requestContext.performedBackgroundAddressRefresh = true; + } + + shortCircut.v = new ReadReplicaResult(false, resultCollector); + replicasToRead.set(0); + return resultCollector; + } + + // Remaining replicas + replicasToRead.set(replicaCountToRead - resultCollector.size()); + } + return resultCollector; + }).flux(); + } + + private ReadReplicaResult createReadReplicaResult(List responseResult, + int replicaCountToRead, + int resolvedAddressCount, + boolean hasGoneException, + RxDocumentServiceRequest entity) throws CosmosClientException { + if (responseResult.size() < replicaCountToRead) { + logger.debug("Could not get quorum number of responses. " + + "ValidResponsesReceived: {} ResponsesExpected: {}, ResolvedAddressCount: {}, ResponsesString: {}", + responseResult.size(), + replicaCountToRead, + resolvedAddressCount, + String.join(";", responseResult.stream().map(r -> r.toString()).collect(Collectors.toList()))); + + if (hasGoneException) { + if (!entity.requestContext.performLocalRefreshOnGoneException) { + // If we are not supposed to act upon GoneExceptions here, just throw them + throw new GoneException(); + } else if (!entity.requestContext.forceRefreshAddressCache) { + // We could not obtain valid read quorum number of responses even when we went through all the secondary addresses + // Attempt force refresh and start over again. + return new ReadReplicaResult(true, responseResult); + } + } + } + + return new ReadReplicaResult(false, responseResult); + } + + /** + * Makes requests to multiple replicas at once and returns responses + * @param entity DocumentServiceRequest + * @param includePrimary flag to indicate whether to indicate primary replica in the reads + * @param replicaCountToRead number of replicas to read from + * @param requiresValidLsn flag to indicate whether a valid lsn is required to consider a response as valid + * @param useSessionToken flag to indicate whether to use session token + * @param readMode READ mode + * @param checkMinLSN set minimum required session lsn + * @param forceReadAll will read from all available replicas to put together result from readsToRead number of replicas + * @return ReadReplicaResult which indicates the LSN and whether Quorum was Met / Not Met etc + */ + private Mono readMultipleReplicasInternalAsync(RxDocumentServiceRequest entity, + boolean includePrimary, + int replicaCountToRead, + boolean requiresValidLsn, + boolean useSessionToken, + ReadMode readMode, + boolean checkMinLSN, + boolean forceReadAll) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + String requestedCollectionId = null; + + if (entity.forceNameCacheRefresh) { + requestedCollectionId = entity.requestContext.resolvedCollectionRid; + } + + Mono> resolveApiResultsObs = this.addressSelector.resolveAllUriAsync( + entity, + includePrimary, + entity.requestContext.forceRefreshAddressCache); + + if (!StringUtils.isEmpty(requestedCollectionId) && !StringUtils.isEmpty(entity.requestContext.resolvedCollectionRid)) { + if (!requestedCollectionId.equals(entity.requestContext.resolvedCollectionRid)) { + this.sessionContainer.clearTokenByResourceId(requestedCollectionId); + } + } + + return resolveApiResultsObs.flux() + .map(list -> Collections.synchronizedList(new ArrayList<>(list))) + .flatMap( + resolveApiResults -> { + try { + MutableVolatile requestSessionToken = new MutableVolatile<>(); + if (useSessionToken) { + SessionTokenHelper.setPartitionLocalSessionToken(entity, this.sessionContainer); + if (checkMinLSN) { + requestSessionToken.v = entity.requestContext.sessionToken; + } + } else { + entity.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + + Flux y = earlyResultIfNotEnoughReplicas(resolveApiResults, entity, replicaCountToRead); + return y.switchIfEmpty( + Flux.defer(() -> { + + List storeResultList = Collections.synchronizedList(new ArrayList<>()); + AtomicInteger replicasToRead = new AtomicInteger(replicaCountToRead); + + // string clientVersion = entity.Headers[HttpConstants.HttpHeaders.Version]; + // enforceSessionCheck = string.IsNullOrEmpty(clientVersion) ? false : VersionUtility.IsLaterThan(clientVersion, HttpConstants.Versions.v2016_05_30); + // TODO: enforceSessionCheck is true, replace with true + boolean enforceSessionCheck = true; + + MutableVolatile hasGoneException = new MutableVolatile(false); + MutableVolatile shortCircuitResult = new MutableVolatile(); + + return Flux.defer(() -> + readFromReplicas( + storeResultList, + resolveApiResults, + replicasToRead, + entity, + includePrimary, + replicaCountToRead, + requiresValidLsn, + useSessionToken, + readMode, + checkMinLSN, + forceReadAll, + requestSessionToken, + hasGoneException, + enforceSessionCheck, + shortCircuitResult)) + // repeat().takeUntil() simulate a while loop pattern + .repeat() + .takeUntil(x -> { + // Loop until we have the read quorum number of valid responses or if we have read all the replicas + if (replicasToRead.get() > 0 && resolveApiResults.size() > 0) { + // take more from the source observable + return false; + } else { + // enough result + return true; + } + }) + .thenMany( + Flux.defer(() -> { + try { + // TODO: some fields which get updated need to be thread-safe + return Flux.just(createReadReplicaResult(storeResultList, replicaCountToRead, resolveApiResults.size(), hasGoneException.v, entity)); + } catch (Exception e) { + return Flux.error(e); + } + } + )); + })); + } catch (Exception e) { + return Flux.error(e); + } + } + ).single(); + } + + public Mono readPrimaryAsync( + RxDocumentServiceRequest entity, + boolean requiresValidLsn, + boolean useSessionToken) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + String originalSessionToken = entity.getHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (entity.requestContext.cosmosResponseDiagnostics == null) { + entity.requestContext.cosmosResponseDiagnostics = BridgeInternal.createCosmosResponseDiagnostics(); + } + + return this.readPrimaryInternalAsync( + entity, requiresValidLsn, useSessionToken).flatMap( + readQuorumResult -> { + + if (entity.requestContext.performLocalRefreshOnGoneException && + readQuorumResult.retryWithForceRefresh && + !entity.requestContext.forceRefreshAddressCache) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + entity.requestContext.forceRefreshAddressCache = true; + return this.readPrimaryInternalAsync(entity, requiresValidLsn, useSessionToken); + } else { + return Mono.just(readQuorumResult); + } + } + ).flatMap(readQuorumResult -> { + + // RxJava1 doesn't allow throwing Typed Exception from Observable.map(.) + // this is a design flaw which was fixed in RxJava2. + + // as our core is built on top of RxJava1 here we had to use Observable.flatMap(.) not map(.) + // once we switch to RxJava2 we can move to Observable.map(.) + // https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#functional-interfaces + if (readQuorumResult.responses.size() == 0) { + return Mono.error(new GoneException(RMResources.Gone)); + } + + return Mono.just(readQuorumResult.responses.get(0)); + + }).doOnEach(arg -> { + try { + SessionTokenHelper.setOriginalSessionToken(entity, originalSessionToken); + } catch (Throwable throwable) { + logger.error("Unexpected failure in handling orig [{}]: new [{}]", arg, throwable.getMessage(), throwable); + } + } + ); + } + + private Mono readPrimaryInternalAsync( + RxDocumentServiceRequest entity, + boolean requiresValidLsn, + boolean useSessionToken) { + if (entity.requestContext.timeoutHelper.isElapsed()) { + return Mono.error(new GoneException()); + } + + Mono primaryUriObs = this.addressSelector.resolvePrimaryUriAsync( + entity, + entity.requestContext.forceRefreshAddressCache); + + Mono storeResultObs = primaryUriObs.flatMap( + primaryUri -> { + try { + if (useSessionToken) { + SessionTokenHelper.setPartitionLocalSessionToken(entity, this.sessionContainer); + } else { + // Remove whatever session token can be there in headers. + // We don't need it. If it is global - backend will not undersand it. + // But there's no point in producing partition local sesison token. + entity.getHeaders().remove(HttpConstants.HttpHeaders.SESSION_TOKEN); + } + + + Pair, URI> storeResponseObsAndUri = this.readFromStoreAsync(primaryUri, entity); + + return storeResponseObsAndUri.getLeft().flatMap( + storeResponse -> { + + try { + StoreResult storeResult = this.createStoreResult( + storeResponse != null ? storeResponse : null, + null, requiresValidLsn, + true, + storeResponse != null ? storeResponseObsAndUri.getRight() : null); + return Mono.just(storeResult); + } catch (CosmosClientException e) { + return Mono.error(e); + } + } + + ); + + } catch (CosmosClientException e) { + // RxJava1 doesn't allow throwing checked exception from Observable:map + return Mono.error(e); + } + + } + ).onErrorResume(t -> { + logger.debug("Exception {} is thrown while doing READ Primary", t); + + Exception storeTaskException = Utils.as(t, Exception.class); + if (storeTaskException == null) { + return Mono.error(t); + } + + try { + StoreResult storeResult = this.createStoreResult( + null, + storeTaskException, requiresValidLsn, + true, + null); + return Mono.just(storeResult); + } catch (CosmosClientException e) { + // RxJava1 doesn't allow throwing checked exception from Observable operators + return Mono.error(e); + } + }); + + return storeResultObs.map(storeResult -> { + BridgeInternal.recordResponse(entity.requestContext.cosmosResponseDiagnostics, entity, storeResult); + entity.requestContext.requestChargeTracker.addCharge(storeResult.requestCharge); + + if (storeResult.isGoneException && !storeResult.isInvalidPartitionException) { + return new ReadReplicaResult(true, Collections.emptyList()); + } + + return new ReadReplicaResult(false, Collections.singletonList(storeResult)); + }); + } + + private Pair, URI> readFromStoreAsync( + URI physicalAddress, + RxDocumentServiceRequest request) throws CosmosClientException { + + if (request.requestContext.timeoutHelper.isElapsed()) { + throw new GoneException(); + } + + //QueryRequestPerformanceActivity activity = null; + // TODO: ifNoneMatch and maxPageSize are not used in the .Net code. check with Ji + String ifNoneMatch = request.getHeaders().get(HttpConstants.HttpHeaders.IF_NONE_MATCH); + String continuation = null; + String maxPageSize = null; + + // TODO: is this needed + this.lastReadAddress = physicalAddress.toString(); + + if (request.getOperationType() == OperationType.ReadFeed || + request.getOperationType() == OperationType.Query) { + continuation = request.getHeaders().get(HttpConstants.HttpHeaders.CONTINUATION); + maxPageSize = request.getHeaders().get(HttpConstants.HttpHeaders.PAGE_SIZE); + + if (continuation != null && continuation.contains(";")) { + String[] parts = StringUtils.split(continuation, ';'); + if (parts.length < 3) { + throw new BadRequestException(String.format( + RMResources.InvalidHeaderValue, + continuation, + HttpConstants.HttpHeaders.CONTINUATION)); + } + + continuation = parts[0]; + } + + request.setContinuation(continuation); + + // TODO: troubleshooting + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + //activity = CustomTypeExtensions.StartActivity(request); + } + + switch (request.getOperationType()) { + case Read: + case Head: { + Mono storeResponseObs = this.transportClient.invokeResourceOperationAsync( + physicalAddress, + request); + + return Pair.of(storeResponseObs, physicalAddress); + + } + + case ReadFeed: + case HeadFeed: + case Query: + case SqlQuery: + case ExecuteJavaScript: { + Mono storeResponseObs = StoreReader.completeActivity(this.transportClient.invokeResourceOperationAsync( + physicalAddress, + request), null); + // TODO activity); + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + return Pair.of(storeResponseObs, physicalAddress); + } + + default: + throw new IllegalStateException(String.format("Unexpected operation type {%s}", request.getOperationType())); + } + } + + + private static Mono completeActivity(Mono task, Object activity) { + // TODO: client statistics + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/258624 + return task; + } + + StoreResult createStoreResult(StoreResponse storeResponse, + Exception responseException, + boolean requiresValidLsn, + boolean useLocalLSNBasedHeaders, + URI storePhysicalAddress) throws CosmosClientException { + + if (responseException == null) { + String headerValue = null; + long quorumAckedLSN = -1; + int currentReplicaSetSize = -1; + int currentWriteQuorum = -1; + long globalCommittedLSN = -1; + int numberOfReadRegions = -1; + long itemLSN = -1; + if ((headerValue = storeResponse.getHeaderValue( + useLocalLSNBasedHeaders ? WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN : WFConstants.BackendHeaders.QUORUM_ACKED_LSN)) != null) { + quorumAckedLSN = Long.parseLong(headerValue); + } + + if ((headerValue = storeResponse.getHeaderValue(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE)) != null) { + currentReplicaSetSize = Integer.parseInt(headerValue); + } + + if ((headerValue = storeResponse.getHeaderValue(WFConstants.BackendHeaders.CURRENT_WRITE_QUORUM)) != null) { + currentWriteQuorum = Integer.parseInt(headerValue); + } + + double requestCharge = 0; + if ((headerValue = storeResponse.getHeaderValue(HttpConstants.HttpHeaders.REQUEST_CHARGE)) != null) { + requestCharge = Double.parseDouble(headerValue); + } + + if ((headerValue = storeResponse.getHeaderValue(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS)) != null) { + numberOfReadRegions = Integer.parseInt(headerValue); + } + + if ((headerValue = storeResponse.getHeaderValue(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN)) != null) { + globalCommittedLSN = Long.parseLong(headerValue); + } + + if ((headerValue = storeResponse.getHeaderValue( + useLocalLSNBasedHeaders ? WFConstants.BackendHeaders.ITEM_LOCAL_LSN : WFConstants.BackendHeaders.ITEM_LSN)) != null) { + itemLSN = Long.parseLong(headerValue); + } + + long lsn = -1; + if (useLocalLSNBasedHeaders) { + if ((headerValue = storeResponse.getHeaderValue(WFConstants.BackendHeaders.LOCAL_LSN)) != null) { + lsn = Long.parseLong(headerValue); + } + } else { + lsn = storeResponse.getLSN(); + } + + ISessionToken sessionToken = null; + // SESSION token response header is introduced from version HttpConstants.Versions.v2018_06_18 onwards. + // Previously it was only a request header + if ((headerValue = storeResponse.getHeaderValue(HttpConstants.HttpHeaders.SESSION_TOKEN)) != null) { + sessionToken = SessionTokenHelper.parse(headerValue); + } + + return new StoreResult( + /* storeResponse: */storeResponse, + /* exception: */ null, + /* partitionKeyRangeId: */ storeResponse.getPartitionKeyRangeId(), + /* lsn: */ lsn, + /* quorumAckedLsn: */ quorumAckedLSN, + /* requestCharge: */ requestCharge, + /* currentReplicaSetSize: */ currentReplicaSetSize, + /* currentWriteQuorum: */ currentWriteQuorum, + /* isValid: */true, + /* storePhysicalAddress: */ storePhysicalAddress, + /* globalCommittedLSN: */ globalCommittedLSN, + /* numberOfReadRegions: */ numberOfReadRegions, + /* itemLSN: */ itemLSN, + /* sessionToken: */ sessionToken); + } else { + CosmosClientException cosmosClientException = Utils.as(responseException, CosmosClientException.class); + if (cosmosClientException != null) { + StoreReader.verifyCanContinueOnException(cosmosClientException); + long quorumAckedLSN = -1; + int currentReplicaSetSize = -1; + int currentWriteQuorum = -1; + long globalCommittedLSN = -1; + int numberOfReadRegions = -1; + String headerValue = cosmosClientException.responseHeaders().get(useLocalLSNBasedHeaders ? WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN : WFConstants.BackendHeaders.QUORUM_ACKED_LSN); + if (!Strings.isNullOrEmpty(headerValue)) { + quorumAckedLSN = Long.parseLong(headerValue); + } + + headerValue = cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE); + if (!Strings.isNullOrEmpty(headerValue)) { + currentReplicaSetSize = Integer.parseInt(headerValue); + } + + headerValue = cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.CURRENT_WRITE_QUORUM); + if (!Strings.isNullOrEmpty(headerValue)) { + currentReplicaSetSize = Integer.parseInt(headerValue); + } + + double requestCharge = 0; + headerValue = cosmosClientException.responseHeaders().get(HttpConstants.HttpHeaders.REQUEST_CHARGE); + if (!Strings.isNullOrEmpty(headerValue)) { + requestCharge = Double.parseDouble(headerValue); + } + + headerValue = cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS); + if (!Strings.isNullOrEmpty(headerValue)) { + numberOfReadRegions = Integer.parseInt(headerValue); + } + + headerValue = cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN); + if (!Strings.isNullOrEmpty(headerValue)) { + globalCommittedLSN = Integer.parseInt(headerValue); + } + + long lsn = -1; + if (useLocalLSNBasedHeaders) { + headerValue = cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.LOCAL_LSN); + if (!Strings.isNullOrEmpty(headerValue)) { + lsn = Long.parseLong(headerValue); + } + } else { + lsn = BridgeInternal.getLSN(cosmosClientException); + } + + ISessionToken sessionToken = null; + + // SESSION token response header is introduced from version HttpConstants.Versions.v2018_06_18 onwards. + // Previously it was only a request header + headerValue = cosmosClientException.responseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + if (!Strings.isNullOrEmpty(headerValue)) { + sessionToken = SessionTokenHelper.parse(headerValue); + } + + return new StoreResult( + /* storeResponse: */ (StoreResponse) null, + /* exception: */ cosmosClientException, + /* partitionKeyRangeId: */BridgeInternal.getPartitionKeyRangeId(cosmosClientException), + /* lsn: */ lsn, + /* quorumAckedLsn: */ quorumAckedLSN, + /* requestCharge: */ requestCharge, + /* currentReplicaSetSize: */ currentReplicaSetSize, + /* currentWriteQuorum: */ currentWriteQuorum, + /* isValid: */!requiresValidLsn + || ((cosmosClientException.statusCode() != HttpConstants.StatusCodes.GONE || isSubStatusCode(cosmosClientException, HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE)) + && lsn >= 0), + // TODO: verify where exception.RequestURI is supposed to be set in .Net + /* storePhysicalAddress: */ storePhysicalAddress == null ? BridgeInternal.getRequestUri(cosmosClientException) : storePhysicalAddress, + /* globalCommittedLSN: */ globalCommittedLSN, + /* numberOfReadRegions: */ numberOfReadRegions, + /* itemLSN: */ -1, + sessionToken); + } else { + logger.error("Unexpected exception {} received while reading from store.", responseException.getMessage(), responseException); + return new StoreResult( + /* storeResponse: */ null, + /* exception: */ new InternalServerErrorException(RMResources.InternalServerError), + /* partitionKeyRangeId: */ (String) null, + /* lsn: */ -1, + /* quorumAckedLsn: */ -1, + /* requestCharge: */ 0, + /* currentReplicaSetSize: */ 0, + /* currentWriteQuorum: */ 0, + /* isValid: */ false, + /* storePhysicalAddress: */ storePhysicalAddress, + /* globalCommittedLSN: */-1, + /* numberOfReadRegions: */ 0, + /* itemLSN: */ -1, + /* sessionToken: */ null); + } + } + } + + void startBackgroundAddressRefresh(RxDocumentServiceRequest request) { + this.addressSelector.resolveAllUriAsync(request, true, true) + .publishOn(Schedulers.elastic()) + .subscribe( + r -> { + }, + e -> logger.warn( + "Background refresh of the addresses failed with {}", e.getMessage(), e) + ); + } + + private static int generateNextRandom(int maxValue) { + // The benefit of using ThreadLocalRandom.current() over Random is + // avoiding the synchronization contention due to multi-threading. + return ThreadLocalRandom.current().nextInt(maxValue); + } + + static void verifyCanContinueOnException(CosmosClientException ex) throws CosmosClientException { + if (ex instanceof PartitionKeyRangeGoneException) { + throw ex; + } + + if (ex instanceof PartitionKeyRangeIsSplittingException) { + throw ex; + } + + if (ex instanceof PartitionIsMigratingException) { + throw ex; + } + + String value = ex.responseHeaders().get(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE); + if (Strings.isNullOrWhiteSpace(value)) { + return; + } + + Integer result = Integers.tryParse(value); + if (result != null && result == 1) { + throw ex; + } + + return; + } + + private class ReadReplicaResult { + public ReadReplicaResult(boolean retryWithForceRefresh, List responses) { + this.retryWithForceRefresh = retryWithForceRefresh; + this.responses = responses; + } + + public final boolean retryWithForceRefresh; + public final List responses; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponse.java new file mode 100644 index 0000000000000..0639c6bb109c3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponse.java @@ -0,0 +1,151 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosResponseDiagnostics; +import com.azure.data.cosmos.internal.HttpConstants; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.util.List; +import java.util.Map.Entry; + +/** + * Used internally to represents a response from the store. + */ +public class StoreResponse { + final static Logger LOGGER = LoggerFactory.getLogger(StoreResponse.class); + final private int status; + final private String[] responseHeaderNames; + final private String[] responseHeaderValues; + final private InputStream httpEntityStream; + final private String content; + + private CosmosResponseDiagnostics cosmosResponseDiagnostics; + + public StoreResponse(int status, List> headerEntries, InputStream inputStream) { + this(status, headerEntries, null, inputStream); + } + + public StoreResponse(int status, List> headerEntries, String content) { + this(status, headerEntries, content, null); + } + + private StoreResponse( + int status, + List> headerEntries, + String content, + InputStream inputStream) { + responseHeaderNames = new String[headerEntries.size()]; + responseHeaderValues = new String[headerEntries.size()]; + + int i = 0; + + for(Entry headerEntry: headerEntries) { + responseHeaderNames[i] = headerEntry.getKey(); + responseHeaderValues[i] = headerEntry.getValue(); + i++; + } + + this.status = status; + + this.content = content; + this.httpEntityStream = inputStream; + } + + public int getStatus() { + return status; + } + + public String[] getResponseHeaderNames() { + return responseHeaderNames; + } + + public String[] getResponseHeaderValues() { + return responseHeaderValues; + } + + public String getResponseBody() { + return this.content; + } + + public InputStream getResponseStream() { + // Some operation type doesn't have a response stream so this can be null + return this.httpEntityStream; + } + + public long getLSN() { + String lsnString = this.getHeaderValue(WFConstants.BackendHeaders.LSN); + if (StringUtils.isNotEmpty(lsnString)) { + return Long.parseLong(lsnString); + } + + return -1; + } + + public String getPartitionKeyRangeId() { + return this.getHeaderValue(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID); + } + + public String getContinuation() { + return this.getHeaderValue(HttpConstants.HttpHeaders.CONTINUATION); + } + + public String getHeaderValue(String attribute) { + if (this.responseHeaderValues == null || this.responseHeaderNames.length != this.responseHeaderValues.length) { + return null; + } + + for (int i = 0; i < responseHeaderNames.length; i++) { + if (responseHeaderNames[i].equalsIgnoreCase(attribute)) { + return responseHeaderValues[i]; + } + } + + return null; + } + + public CosmosResponseDiagnostics getCosmosResponseDiagnostics() { + return cosmosResponseDiagnostics; + } + + void setCosmosResponseDiagnostics(CosmosResponseDiagnostics cosmosResponseDiagnostics) { + this.cosmosResponseDiagnostics = cosmosResponseDiagnostics; + } + + int getSubStatusCode() { + int subStatusCode = HttpConstants.SubStatusCodes.UNKNOWN; + String subStatusCodeString = this.getHeaderValue(WFConstants.BackendHeaders.SUB_STATUS); + if (StringUtils.isNotEmpty(subStatusCodeString)) { + try { + subStatusCode = Integer.parseInt(subStatusCodeString); + } catch (NumberFormatException e) { + // If value cannot be parsed as Integer, return Unknown. + } + } + return subStatusCode; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResult.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResult.java new file mode 100644 index 0000000000000..e48054103547c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/StoreResult.java @@ -0,0 +1,179 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.ISessionToken; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URI; + +public class StoreResult { + private final static Logger logger = LoggerFactory.getLogger(StoreResult.class); + + private final StoreResponse storeResponse; + private final CosmosClientException exception; + + final public long lsn; + final public String partitionKeyRangeId; + final public long quorumAckedLSN; + final public long globalCommittedLSN; + final public long numberOfReadRegions; + final public long itemLSN; + final public ISessionToken sessionToken; + final public double requestCharge; + final public int currentReplicaSetSize; + final public int currentWriteQuorum; + final public boolean isValid; + final public boolean isGoneException; + final public boolean isNotFoundException; + final public boolean isInvalidPartitionException; + final public URI storePhysicalAddress; + + public StoreResult( + StoreResponse storeResponse, + CosmosClientException exception, + String partitionKeyRangeId, + long lsn, + long quorumAckedLsn, + double requestCharge, + int currentReplicaSetSize, + int currentWriteQuorum, + boolean isValid, + URI storePhysicalAddress, + long globalCommittedLSN, + int numberOfReadRegions, + long itemLSN, + ISessionToken sessionToken) { + this.storeResponse = storeResponse; + this.exception = exception; + this.partitionKeyRangeId = partitionKeyRangeId; + this.lsn = lsn; + this.quorumAckedLSN = quorumAckedLsn; + this.requestCharge = requestCharge; + this.currentReplicaSetSize = currentReplicaSetSize; + this.currentWriteQuorum = currentWriteQuorum; + this.isValid = isValid; + this.isGoneException = this.exception != null && this.exception.statusCode() == HttpConstants.StatusCodes.GONE; + this.isNotFoundException = this.exception != null && this.exception.statusCode() == HttpConstants.StatusCodes.NOTFOUND; + this.isInvalidPartitionException = this.exception != null + && Exceptions.isNameCacheStale(this.exception); + this.storePhysicalAddress = storePhysicalAddress; + this.globalCommittedLSN = globalCommittedLSN; + this.numberOfReadRegions = numberOfReadRegions; + this.itemLSN = itemLSN; + this.sessionToken = sessionToken; + } + + public CosmosClientException getException() throws InternalServerErrorException { + if (this.exception == null) { + String message = "Exception should be available but found none"; + assert false : message; + logger.error(message); + throw new InternalServerErrorException(RMResources.InternalServerError); + } + + return exception; + } + + public StoreResponse toResponse() throws CosmosClientException { + return toResponse(null); + } + + public StoreResponse toResponse(RequestChargeTracker requestChargeTracker) throws CosmosClientException { + if (!this.isValid) { + if (this.exception == null) { + logger.error("Exception not set for invalid response"); + throw new InternalServerErrorException(RMResources.InternalServerError); + } + + throw this.exception; + } + + if (requestChargeTracker != null && this.isValid) { + StoreResult.setRequestCharge(this.storeResponse, this.exception, requestChargeTracker.getTotalRequestCharge()); + } + + if (this.exception != null) { + throw exception; + } + + return this.storeResponse; + } + + private static void setRequestCharge(StoreResponse response, CosmosClientException cosmosClientException, double totalRequestCharge) { + if (cosmosClientException != null) { + cosmosClientException.responseHeaders().put(HttpConstants.HttpHeaders.REQUEST_CHARGE, + Double.toString(totalRequestCharge)); + } + // Set total charge as final charge for the response. + else if (response.getResponseHeaderNames() != null) { + for (int i = 0; i < response.getResponseHeaderNames().length; ++i) { + if (Strings.areEqualIgnoreCase( + response.getResponseHeaderNames()[i], + HttpConstants.HttpHeaders.REQUEST_CHARGE)) { + response.getResponseHeaderValues()[i] = Double.toString(totalRequestCharge); + break; + } + } + } + } + + @Override + public String toString() { + int statusCode = 0; + int subStatusCode = HttpConstants.SubStatusCodes.UNKNOWN; + + if (this.storeResponse != null) { + statusCode = this.storeResponse.getStatus(); + subStatusCode = this.storeResponse.getSubStatusCode(); + } else if (this.exception != null) { + statusCode = this.exception.statusCode(); + subStatusCode = this.exception.subStatusCode(); + } + + return "storePhysicalAddress: " + this.storePhysicalAddress + + ", lsn: " + this.lsn + + ", globalCommittedLsn: " + this.globalCommittedLSN + + ", partitionKeyRangeId: " + this.partitionKeyRangeId + + ", isValid: " + this.isValid + + ", statusCode: " + statusCode + + ", subStatusCode: " + subStatusCode + + ", isGone: " + this.isGoneException + + ", isNotFound: " + this.isNotFoundException + + ", isInvalidPartition: " + this.isInvalidPartitionException + + ", requestCharge: " + this.requestCharge + + ", itemLSN: " + this.itemLSN + + ", sessionToken: " + (this.sessionToken != null ? this.sessionToken.convertToString() : null) + + ", exception: " + BridgeInternal.getInnerErrorMessage(this.exception); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelper.java new file mode 100644 index 0000000000000..c497f87dc20ae --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelper.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.RequestTimeoutException; + +import java.time.Duration; +import java.time.Instant; + +public class TimeoutHelper { + private final Instant startTime; + private final Duration timeOut; + + public TimeoutHelper(Duration timeOut) { + this.startTime = Instant.now(); + this.timeOut = timeOut; + } + + public boolean isElapsed() { + Duration elapsed = Duration.ofMillis(Instant.now().toEpochMilli() - startTime.toEpochMilli()); + return elapsed.compareTo(this.timeOut) >= 0; + } + + public Duration getRemainingTime() { + Duration elapsed = Duration.ofMillis(Instant.now().toEpochMilli() - startTime.toEpochMilli()); + return this.timeOut.minus(elapsed); + } + + public void throwTimeoutIfElapsed() throws RequestTimeoutException { + if (this.isElapsed()) { + throw new RequestTimeoutException(); + } + } + + public void throwGoneIfElapsed() throws GoneException { + if (this.isElapsed()) { + throw new GoneException(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportClient.java new file mode 100644 index 0000000000000..2af1c428b5528 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportClient.java @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import reactor.core.publisher.Mono; + +import java.net.URI; + +public abstract class TransportClient implements AutoCloseable { + + // Uses requests's ResourceOperation to determine the operation + public Mono invokeResourceOperationAsync(URI physicalAddress, RxDocumentServiceRequest request) { + return this.invokeStoreAsync(physicalAddress, request); + } + + protected abstract Mono invokeStoreAsync( + URI physicalAddress, + RxDocumentServiceRequest request); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportException.java new file mode 100644 index 0000000000000..306a820700c42 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/TransportException.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +// TODO: DANOBLE: Use a TransportException derivative wherever CorruptFrameException is thrown in RntbdTransportClient +// * Continue to throw IllegalArgumentException, IllegalStateException, and NullPointerException. +// * Continue to complete all pending requests with a GoneException. +// Customers should then expect to see these causes for GoneException errors originating in RntbdTransportClient: +// - TransportException +// - ReadTimeoutException +// - WriteTimeoutException +// These causes for GoneException errors will be logged as issues because they indicate a problem in the +// RntbdTransportClient code: +// - IllegalArgumentException +// - IllegalStateException +// - NullPointerException +// Any other exceptions caught by the RntbdTransportClient code will also be logged as issues because they +// indicate something unexpected happened. +// NOTES: +// We throw a derivative in one place: RntbdContextException in RntbdContext.decode. This is a special case +// that is handled by RntbdRequestManager.userEventTriggered. + +public class TransportException extends RuntimeException { + public TransportException(String message, Throwable cause) { + super(message, cause, /* enableSuppression */ true, /* writableStackTrace */ false); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WFConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WFConstants.java new file mode 100644 index 0000000000000..d99a09217abdd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WFConstants.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +public class WFConstants { + public static class BackendHeaders { + public static final String RESOURCE_ID = "x-docdb-resource-id"; + public static final String OWNER_ID = "x-docdb-owner-id"; + public static final String ENTITY_ID = "x-docdb-entity-id"; + public static final String DATABASE_ENTITY_MAX_COUNT = "x-ms-database-entity-max-count"; + public static final String DATABASE_ENTITY_CURRENT_COUNT = "x-ms-database-entity-current-count"; + public static final String COLLECTION_ENTITY_MAX_COUNT = "x-ms-collection-entity-max-count"; + public static final String COLLECTION_ENTITY_CURRENT_COUNT = "x-ms-collection-entity-current-count"; + public static final String USER_ENTITY_MAX_COUNT = "x-ms-user-entity-max-count"; + public static final String USER_ENTITY_CURRENT_COUNT = "x-ms-user-entity-current-count"; + public static final String PERMISSION_ENTITY_MAX_COUNT = "x-ms-permission-entity-max-count"; + public static final String PERMISSION_ENTITY_CURRENT_COUNT = "x-ms-permission-entity-current-count"; + public static final String ROOT_ENTITY_MAX_COUNT = "x-ms-root-entity-max-count"; + public static final String ROOT_ENTITY_CURRENT_COUNT = "x-ms-root-entity-current-count"; + public static final String RESOURCE_SCHEMA_NAME = "x-ms-resource-schema-name"; + public static final String LSN = "lsn"; + public static final String QUORUM_ACKED_LSN = "x-ms-quorum-acked-lsn"; + public static final String QUORUM_ACKED_LLSN = "x-ms-cosmos-quorum-acked-llsn"; + public static final String CURRENT_WRITE_QUORUM = "x-ms-current-write-quorum"; + public static final String CURRENT_REPLICA_SET_SIZE = "x-ms-current-replica-set-size"; + public static final String COLLECTION_PARTITION_INDEX = "collection-partition-index"; + public static final String COLLECTION_SERVICE_INDEX = "collection-service-index"; + public static final String STATUS = "Status"; + public static final String ACTIVITY_ID = "ActivityId"; + public static final String IS_FANOUT_REQUEST = "x-ms-is-fanout-request"; + public static final String PRIMARY_MASTER_KEY = "x-ms-primary-master-key"; + public static final String SECONDARY_MASTER_KEY = "x-ms-secondary-master-key"; + public static final String PRIMARY_READONLY_KEY = "x-ms-primary-readonly-key"; + public static final String SECONDARY_READONLY_KEY = "x-ms-secondary-readonly-key"; + public static final String BIND_REPLICA_DIRECTIVE = "x-ms-bind-replica"; + public static final String DATABASE_ACCOUNT_ID = "x-ms-database-account-id"; + public static final String REQUEST_VALIDATION_FAILURE = "x-ms-request-validation-failure"; + public static final String SUB_STATUS = "x-ms-substatus"; + public static final String PARTITION_KEY_RANGE_ID = "x-ms-documentdb-partitionkeyrangeid"; + public static final String BIND_MIN_EFFECTIVE_PARTITION_KEY = "x-ms-documentdb-bindmineffectivepartitionkey"; + public static final String BIND_MAX_EFFECTIVE_PARTITION_KEY = "x-ms-documentdb-bindmaxeffectivepartitionkey"; + public static final String BIND_PARTITION_KEY_RANGE_ID = "x-ms-documentdb-bindpartitionkeyrangeid"; + public static final String BIND_PARTITION_KEY_RANGE_RID_PREFIX = "x-ms-documentdb-bindpartitionkeyrangeridprefix"; + public static final String MINIMUM_ALLOWED_CLIENT_VERSION = "x-ms-documentdb-minimumallowedclientversion"; + public static final String PARTITION_COUNT = "x-ms-documentdb-partitioncount"; + public static final String COLLECTION_RID = "x-ms-documentdb-collection-rid"; + public static final String XP_ROLE = "x-ms-xp-role"; + public static final String HAS_TENTATIVE_WRITES = "x-ms-cosmosdb-has-tentative-writes"; + public static final String IS_RU_PER_MINUTE_USED = "x-ms-documentdb-is-ru-per-minute-used"; + public static final String QUERY_METRICS = "x-ms-documentdb-query-metrics"; + public static final String GLOBAL_COMMITTED_LSN = "x-ms-global-Committed-lsn"; + public static final String NUMBER_OF_READ_REGIONS = "x-ms-number-of-read-regions"; + public static final String OFFER_REPLACE_PENDING = "x-ms-offer-replace-pending"; + public static final String ITEM_LSN = "x-ms-item-lsn"; + public static final String REMOTE_STORAGE_TYPE = "x-ms-remote-storage-type"; + public static final String RESTORE_STATE = "x-ms-restore-state"; + public static final String COLLECTION_SECURITY_IDENTIFIER = "x-ms-collection-security-identifier"; + public static final String RESTORE_PARAMS = "x-ms-restore-params"; + public static final String SHARE_THROUGHPUT = "x-ms-share-throughput"; + public static final String PARTITION_RESOURCE_FILTER = "x-ms-partition-resource-filter"; + public static final String FEDERATION_ID_FOR_AUTH = "x-ms-federation-for-auth"; + public static final String FORCE_QUERY_SCAN = "x-ms-documentdb-force-query-scan"; + public static final String ENABLE_DYNAMIC_RID_RANGE_ALLOCATION = "x-ms-enable-dynamic-rid-range-allocation"; + public static final String EXCLUDE_SYSTEM_PROPERTIES = "x-ms-exclude-system-properties"; + public static final String LOCAL_LSN = "x-ms-cosmos-llsn"; + public static final String QUORUM_ACKED_LOCAL_LSN = "x-ms-cosmos-quorum-acked-llsn"; + public static final String ITEM_LOCAL_LSN = "x-ms-cosmos-item-llsn"; + public static final String BINARY_ID = "x-ms-binary-id"; + public static final String TIME_TO_LIVE_IN_SECONDS = "x-ms-time-to-live-in-seconds"; + public static final String EFFECTIVE_PARTITION_KEY = "x-ms-effective-partition-key"; + public static final String BINARY_PASSTHROUGH_REQUEST = "x-ms-binary-passthrough-request"; + public static final String FANOUT_OPERATION_STATE = "x-ms-fanout-operation-state"; + public static final String CONTENT_SERIALIZATION_FORMAT = "x-ms-documentdb-content-serialization-format"; + public static final String ALLOW_TENTATIVE_WRITES = "x-ms-cosmos-allow-tentative-writes"; + public static final String IS_USER_REQUEST = "x-ms-cosmos-internal-is-user-request"; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtility.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtility.java new file mode 100644 index 0000000000000..5363972807f46 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtility.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.Utils; +import io.netty.channel.ChannelException; + +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import java.io.IOException; +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.UnknownHostException; + +public class WebExceptionUtility { + public static boolean isWebExceptionRetriable(Exception ex) { + Exception iterator = ex; + + while (iterator != null) { + if (WebExceptionUtility.isWebExceptionRetriableInternal(iterator)) { + return true; + } + + Throwable t = iterator.getCause(); + iterator = Utils.as(t, Exception.class); + } + + return false; + } + + private static boolean isWebExceptionRetriableInternal(Exception ex) { + + IOException webEx = Utils.as(ex, IOException.class); + if (webEx == null) { + return false; + } + + // any network failure for which we are certain the request hasn't reached the service endpoint. + if (webEx instanceof ConnectException || + webEx instanceof UnknownHostException || + webEx instanceof SSLHandshakeException || + webEx instanceof NoRouteToHostException || + webEx instanceof SSLPeerUnverifiedException) { + return true; + } + + return false; + } + + public static boolean isNetworkFailure(Exception ex) { + Exception iterator = ex; + + while (iterator != null) { + if (WebExceptionUtility.isNetworkFailureInternal(iterator)) { + return true; + } + + Throwable t = iterator.getCause(); + iterator = Utils.as(t, Exception.class); + } + + return false; + } + + private static boolean isNetworkFailureInternal(Exception ex) { + if (ex instanceof IOException) { + return true; + } + + if (ex instanceof ChannelException) { + return true; + } + + return false; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelHandler.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelHandler.java new file mode 100644 index 0000000000000..a91f7859fefdc --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelHandler.java @@ -0,0 +1,139 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoop; +import io.netty.channel.pool.ChannelPool; +import io.netty.channel.pool.ChannelPoolHandler; +import io.netty.handler.logging.LoggingHandler; +import io.netty.handler.ssl.SslHandler; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLEngine; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class RntbdClientChannelHandler extends ChannelInitializer implements ChannelPoolHandler { + + private static Logger logger = LoggerFactory.getLogger(RntbdClientChannelHandler.class); + private final RntbdEndpoint.Config config; + + RntbdClientChannelHandler(final RntbdEndpoint.Config config) { + checkNotNull(config, "config"); + this.config = config; + } + + /** + * Called by {@link ChannelPool#acquire} after a {@link Channel} is acquired + *

    + * This method is called within the {@link EventLoop} of the {@link Channel}. + * + * @param channel a channel that was just acquired + */ + @Override + public void channelAcquired(final Channel channel) { + logger.trace("{} CHANNEL ACQUIRED", channel); + } + + /** + * Called by {@link ChannelPool#release} after a {@link Channel} is created + *

    + * This method is called within the {@link EventLoop} of the {@link Channel}. + * + * @param channel a channel that was just created + */ + @Override + public void channelCreated(final Channel channel) { + logger.trace("{} CHANNEL CREATED", channel); + this.initChannel(channel); + } + + /** + * Called by {@link ChannelPool#release} after a {@link Channel} is released + *

    + * This method is called within the {@link EventLoop} of the {@link Channel}. + * + * @param channel a channel that was just released + */ + @Override + public void channelReleased(final Channel channel) { + logger.trace("{} CHANNEL RELEASED", channel); + } + + /** + * Called by @{ChannelPipeline} initializer after the current channel is registered to an event loop. + *

    + * This method constructs this pipeline: + *

    {@code
    +     * ChannelPipeline {
    +     *     (ReadTimeoutHandler#0 = io.netty.handler.timeout.ReadTimeoutHandler),
    +     *     (SslHandler#0 = io.netty.handler.ssl.SslHandler),
    +     *     (RntbdContextNegotiator#0 = com.microsoft.azure.cosmosdb.internal.directconnectivity.rntbd.RntbdContextNegotiator),
    +     *     (RntbdResponseDecoder#0 = com.microsoft.azure.cosmosdb.internal.directconnectivity.rntbd.RntbdResponseDecoder),
    +     *     (RntbdRequestEncoder#0 = com.microsoft.azure.cosmosdb.internal.directconnectivity.rntbd.RntbdRequestEncoder),
    +     *     (WriteTimeoutHandler#0 = io.netty.handler.timeout.WriteTimeoutHandler),
    +     *     (RntbdRequestManager#0 = com.microsoft.azure.cosmosdb.internal.directconnectivity.rntbd.RntbdRequestManager),
    +     * }
    +     * }
    + * + * @param channel a channel that was just registered with an event loop + */ + @Override + protected void initChannel(final Channel channel) { + + checkNotNull(channel); + + final RntbdRequestManager requestManager = new RntbdRequestManager(this.config.getMaxRequestsPerChannel()); + final long readerIdleTime = this.config.getReceiveHangDetectionTime(); + final long writerIdleTime = this.config.getSendHangDetectionTime(); + final ChannelPipeline pipeline = channel.pipeline(); + + pipeline.addFirst( + new RntbdContextNegotiator(requestManager, this.config.getUserAgent()), + new RntbdResponseDecoder(), + new RntbdRequestEncoder(), + new WriteTimeoutHandler(writerIdleTime, TimeUnit.NANOSECONDS), + requestManager + ); + + if (this.config.getWireLogLevel() != null) { + pipeline.addFirst(new LoggingHandler(this.config.getWireLogLevel())); + } + + final SSLEngine sslEngine = this.config.getSslContext().newEngine(channel.alloc()); + + pipeline.addFirst( + new ReadTimeoutHandler(readerIdleTime, TimeUnit.NANOSECONDS), + new SslHandler(sslEngine) + ); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelPool.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelPool.java new file mode 100644 index 0000000000000..132b3fc16b481 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdClientChannelPool.java @@ -0,0 +1,266 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.pool.ChannelHealthChecker; +import io.netty.channel.pool.FixedChannelPool; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.Promise; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdReporter.reportIssue; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdReporter.reportIssueUnless; +import static com.google.common.base.Preconditions.checkState; + +@JsonSerialize(using = RntbdClientChannelPool.JsonSerializer.class) +public final class RntbdClientChannelPool extends FixedChannelPool { + + // region Fields + + private static final Logger logger = LoggerFactory.getLogger(RntbdClientChannelPool.class); + private static final AtomicReference pendingAcquireCount = new AtomicReference<>(); + + private final AtomicInteger availableChannelCount; + private final AtomicBoolean closed; + private final int maxChannels; + private final int maxRequestsPerChannel; + + // endregion + + // region Methods + + /** + * Initializes a newly created {@link RntbdClientChannelPool} object + * + * @param bootstrap the {@link Bootstrap} that is used for connections + * @param config the {@link RntbdEndpoint.Config} that is used for the channel pool instance created + */ + RntbdClientChannelPool(final Bootstrap bootstrap, final RntbdEndpoint.Config config) { + + super(bootstrap, new RntbdClientChannelHandler(config), ChannelHealthChecker.ACTIVE, null, + -1L, config.getMaxChannelsPerEndpoint(), Integer.MAX_VALUE, true + ); + + this.maxRequestsPerChannel = config.getMaxRequestsPerChannel(); + this.maxChannels = config.getMaxChannelsPerEndpoint(); + this.availableChannelCount = new AtomicInteger(); + this.closed = new AtomicBoolean(); + } + + @Override + public Future acquire(Promise promise) { + this.throwIfClosed(); + return super.acquire(promise); + } + + @Override + public Future release(Channel channel, Promise promise) { + this.throwIfClosed(); + return super.release(channel, promise); + } + + @Override + public void close() { + if (this.closed.compareAndSet(false, true)) { + this.availableChannelCount.set(0); + super.close(); + } + } + + public int availableChannelCount() { + return this.availableChannelCount.get(); + } + + public int maxChannels() { + return this.maxChannels; + } + + public int maxRequestsPerChannel() { + return this.maxRequestsPerChannel; + } + + public int pendingAcquisitionCount() { + + Field field = pendingAcquireCount.get(); + + if (field == null) { + synchronized (pendingAcquireCount) { + field = pendingAcquireCount.get(); + if (field == null) { + field = FieldUtils.getDeclaredField(FixedChannelPool.class, "pendingAcquireCount", true); + pendingAcquireCount.set(field); + } + } + } + + try { + return (int)FieldUtils.readField(field, this); + } catch (IllegalAccessException error) { + reportIssue(logger, this, "could not access field due to ", error); + } + + return -1; + } + + /** + * Poll a {@link Channel} out of internal storage to reuse it + *

    + * Maintainers: Implementations of this method must be thread-safe and this type's base class, {@link FixedChannelPool}, + * ensures thread safety. It does this by calling this method serially on a single-threaded EventExecutor. As a + * result this method need not (and should not) be synchronized. + * + * @return a value of {@code null}, if no {@link Channel} is ready to be reused + * + * @see #acquire(Promise) + */ + @Override + protected Channel pollChannel() { + + final Channel first = super.pollChannel(); + + if (first == null) { + return null; + } + + if (this.closed.get()) { + return first; // because we're being called following a call to close (from super.close) + } + + if (this.isInactiveOrServiceableChannel(first)) { + return this.decrementAvailableChannelCountAndAccept(first); + } + + super.offerChannel(first); // because we need a non-null sentinel to stop the search for a channel + + for (Channel next = super.pollChannel(); next != first; super.offerChannel(next), next = super.pollChannel()) { + if (this.isInactiveOrServiceableChannel(next)) { + return this.decrementAvailableChannelCountAndAccept(next); + } + } + + super.offerChannel(first); // because we choose not to check any channel more than once in a single call + return null; + } + + /** + * Offer a {@link Channel} back to the internal storage + *

    + * Maintainers: Implementations of this method must be thread-safe. + * + * @param channel the {@link Channel} to return to internal storage + * @return {@code true}, if the {@link Channel} could be added to internal storage; otherwise {@code false} + */ + @Override + protected boolean offerChannel(final Channel channel) { + if (super.offerChannel(channel)) { + this.availableChannelCount.incrementAndGet(); + return true; + } + return false; + } + + public SocketAddress remoteAddress() { + return this.bootstrap().config().remoteAddress(); + } + + @Override + public String toString() { + return "RntbdClientChannelPool(" + RntbdObjectMapper.toJson(this) + ")"; + } + + // endregion + + // region Privates + + private Channel decrementAvailableChannelCountAndAccept(final Channel first) { + this.availableChannelCount.decrementAndGet(); + return first; + } + + private boolean isInactiveOrServiceableChannel(final Channel channel) { + + if (!channel.isActive()) { + return true; + } + + final RntbdRequestManager requestManager = channel.pipeline().get(RntbdRequestManager.class); + + if (requestManager == null) { + reportIssueUnless(!channel.isActive(), logger, this, "{} active with no request manager", channel); + return true; // inactive + } + + return requestManager.isServiceable(this.maxRequestsPerChannel); + } + + private void throwIfClosed() { + checkState(!this.closed.get(), "%s is closed", this); + } + + // endregion + + // region Types + + static final class JsonSerializer extends StdSerializer { + + public JsonSerializer() { + this(null); + } + + public JsonSerializer(Class type) { + super(type); + } + + @Override + public void serialize(RntbdClientChannelPool value, JsonGenerator generator, SerializerProvider provider) throws IOException { + generator.writeStartObject(); + generator.writeStringField("remoteAddress", value.remoteAddress().toString()); + generator.writeNumberField("maxChannels", value.maxChannels()); + generator.writeNumberField("maxRequestsPerChannel", value.maxRequestsPerChannel()); + generator.writeObjectFieldStart("state"); + generator.writeBooleanField("isClosed", value.closed.get()); + generator.writeNumberField("acquiredChannelCount", value.acquiredChannelCount()); + generator.writeNumberField("availableChannelCount", value.availableChannelCount()); + generator.writeNumberField("pendingAcquisitionCount", value.pendingAcquisitionCount()); + generator.writeEndObject(); + generator.writeEndObject(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdConstants.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdConstants.java new file mode 100644 index 0000000000000..a6bc01c32f95a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdConstants.java @@ -0,0 +1,751 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; + +import java.util.EnumSet; +import java.util.stream.Collector; + +final class RntbdConstants { + + static final int CurrentProtocolVersion = 0x00000001; + + private RntbdConstants() { + } + + public enum RntbdConsistencyLevel { + + Strong((byte)0x00), + BoundedStaleness((byte)0x01), + Session((byte)0x02), + Eventual((byte)0x03), + ConsistentPrefix((byte)0x04), + + Invalid((byte)0xFF); + + private final byte id; + + RntbdConsistencyLevel(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + public enum RntbdContentSerializationFormat { + + JsonText((byte)0x00), + CosmosBinary((byte)0x01), + + Invalid((byte)0xFF); + + private final byte id; + + RntbdContentSerializationFormat(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + @SuppressWarnings("UnstableApiUsage") + enum RntbdContextHeader implements RntbdHeader { + + ProtocolVersion((short)0x0000, RntbdTokenType.ULong, false), + ClientVersion((short)0x0001, RntbdTokenType.SmallString, false), + ServerAgent((short)0x0002, RntbdTokenType.SmallString, true), + ServerVersion((short)0x0003, RntbdTokenType.SmallString, true), + IdleTimeoutInSeconds((short)0x0004, RntbdTokenType.ULong, false), + UnauthenticatedTimeoutInSeconds((short)0x0005, RntbdTokenType.ULong, false); + + public static final ImmutableMap map; + public static final ImmutableSet set = Sets.immutableEnumSet(EnumSet.allOf(RntbdContextHeader.class)); + + static { + final Collector> collector = ImmutableMap.toImmutableMap(RntbdContextHeader::id, h -> h); + map = set.stream().collect(collector); + } + + private final short id; + private final boolean isRequired; + private final RntbdTokenType type; + + RntbdContextHeader(final short id, final RntbdTokenType type, final boolean isRequired) { + this.id = id; + this.type = type; + this.isRequired = isRequired; + } + + public boolean isRequired() { + return this.isRequired; + } + + public short id() { + return this.id; + } + + public RntbdTokenType type() { + return this.type; + } + } + + enum RntbdContextRequestHeader implements RntbdHeader { + + ProtocolVersion((short)0x0000, RntbdTokenType.ULong, true), + ClientVersion((short)0x0001, RntbdTokenType.SmallString, true), + UserAgent((short)0x0002, RntbdTokenType.SmallString, true); + + public static final ImmutableMap map; + public static final ImmutableSet set = Sets.immutableEnumSet(EnumSet.allOf(RntbdContextRequestHeader.class)); + + static { + final Collector> collector = ImmutableMap.toImmutableMap(h -> h.id(), h -> h); + map = set.stream().collect(collector); + } + + private final short id; + private final boolean isRequired; + private final RntbdTokenType type; + + RntbdContextRequestHeader(final short id, final RntbdTokenType type, final boolean isRequired) { + this.id = id; + this.type = type; + this.isRequired = isRequired; + } + + public boolean isRequired() { + return this.isRequired; + } + + public short id() { + return this.id; + } + + public RntbdTokenType type() { + return this.type; + } + } + + public enum RntbdEnumerationDirection { + + Invalid((byte)0x00), + + Forward((byte)0x01), + Reverse((byte)0x02); + + private final byte id; + + RntbdEnumerationDirection(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + public enum RntbdFanoutOperationState { + + Started((byte)0x01), + Completed((byte)0x02); + + private final byte id; + + RntbdFanoutOperationState(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + enum RntbdIndexingDirective { + + Default((byte)0x00), + Include((byte)0x01), + Exclude((byte)0x02), + Invalid((byte)0xFF); + + private final byte id; + + RntbdIndexingDirective(final byte id) { + this.id = id; + } + + public static RntbdIndexingDirective fromId(final byte id) { + switch (id) { + case (byte)0x00: + return Default; + case (byte)0x01: + return Include; + case (byte)0x02: + return Exclude; + case (byte)0xFF: + return Invalid; + } + throw new IllegalArgumentException("id"); + } + + public byte id() { + return this.id; + } + } + + public enum RntbdMigrateCollectionDirective { + + Thaw((byte)0x00), + Freeze((byte)0x01), + + Invalid((byte)0xFF); + + private final byte id; + + RntbdMigrateCollectionDirective(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + enum RntbdOperationType { + + Connection((short)0x0000), + Create((short)0x0001), + Update((short)0x0002), + Read((short)0x0003), + ReadFeed((short)0x0004), + Delete((short)0x0005), + Replace((short)0x0006), + // Obsolete and now undefined: JPathQuery((short)0x0007), + ExecuteJavaScript((short)0x0008), + SQLQuery((short)0x0009), + Pause((short)0x000A), + Resume((short)0x000B), + Stop((short)0x000C), + Recycle((short)0x000D), + Crash((short)0x000E), + Query((short)0x000F), + ForceConfigRefresh((short)0x0010), + Head((short)0x0011), + HeadFeed((short)0x0012), + Upsert((short)0x0013), + Recreate((short)0x0014), + Throttle((short)0x0015), + GetSplitPoint((short)0x0016), + PreCreateValidation((short)0x0017), + BatchApply((short)0x0018), + AbortSplit((short)0x0019), + CompleteSplit((short)0x001A), + OfferUpdateOperation((short)0x001B), + OfferPreGrowValidation((short)0x001C), + BatchReportThroughputUtilization((short)0x001D), + CompletePartitionMigration((short)0x001E), + AbortPartitionMigration((short)0x001F), + PreReplaceValidation((short)0x0020), + AddComputeGatewayRequestCharges((short)0x0021), + MigratePartition((short)0x0022); + + private final short id; + + RntbdOperationType(final short id) { + this.id = id; + } + + public static RntbdOperationType fromId(final short id) throws IllegalArgumentException { + + switch (id) { + case 0x0000: + return RntbdOperationType.Connection; + case 0x0001: + return RntbdOperationType.Create; + case 0x0002: + return RntbdOperationType.Update; + case 0x0003: + return RntbdOperationType.Read; + case 0x0004: + return RntbdOperationType.ReadFeed; + case 0x0005: + return RntbdOperationType.Delete; + case 0x0006: + return RntbdOperationType.Replace; + // Obsolete and now undefined: case 0x0007: return RntbdOperationType.JPathQuery; + case 0x0008: + return RntbdOperationType.ExecuteJavaScript; + case 0x0009: + return RntbdOperationType.SQLQuery; + case 0x000A: + return RntbdOperationType.Pause; + case 0x000B: + return RntbdOperationType.Resume; + case 0x000C: + return RntbdOperationType.Stop; + case 0x000D: + return RntbdOperationType.Recycle; + case 0x000E: + return RntbdOperationType.Crash; + case 0x000F: + return RntbdOperationType.Query; + case 0x0010: + return RntbdOperationType.ForceConfigRefresh; + case 0x0011: + return RntbdOperationType.Head; + case 0x0012: + return RntbdOperationType.HeadFeed; + case 0x0013: + return RntbdOperationType.Upsert; + case 0x0014: + return RntbdOperationType.Recreate; + case 0x0015: + return RntbdOperationType.Throttle; + case 0x0016: + return RntbdOperationType.GetSplitPoint; + case 0x0017: + return RntbdOperationType.PreCreateValidation; + case 0x0018: + return RntbdOperationType.BatchApply; + case 0x0019: + return RntbdOperationType.AbortSplit; + case 0x001A: + return RntbdOperationType.CompleteSplit; + case 0x001B: + return RntbdOperationType.OfferUpdateOperation; + case 0x001C: + return RntbdOperationType.OfferPreGrowValidation; + case 0x001D: + return RntbdOperationType.BatchReportThroughputUtilization; + case 0x001E: + return RntbdOperationType.CompletePartitionMigration; + case 0x001F: + return RntbdOperationType.AbortPartitionMigration; + case 0x0020: + return RntbdOperationType.PreReplaceValidation; + case 0x0021: + return RntbdOperationType.AddComputeGatewayRequestCharges; + case 0x0022: + return RntbdOperationType.MigratePartition; + } + throw new IllegalArgumentException("id"); + } + + public short id() { + return this.id; + } + } + + public enum RntbdReadFeedKeyType { + + Invalid((byte)0x00), + ResourceId((byte)0x01), + EffectivePartitionKey((byte)0x02); + + private final byte id; + + RntbdReadFeedKeyType(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + public enum RntbdRemoteStorageType { + + Invalid((byte)0x00), + NotSpecified((byte)0x01), + Standard((byte)0x02), + Premium((byte)0x03); + + private final byte id; + + RntbdRemoteStorageType(final byte id) { + this.id = id; + } + + public byte id() { + return this.id; + } + } + + public enum RntbdRequestHeader implements RntbdHeader { + + ResourceId((short)0x0000, RntbdTokenType.Bytes, false), + AuthorizationToken((short)0x0001, RntbdTokenType.String, false), + PayloadPresent((short)0x0002, RntbdTokenType.Byte, true), + Date((short)0x0003, RntbdTokenType.SmallString, false), + PageSize((short)0x0004, RntbdTokenType.ULong, false), + SessionToken((short)0x0005, RntbdTokenType.String, false), + ContinuationToken((short)0x0006, RntbdTokenType.String, false), + IndexingDirective((short)0x0007, RntbdTokenType.Byte, false), + Match((short)0x0008, RntbdTokenType.String, false), + PreTriggerInclude((short)0x0009, RntbdTokenType.String, false), + PostTriggerInclude((short)0x000A, RntbdTokenType.String, false), + IsFanout((short)0x000B, RntbdTokenType.Byte, false), + CollectionPartitionIndex((short)0x000C, RntbdTokenType.ULong, false), + CollectionServiceIndex((short)0x000D, RntbdTokenType.ULong, false), + PreTriggerExclude((short)0x000E, RntbdTokenType.String, false), + PostTriggerExclude((short)0x000F, RntbdTokenType.String, false), + ConsistencyLevel((short)0x0010, RntbdTokenType.Byte, false), + EntityId((short)0x0011, RntbdTokenType.String, false), + ResourceSchemaName((short)0x0012, RntbdTokenType.SmallString, false), + ReplicaPath((short)0x0013, RntbdTokenType.String, true), + ResourceTokenExpiry((short)0x0014, RntbdTokenType.ULong, false), + DatabaseName((short)0x0015, RntbdTokenType.String, false), + CollectionName((short)0x0016, RntbdTokenType.String, false), + DocumentName((short)0x0017, RntbdTokenType.String, false), + AttachmentName((short)0x0018, RntbdTokenType.String, false), + UserName((short)0x0019, RntbdTokenType.String, false), + PermissionName((short)0x001A, RntbdTokenType.String, false), + StoredProcedureName((short)0x001B, RntbdTokenType.String, false), + UserDefinedFunctionName((short)0x001C, RntbdTokenType.String, false), + TriggerName((short)0x001D, RntbdTokenType.String, false), + EnableScanInQuery((short)0x001E, RntbdTokenType.Byte, false), + EmitVerboseTracesInQuery((short)0x001F, RntbdTokenType.Byte, false), + ConflictName((short)0x0020, RntbdTokenType.String, false), + BindReplicaDirective((short)0x0021, RntbdTokenType.String, false), + PrimaryMasterKey((short)0x0022, RntbdTokenType.String, false), + SecondaryMasterKey((short)0x0023, RntbdTokenType.String, false), + PrimaryReadonlyKey((short)0x0024, RntbdTokenType.String, false), + SecondaryReadonlyKey((short)0x0025, RntbdTokenType.String, false), + ProfileRequest((short)0x0026, RntbdTokenType.Byte, false), + EnableLowPrecisionOrderBy((short)0x0027, RntbdTokenType.Byte, false), + ClientVersion((short)0x0028, RntbdTokenType.SmallString, false), + CanCharge((short)0x0029, RntbdTokenType.Byte, false), + CanThrottle((short)0x002A, RntbdTokenType.Byte, false), + PartitionKey((short)0x002B, RntbdTokenType.String, false), + PartitionKeyRangeId((short)0x002C, RntbdTokenType.String, false), + NotUsed2D((short)0x002D, RntbdTokenType.Invalid, false), + NotUsed2E((short)0x002E, RntbdTokenType.Invalid, false), + NotUsed2F((short)0x002F, RntbdTokenType.Invalid, false), + // not used 0x0030, + MigrateCollectionDirective((short)0x0031, RntbdTokenType.Byte, false), + NotUsed32((short)0x0032, RntbdTokenType.Invalid, false), + SupportSpatialLegacyCoordinates((short)0x0033, RntbdTokenType.Byte, false), + PartitionCount((short)0x0034, RntbdTokenType.ULong, false), + CollectionRid((short)0x0035, RntbdTokenType.String, false), + PartitionKeyRangeName((short)0x0036, RntbdTokenType.String, false), + // not used((short)0x0037), RoundTripTimeInMsec + // not used((short)0x0038), RequestMessageSentTime + // not used((short)0x0039), RequestMessageTimeOffset + SchemaName((short)0x003A, RntbdTokenType.String, false), + FilterBySchemaRid((short)0x003B, RntbdTokenType.String, false), + UsePolygonsSmallerThanAHemisphere((short)0x003C, RntbdTokenType.Byte, false), + GatewaySignature((short)0x003D, RntbdTokenType.String, false), + EnableLogging((short)0x003E, RntbdTokenType.Byte, false), + A_IM((short)0x003F, RntbdTokenType.String, false), + PopulateQuotaInfo((short)0x0040, RntbdTokenType.Byte, false), + DisableRUPerMinuteUsage((short)0x0041, RntbdTokenType.Byte, false), + PopulateQueryMetrics((short)0x0042, RntbdTokenType.Byte, false), + ResponseContinuationTokenLimitInKb((short)0x0043, RntbdTokenType.ULong, false), + PopulatePartitionStatistics((short)0x0044, RntbdTokenType.Byte, false), + RemoteStorageType((short)0x0045, RntbdTokenType.Byte, false), + CollectionRemoteStorageSecurityIdentifier((short)0x0046, RntbdTokenType.String, false), + IfModifiedSince((short)0x0047, RntbdTokenType.String, false), + PopulateCollectionThroughputInfo((short)0x0048, RntbdTokenType.Byte, false), + RemainingTimeInMsOnClientRequest((short)0x0049, RntbdTokenType.ULong, false), + ClientRetryAttemptCount((short)0x004A, RntbdTokenType.ULong, false), + TargetLsn((short)0x004B, RntbdTokenType.LongLong, false), + TargetGlobalCommittedLsn((short)0x004C, RntbdTokenType.LongLong, false), + TransportRequestID((short)0x004D, RntbdTokenType.ULong, false), + RestoreMetadaFilter((short)0x004E, RntbdTokenType.String, false), + RestoreParams((short)0x004F, RntbdTokenType.String, false), + ShareThroughput((short)0x0050, RntbdTokenType.Byte, false), + PartitionResourceFilter((short)0x0051, RntbdTokenType.String, false), + IsReadOnlyScript((short)0x0052, RntbdTokenType.Byte, false), + IsAutoScaleRequest((short)0x0053, RntbdTokenType.Byte, false), + ForceQueryScan((short)0x0054, RntbdTokenType.Byte, false), + // not used((short)0x0055), LeaseSeqNumber + CanOfferReplaceComplete((short)0x0056, RntbdTokenType.Byte, false), + ExcludeSystemProperties((short)0x0057, RntbdTokenType.Byte, false), + BinaryId((short)0x0058, RntbdTokenType.Bytes, false), + TimeToLiveInSeconds((short)0x0059, RntbdTokenType.Long, false), + EffectivePartitionKey((short)0x005A, RntbdTokenType.Bytes, false), + BinaryPassthroughRequest((short)0x005B, RntbdTokenType.Byte, false), + UserDefinedTypeName((short)0x005C, RntbdTokenType.String, false), + EnableDynamicRidRangeAllocation((short)0x005D, RntbdTokenType.Byte, false), + EnumerationDirection((short)0x005E, RntbdTokenType.Byte, false), + StartId((short)0x005F, RntbdTokenType.Bytes, false), + EndId((short)0x0060, RntbdTokenType.Bytes, false), + FanoutOperationState((short)0x0061, RntbdTokenType.Byte, false), + StartEpk((short)0x0062, RntbdTokenType.Bytes, false), + EndEpk((short)0x0063, RntbdTokenType.Bytes, false), + ReadFeedKeyType((short)0x0064, RntbdTokenType.Byte, false), + ContentSerializationFormat((short)0x0065, RntbdTokenType.Byte, false), + AllowTentativeWrites((short)0x0066, RntbdTokenType.Byte, false), + IsUserRequest((short)0x0067, RntbdTokenType.Byte, false), + SharedOfferThroughput((short)0x0068, RntbdTokenType.ULong, false); + + public static final ImmutableMap map; + public static final ImmutableSet set = Sets.immutableEnumSet(EnumSet.allOf(RntbdRequestHeader.class)); + + static { + final Collector> collector = ImmutableMap.toImmutableMap(RntbdRequestHeader::id, h -> h); + map = set.stream().collect(collector); + } + + private final short id; + private final boolean isRequired; + private final RntbdTokenType type; + + RntbdRequestHeader(final short id, final RntbdTokenType type, final boolean isRequired) { + this.id = id; + this.type = type; + this.isRequired = isRequired; + } + + public boolean isRequired() { + return this.isRequired; + } + + public short id() { + return this.id; + } + + public RntbdTokenType type() { + return this.type; + } + } + + enum RntbdResourceType { + + Connection((short)0x0000), + Database((short)0x0001), + Collection((short)0x0002), + Document((short)0x0003), + Attachment((short)0x0004), + User((short)0x0005), + Permission((short)0x0006), + StoredProcedure((short)0x0007), + Conflict((short)0x0008), + Trigger((short)0x0009), + UserDefinedFunction((short)0x000A), + Module((short)0x000B), + Replica((short)0x000C), + ModuleCommand((short)0x000D), + Record((short)0x000E), + Offer((short)0x000F), + PartitionSetInformation((short)0x0010), + XPReplicatorAddress((short)0x0011), + MasterPartition((short)0x0012), + ServerPartition((short)0x0013), + DatabaseAccount((short)0x0014), + Topology((short)0x0015), + PartitionKeyRange((short)0x0016), + // Obsolete and now undefined: Timestamp((short)0x0017), + Schema((short)0x0018), + BatchApply((short)0x0019), + RestoreMetadata((short)0x001A), + ComputeGatewayCharges((short)0x001B), + RidRange((short)0x001C), + UserDefinedType((short)0x001D); + + private final short id; + + RntbdResourceType(final short id) { + this.id = id; + } + + public static RntbdResourceType fromId(final short id) throws IllegalArgumentException { + switch (id) { + case 0x0000: + return RntbdResourceType.Connection; + case 0x0001: + return RntbdResourceType.Database; + case 0x0002: + return RntbdResourceType.Collection; + case 0x0003: + return RntbdResourceType.Document; + case 0x0004: + return RntbdResourceType.Attachment; + case 0x0005: + return RntbdResourceType.User; + case 0x0006: + return RntbdResourceType.Permission; + case 0x0007: + return RntbdResourceType.StoredProcedure; + case 0x0008: + return RntbdResourceType.Conflict; + case 0x0009: + return RntbdResourceType.Trigger; + case 0x000A: + return RntbdResourceType.UserDefinedFunction; + case 0x000B: + return RntbdResourceType.Module; + case 0x000C: + return RntbdResourceType.Replica; + case 0x000D: + return RntbdResourceType.ModuleCommand; + case 0x000E: + return RntbdResourceType.Record; + case 0x000F: + return RntbdResourceType.Offer; + case 0x0010: + return RntbdResourceType.PartitionSetInformation; + case 0x0011: + return RntbdResourceType.XPReplicatorAddress; + case 0x0012: + return RntbdResourceType.MasterPartition; + case 0x0013: + return RntbdResourceType.ServerPartition; + case 0x0014: + return RntbdResourceType.DatabaseAccount; + case 0x0015: + return RntbdResourceType.Topology; + case 0x0016: + return RntbdResourceType.PartitionKeyRange; + // Obsolete and now undefined: case 0x0017: return RntbdResourceType.Timestamp; + case 0x0018: + return RntbdResourceType.Schema; + case 0x0019: + return RntbdResourceType.BatchApply; + case 0x001A: + return RntbdResourceType.RestoreMetadata; + case 0x001B: + return RntbdResourceType.ComputeGatewayCharges; + case 0x001C: + return RntbdResourceType.RidRange; + case 0x001D: + return RntbdResourceType.UserDefinedType; + } + throw new IllegalArgumentException(String.format("id: %d", id)); + } + + public short id() { + return this.id; + } + } + + public enum RntbdResponseHeader implements RntbdHeader { + + PayloadPresent((short)0x0000, RntbdTokenType.Byte, true), + // not used((short)0x0001), + LastStateChangeDateTime((short)0x0002, RntbdTokenType.SmallString, false), + ContinuationToken((short)0x0003, RntbdTokenType.String, false), + ETag((short)0x0004, RntbdTokenType.String, false), + // not used((short)0x005,) + // not used((short)0x006,) + ReadsPerformed((short)0x0007, RntbdTokenType.ULong, false), + WritesPerformed((short)0x0008, RntbdTokenType.ULong, false), + QueriesPerformed((short)0x0009, RntbdTokenType.ULong, false), + IndexTermsGenerated((short)0x000A, RntbdTokenType.ULong, false), + ScriptsExecuted((short)0x000B, RntbdTokenType.ULong, false), + RetryAfterMilliseconds((short)0x000C, RntbdTokenType.ULong, false), + IndexingDirective((short)0x000D, RntbdTokenType.Byte, false), + StorageMaxResoureQuota((short)0x000E, RntbdTokenType.String, false), + StorageResourceQuotaUsage((short)0x000F, RntbdTokenType.String, false), + SchemaVersion((short)0x0010, RntbdTokenType.SmallString, false), + CollectionPartitionIndex((short)0x0011, RntbdTokenType.ULong, false), + CollectionServiceIndex((short)0x0012, RntbdTokenType.ULong, false), + LSN((short)0x0013, RntbdTokenType.LongLong, false), + ItemCount((short)0x0014, RntbdTokenType.ULong, false), + RequestCharge((short)0x0015, RntbdTokenType.Double, false), + // not used((short)0x0016), + OwnerFullName((short)0x0017, RntbdTokenType.String, false), + OwnerId((short)0x0018, RntbdTokenType.String, false), + DatabaseAccountId((short)0x0019, RntbdTokenType.String, false), + QuorumAckedLSN((short)0x001A, RntbdTokenType.LongLong, false), + RequestValidationFailure((short)0x001B, RntbdTokenType.Byte, false), + SubStatus((short)0x001C, RntbdTokenType.ULong, false), + CollectionUpdateProgress((short)0x001D, RntbdTokenType.ULong, false), + CurrentWriteQuorum((short)0x001E, RntbdTokenType.ULong, false), + CurrentReplicaSetSize((short)0x001F, RntbdTokenType.ULong, false), + CollectionLazyIndexProgress((short)0x0020, RntbdTokenType.ULong, false), + PartitionKeyRangeId((short)0x0021, RntbdTokenType.String, false), + // not used((short)0x0022), RequestMessageReceivedTime + // not used((short)0x0023), ResponseMessageSentTime + // not used((short)0x0024), ResponseMessageTimeOffset + LogResults((short)0x0025, RntbdTokenType.String, false), + XPRole((short)0x0026, RntbdTokenType.ULong, false), + IsRUPerMinuteUsed((short)0x0027, RntbdTokenType.Byte, false), + QueryMetrics((short)0x0028, RntbdTokenType.String, false), + GlobalCommittedLSN((short)0x0029, RntbdTokenType.LongLong, false), + NumberOfReadRegions((short)0x0030, RntbdTokenType.ULong, false), + OfferReplacePending((short)0x0031, RntbdTokenType.Byte, false), + ItemLSN((short)0x0032, RntbdTokenType.LongLong, false), + RestoreState((short)0x0033, RntbdTokenType.String, false), + CollectionSecurityIdentifier((short)0x0034, RntbdTokenType.String, false), + TransportRequestID((short)0x0035, RntbdTokenType.ULong, false), + ShareThroughput((short)0x0036, RntbdTokenType.Byte, false), + // not used((short)0x0037), LeaseSeqNumber + DisableRntbdChannel((short)0x0038, RntbdTokenType.Byte, false), + ServerDateTimeUtc((short)0x0039, RntbdTokenType.SmallString, false), + LocalLSN((short)0x003A, RntbdTokenType.LongLong, false), + QuorumAckedLocalLSN((short)0x003B, RntbdTokenType.LongLong, false), + ItemLocalLSN((short)0x003C, RntbdTokenType.LongLong, false), + HasTentativeWrites((short)0x003D, RntbdTokenType.Byte, false), + SessionToken((short)0x003E, RntbdTokenType.String, false); + + public static final ImmutableMap map; + public static final ImmutableSet set = Sets.immutableEnumSet(EnumSet.allOf(RntbdResponseHeader.class)); + + static { + final Collector> collector = ImmutableMap.toImmutableMap(RntbdResponseHeader::id, header -> header); + map = set.stream().collect(collector); + } + + private final short id; + private final boolean isRequired; + private final RntbdTokenType type; + + RntbdResponseHeader(final short id, final RntbdTokenType type, final boolean isRequired) { + this.id = id; + this.type = type; + this.isRequired = isRequired; + } + + public boolean isRequired() { + return this.isRequired; + } + + public short id() { + return this.id; + } + + public RntbdTokenType type() { + return this.type; + } + } + + interface RntbdHeader { + + boolean isRequired(); + + short id(); + + String name(); + + RntbdTokenType type(); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContext.java new file mode 100644 index 0000000000000..10f2fd894fb5f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContext.java @@ -0,0 +1,207 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.directconnectivity.ServerProperties; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpResponseStatus; + +import java.util.Collections; +import java.util.HashMap; +import java.util.UUID; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.CurrentProtocolVersion; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdContextHeader; +import static com.google.common.base.Preconditions.checkState; + +public final class RntbdContext { + + private final RntbdResponseStatus frame; + private final Headers headers; + private ServerProperties serverProperties; + + private RntbdContext(final RntbdResponseStatus frame, final Headers headers) { + this.frame = frame; + this.headers = headers; + } + + @JsonProperty + public UUID getActivityId() { + return this.frame.getActivityId(); + } + + @JsonProperty + public String getClientVersion() { + return this.headers.clientVersion.getValue(String.class); + } + + @JsonProperty + public long getIdleTimeoutInSeconds() { + return this.headers.idleTimeoutInSeconds.getValue(Long.class); + } + + @JsonProperty + public int getProtocolVersion() { + return this.headers.protocolVersion.getValue(Long.class).intValue(); + } + + @JsonProperty + public ServerProperties getServerProperties() { + return this.serverProperties == null ? (this.serverProperties = new ServerProperties( + this.headers.serverAgent.getValue(String.class), + this.headers.serverVersion.getValue(String.class)) + ) : this.serverProperties; + } + + @JsonIgnore + public String getServerVersion() { + return this.headers.serverVersion.getValue(String.class); + } + + @JsonProperty + public int getStatusCode() { + return this.frame.getStatusCode(); + } + + @JsonProperty + public long getUnauthenticatedTimeoutInSeconds() { + return this.headers.unauthenticatedTimeoutInSeconds.getValue(Long.class); + } + + public static RntbdContext decode(final ByteBuf in) { + + in.markReaderIndex(); + + final RntbdResponseStatus frame = RntbdResponseStatus.decode(in); + final int statusCode = frame.getStatusCode(); + final int headersLength = frame.getHeadersLength(); + + if (statusCode < 200 || statusCode >= 400) { + if (!RntbdFramer.canDecodePayload(in, in.readerIndex() + headersLength)) { + in.resetReaderIndex(); + return null; + } + } + + final Headers headers = Headers.decode(in.readSlice(headersLength)); + + if (statusCode < 200 || statusCode >= 400) { + + final ObjectNode details = RntbdObjectMapper.readTree(in.readSlice(in.readIntLE())); + final HashMap map = new HashMap<>(4); + + if (headers.clientVersion.isPresent()) { + map.put("requiredClientVersion", headers.clientVersion.getValue()); + } + + if (headers.protocolVersion.isPresent()) { + map.put("requiredProtocolVersion", headers.protocolVersion.getValue()); + } + + if (headers.serverAgent.isPresent()) { + map.put("serverAgent", headers.serverAgent.getValue()); + } + + if (headers.serverVersion.isPresent()) { + map.put("serverVersion", headers.serverVersion.getValue()); + } + + throw new RntbdContextException(frame.getStatus(), details, Collections.unmodifiableMap(map)); + } + + return new RntbdContext(frame, headers); + } + + public void encode(final ByteBuf out) { + + final int start = out.writerIndex(); + + this.frame.encode(out); + this.headers.encode(out); + + final int length = out.writerIndex() - start; + checkState(length == this.frame.getLength()); + } + + public static RntbdContext from(final RntbdContextRequest request, final ServerProperties properties, final HttpResponseStatus status) { + + // NOTE TO CODE REVIEWERS + // ---------------------- + // In its current form this method is meant to enable a limited set of test scenarios. It will be revised as + // required to support test scenarios as they are developed. + + final Headers headers = new Headers(); + + headers.clientVersion.setValue(request.getClientVersion()); + headers.idleTimeoutInSeconds.setValue(0); + headers.protocolVersion.setValue(CurrentProtocolVersion); + headers.serverAgent.setValue(properties.getAgent()); + headers.serverVersion.setValue(properties.getVersion()); + headers.unauthenticatedTimeoutInSeconds.setValue(0); + + final int length = RntbdResponseStatus.LENGTH + headers.computeLength(); + final UUID activityId = request.getActivityId(); + + final RntbdResponseStatus frame = new RntbdResponseStatus(length, status, activityId); + + return new RntbdContext(frame, headers); + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + private static final class Headers extends RntbdTokenStream { + + RntbdToken clientVersion; + RntbdToken idleTimeoutInSeconds; + RntbdToken protocolVersion; + RntbdToken serverAgent; + RntbdToken serverVersion; + RntbdToken unauthenticatedTimeoutInSeconds; + + Headers() { + + super(RntbdContextHeader.set, RntbdContextHeader.map); + + this.clientVersion = this.get(RntbdContextHeader.ClientVersion); + this.idleTimeoutInSeconds = this.get(RntbdContextHeader.IdleTimeoutInSeconds); + this.protocolVersion = this.get(RntbdContextHeader.ProtocolVersion); + this.serverAgent = this.get(RntbdContextHeader.ServerAgent); + this.serverVersion = this.get(RntbdContextHeader.ServerVersion); + this.unauthenticatedTimeoutInSeconds = this.get(RntbdContextHeader.UnauthenticatedTimeoutInSeconds); + } + + static Headers decode(final ByteBuf in) { + final Headers headers = new Headers(); + Headers.decode(in, headers); + return headers; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextDecoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextDecoder.java new file mode 100644 index 0000000000000..d874549ccd907 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextDecoder.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +class RntbdContextDecoder extends ByteToMessageDecoder { + + private static final Logger logger = LoggerFactory.getLogger(RntbdContextDecoder.class); + + /** + * Deserialize from an input {@link ByteBuf} to an {@link RntbdContext} instance + *

    + * This method decodes an {@link RntbdContext} or {@link RntbdContextException} instance and fires a user event. + * + * @param context the {@link ChannelHandlerContext} to which this {@link RntbdContextDecoder} belongs + * @param in the {@link ByteBuf} from which to readTree data + * @param out the {@link List} to which decoded messages should be added + */ + @Override + protected void decode(final ChannelHandlerContext context, final ByteBuf in, final List out) { + + if (RntbdFramer.canDecodeHead(in)) { + + Object result; + + try { + final RntbdContext rntbdContext = RntbdContext.decode(in); + context.fireUserEventTriggered(rntbdContext); + result = rntbdContext; + } catch (RntbdContextException error) { + context.fireUserEventTriggered(error); + result = error; + } finally { + in.discardReadBytes(); + } + + logger.debug("{} DECODE COMPLETE: {}", context.channel(), result); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextException.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextException.java new file mode 100644 index 0000000000000..992e7664040f1 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextException.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.internal.directconnectivity.TransportException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.netty.handler.codec.http.HttpResponseStatus; + +import java.util.Map; + +public final class RntbdContextException extends TransportException { + + final private CosmosError cosmosError; + final private Map responseHeaders; + final private HttpResponseStatus status; + + RntbdContextException(HttpResponseStatus status, ObjectNode details, Map responseHeaders) { + + super(status + ": " + details, null); + + this.cosmosError = BridgeInternal.createCosmosError(details); + this.responseHeaders = responseHeaders; + this.status = status; + } + + public CosmosError getCosmosError() { + return cosmosError; + } + + public Map getResponseHeaders() { + return responseHeaders; + } + + public HttpResponseStatus getStatus() { + return status; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextNegotiator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextNegotiator.java new file mode 100644 index 0000000000000..58aa970ee3e73 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextNegotiator.java @@ -0,0 +1,120 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.Utils; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.channel.CombinedChannelDuplexHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.CompletableFuture; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +public final class RntbdContextNegotiator extends CombinedChannelDuplexHandler { + + private static final Logger logger = LoggerFactory.getLogger(RntbdContextNegotiator.class); + private final RntbdRequestManager manager; + private final UserAgentContainer userAgent; + + private volatile boolean pendingRntbdContextRequest = true; + + public RntbdContextNegotiator(final RntbdRequestManager manager, final UserAgentContainer userAgent) { + + super(new RntbdContextDecoder(), new RntbdContextRequestEncoder()); + + checkNotNull(manager, "manager"); + checkNotNull(userAgent, "userAgent"); + + this.manager = manager; + this.userAgent = userAgent; + } + + /** + * Called once a write operation is made. The write operation will write the messages through the + * {@link ChannelPipeline}. Those are then ready to be flushed to the actual {@link Channel} once + * {@link Channel#flush()} is called + * + * @param context the {@link ChannelHandlerContext} for which the write operation is made + * @param message the message to write + * @param promise the {@link ChannelPromise} to notify once the operation completes + * @throws Exception thrown if an error occurs + */ + @Override + public void write( + final ChannelHandlerContext context, final Object message, final ChannelPromise promise + ) throws Exception { + + checkArgument(message instanceof ByteBuf, "message: %s", message.getClass()); + final ByteBuf out = (ByteBuf)message; + + if (this.manager.hasRntbdContext()) { + context.writeAndFlush(out, promise); + } else { + if (this.pendingRntbdContextRequest) { + // Thread safe: netty guarantees that no channel handler methods are called concurrently + this.startRntbdContextRequest(context); + this.pendingRntbdContextRequest = false; + } + this.manager.pendWrite(out, promise); + } + } + + // region Privates + + private void startRntbdContextRequest(final ChannelHandlerContext context) throws Exception { + + logger.debug("{} START CONTEXT REQUEST", context.channel()); + + final Channel channel = context.channel(); + final RntbdContextRequest request = new RntbdContextRequest(Utils.randomUUID(), this.userAgent); + final CompletableFuture contextRequestFuture = this.manager.getRntbdContextRequestFuture(); + + super.write(context, request, channel.newPromise().addListener((ChannelFutureListener)future -> { + + if (future.isSuccess()) { + contextRequestFuture.complete(request); + return; + } + + if (future.isCancelled()) { + contextRequestFuture.cancel(true); + return; + } + + contextRequestFuture.completeExceptionally(future.cause()); + })); + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequest.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequest.java new file mode 100644 index 0000000000000..eb439ab06c67f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequest.java @@ -0,0 +1,158 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectWriter; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.CorruptedFrameException; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import static com.azure.data.cosmos.internal.HttpConstants.Versions; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.CurrentProtocolVersion; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdContextRequestHeader; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdOperationType; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdResourceType; + +public final class RntbdContextRequest { + + @JsonProperty + private final UUID activityId; + + @JsonProperty + private final Headers headers; + + RntbdContextRequest(final UUID activityId, final UserAgentContainer userAgent) { + this(activityId, new Headers(userAgent)); + } + + private RntbdContextRequest(final UUID activityId, final Headers headers) { + this.activityId = activityId; + this.headers = headers; + } + + public UUID getActivityId() { + return this.activityId; + } + + public String getClientVersion() { + return this.headers.clientVersion.getValue(String.class); + } + + public static RntbdContextRequest decode(final ByteBuf in) { + + final int resourceOperationTypeCode = in.getInt(in.readerIndex() + Integer.BYTES); + + if (resourceOperationTypeCode != 0) { + final String reason = String.format("resourceOperationCode=0x%08X", resourceOperationTypeCode); + throw new IllegalStateException(reason); + } + + final int start = in.readerIndex(); + final int expectedLength = in.readIntLE(); + + final RntbdRequestFrame header = RntbdRequestFrame.decode(in); + final Headers headers = Headers.decode(in.readSlice(expectedLength - (in.readerIndex() - start))); + + final int observedLength = in.readerIndex() - start; + + if (observedLength != expectedLength) { + final String reason = String.format("expectedLength=%d, observeredLength=%d", expectedLength, observedLength); + throw new IllegalStateException(reason); + } + + in.discardReadBytes(); + return new RntbdContextRequest(header.getActivityId(), headers); + } + + public void encode(final ByteBuf out) { + + final int expectedLength = RntbdRequestFrame.LENGTH + this.headers.computeLength(); + final int start = out.writerIndex(); + + out.writeIntLE(expectedLength); + + final RntbdRequestFrame header = new RntbdRequestFrame(this.getActivityId(), RntbdOperationType.Connection, RntbdResourceType.Connection); + header.encode(out); + this.headers.encode(out); + + final int observedLength = out.writerIndex() - start; + + if (observedLength != expectedLength) { + final String reason = String.format("expectedLength=%d, observeredLength=%d", expectedLength, observedLength); + throw new IllegalStateException(reason); + } + } + + @Override + public String toString() { + final ObjectWriter writer = RntbdObjectMapper.writer(); + try { + return writer.writeValueAsString(this); + } catch (final JsonProcessingException error) { + throw new CorruptedFrameException(error); + } + } + + private static final class Headers extends RntbdTokenStream { + + private static final byte[] ClientVersion = Versions.CURRENT_VERSION.getBytes(StandardCharsets.UTF_8); + + @JsonProperty + RntbdToken clientVersion; + + @JsonProperty + RntbdToken protocolVersion; + + @JsonProperty + RntbdToken userAgent; + + Headers(final UserAgentContainer container) { + + this(); + + this.clientVersion.setValue(ClientVersion); + this.protocolVersion.setValue(CurrentProtocolVersion); + this.userAgent.setValue(container.getUserAgent()); + } + + private Headers() { + + super(RntbdContextRequestHeader.set, RntbdContextRequestHeader.map); + + this.clientVersion = this.get(RntbdContextRequestHeader.ClientVersion); + this.protocolVersion = this.get(RntbdContextRequestHeader.ProtocolVersion); + this.userAgent = this.get(RntbdContextRequestHeader.UserAgent); + } + + static Headers decode(final ByteBuf in) { + return Headers.decode(in, new Headers()); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestDecoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestDecoder.java new file mode 100644 index 0000000000000..473b98fc8ace8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestDecoder.java @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +public class RntbdContextRequestDecoder extends ByteToMessageDecoder { + + public RntbdContextRequestDecoder() { + this.setSingleDecode(true); + } + + /** + * Prepare for decoding an @{link RntbdContextRequest} or fire a channel readTree event to pass the input message along + * + * @param context the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to + * @param message the message to be decoded + * @throws Exception thrown if an error occurs + */ + @Override + public void channelRead(final ChannelHandlerContext context, final Object message) throws Exception { + + if (message instanceof ByteBuf) { + + final ByteBuf in = (ByteBuf)message; + final int resourceOperationType = in.getInt(in.readerIndex() + Integer.BYTES); + + if (resourceOperationType == 0) { + assert this.isSingleDecode(); + super.channelRead(context, message); + return; + } + } + context.fireChannelRead(message); + } + + /** + * Decode an RntbdContextRequest from an {@link ByteBuf} stream + *

    + * This method will be called till either an input {@link ByteBuf} has nothing to readTree on return from this method or + * till nothing is readTree from the input {@link ByteBuf}. + * + * @param context the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to + * @param in the {@link ByteBuf} from which to readTree data + * @param out the {@link List} to which decoded messages should be added + * @throws IllegalStateException thrown if an error occurs + */ + @Override + protected void decode(final ChannelHandlerContext context, final ByteBuf in, final List out) throws IllegalStateException { + + final RntbdContextRequest request; + in.markReaderIndex(); + + try { + request = RntbdContextRequest.decode(in); + } catch (final IllegalStateException error) { + in.resetReaderIndex(); + throw error; + } + + in.discardReadBytes(); + out.add(request); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestEncoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestEncoder.java new file mode 100644 index 0000000000000..02d1f1b13a803 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdContextRequestEncoder.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class RntbdContextRequestEncoder extends MessageToByteEncoder { + + private static final Logger Logger = LoggerFactory.getLogger(RntbdContextRequestEncoder.class); + + /** + * Returns {@code true} if the given message is an @{link RntbdContextRequest} instance + *

    + * If {@code false} this message should be passed to the next @{link ChannelOutboundHandler} in the pipeline. + * + * @param message the message to encode + * @return @{code true}, if the given message is an an @{link RntbdContextRequest} instance; otherwise @{false} + */ + @Override + public boolean acceptOutboundMessage(final Object message) { + return message instanceof RntbdContextRequest; + } + + /** + * Encode an @{link RntbdContextRequest} message into a {@link ByteBuf} + *

    + * This method will be called for each written message that can be handled by this encoder. + * + * @param context the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to + * @param message the message to encode + * @param out the {@link ByteBuf} into which the encoded message will be written + * @throws IllegalStateException is thrown if an error occurs + */ + @Override + protected void encode(final ChannelHandlerContext context, final Object message, final ByteBuf out) throws IllegalStateException { + + final RntbdContextRequest request = (RntbdContextRequest)message; + out.markWriterIndex(); + + try { + request.encode(out); + } catch (final IllegalStateException error) { + out.resetWriterIndex(); + throw error; + } + + Logger.debug("{}: ENCODE COMPLETE: request={}", context.channel(), request); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdEndpoint.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdEndpoint.java new file mode 100644 index 0000000000000..d7c10dd127988 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdEndpoint.java @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.UserAgentContainer; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.ssl.SslContext; + +import java.net.URI; +import java.util.stream.Stream; + +import static com.azure.data.cosmos.internal.directconnectivity.RntbdTransportClient.Options; +import static com.google.common.base.Preconditions.checkNotNull; + +public interface RntbdEndpoint extends AutoCloseable { + + String getName(); + + @Override + void close() throws RuntimeException; + + RntbdRequestRecord request(RntbdRequestArgs requestArgs); + + interface Provider extends AutoCloseable { + + @Override + void close() throws RuntimeException; + + Config config(); + + int count(); + + RntbdEndpoint get(URI physicalAddress); + + Stream list(); + } + + final class Config { + + private final Options options; + private final SslContext sslContext; + private final LogLevel wireLogLevel; + + public Config(final Options options, final SslContext sslContext, final LogLevel wireLogLevel) { + + checkNotNull(options, "options"); + checkNotNull(sslContext, "sslContext"); + + this.options = options; + this.sslContext = sslContext; + this.wireLogLevel = wireLogLevel; + } + + public int getConnectionTimeout() { + final long value = this.options.getConnectionTimeout().toMillis(); + assert value <= Integer.MAX_VALUE; + return (int)value; + } + + public int getMaxChannelsPerEndpoint() { + return this.options.getMaxChannelsPerEndpoint(); + } + + public int getMaxRequestsPerChannel() { + return this.options.getMaxRequestsPerChannel(); + } + + public long getReceiveHangDetectionTime() { + return this.options.getReceiveHangDetectionTime().toNanos(); + } + + public long getRequestTimeout() { + return this.options.getRequestTimeout().toNanos(); + } + + public long getSendHangDetectionTime() { + return this.options.getSendHangDetectionTime().toNanos(); + } + + public SslContext getSslContext() { + return this.sslContext; + } + + public UserAgentContainer getUserAgent() { + return this.options.getUserAgent(); + } + + public LogLevel getWireLogLevel() { + return this.wireLogLevel; + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdFramer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdFramer.java new file mode 100644 index 0000000000000..c856587132d0b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdFramer.java @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.CorruptedFrameException; + +import static com.google.common.base.Preconditions.checkNotNull; + +final class RntbdFramer { + + private RntbdFramer() { + } + + static boolean canDecodeHead(final ByteBuf in) throws CorruptedFrameException { + + checkNotNull(in, "in"); + + if (in.readableBytes() < RntbdResponseStatus.LENGTH) { + return false; + } + + final int start = in.readerIndex(); + final long length = in.getUnsignedIntLE(start); + + if (length > Integer.MAX_VALUE) { + final String reason = String.format("Head frame length exceeds Integer.MAX_VALUE, %d: %d", + Integer.MAX_VALUE, length + ); + throw new CorruptedFrameException(reason); + } + + if (length < Integer.BYTES) { + final String reason = String.format("Head frame length is less than size of length field, %d: %d", + Integer.BYTES, length + ); + throw new CorruptedFrameException(reason); + } + + return length <= in.readableBytes(); + } + + static boolean canDecodePayload(final ByteBuf in, final int start) { + + checkNotNull(in, "in"); + + final int readerIndex = in.readerIndex(); + + if (start < readerIndex) { + throw new IllegalArgumentException("start < in.readerIndex()"); + } + + final int offset = start - readerIndex; + + if (in.readableBytes() - offset < Integer.BYTES) { + return false; + } + + final long length = in.getUnsignedIntLE(start); + + if (length > Integer.MAX_VALUE) { + final String reason = String.format("Payload frame length exceeds Integer.MAX_VALUE, %d: %d", + Integer.MAX_VALUE, length + ); + throw new CorruptedFrameException(reason); + } + + return offset + Integer.BYTES + length <= in.readableBytes(); + } + + static boolean canDecodePayload(final ByteBuf in) { + return canDecodePayload(in, in.readerIndex()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdMetrics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdMetrics.java new file mode 100644 index 0000000000000..e7aee53bc5d63 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdMetrics.java @@ -0,0 +1,159 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.codahale.metrics.Gauge; +import com.codahale.metrics.Meter; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.RatioGauge; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.google.common.base.Stopwatch; + +import java.time.Duration; + +@JsonPropertyOrder({ + "lifetime", "requests", "responses", "errorResponses", "responseRate", "completionRate", "throughput" +}) +public final class RntbdMetrics implements AutoCloseable { + + // region Fields + + private static final MetricRegistry registry = new MetricRegistry(); + + private final Gauge completionRate; + private final Meter errorResponses; + private final Stopwatch lifetime; + private final String prefix; + private final Meter requests; + private final Gauge responseRate; + private final Meter responses; + + // endregion + + // region Constructors + + public RntbdMetrics(final String name) { + + this.lifetime = Stopwatch.createStarted(); + this.prefix = name + '.'; + + this.requests = registry.register(this.prefix + "requests", new Meter()); + this.responses = registry.register(this.prefix + "responses", new Meter()); + this.errorResponses = registry.register(this.prefix + "errorResponses", new Meter()); + this.responseRate = registry.register(this.prefix + "responseRate", new ResponseRate(this)); + this.completionRate = registry.register(this.prefix + "completionRate", new CompletionRate(this)); + } + + // endregion + + // region Accessors + + public double getCompletionRate() { + return this.completionRate.getValue(); + } + + public long getErrorResponses() { + return this.errorResponses.getCount(); + } + + public double getLifetime() { + final Duration elapsed = this.lifetime.elapsed(); + return elapsed.getSeconds() + (1E-9D * elapsed.getNano()); + } + + public long getRequests() { + return this.requests.getCount(); + } + + public double getResponseRate() { + return this.responseRate.getValue(); + } + + public long getResponses() { + return this.responses.getCount(); + } + + public double getThroughput() { + return this.responses.getMeanRate(); + } + + // endregion + + // region Methods + + @Override + public void close() { + registry.removeMatching(MetricFilter.startsWith(this.prefix)); + } + + public final void incrementErrorResponseCount() { + this.errorResponses.mark(); + } + + public final void incrementRequestCount() { + this.requests.mark(); + } + + public final void incrementResponseCount() { + this.responses.mark(); + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + // endregion + + private static final class CompletionRate extends RatioGauge { + + private final RntbdMetrics metrics; + + private CompletionRate(RntbdMetrics metrics) { + this.metrics = metrics; + } + + @Override + protected Ratio getRatio() { + return Ratio.of(this.metrics.responses.getCount() - this.metrics.errorResponses.getCount(), + this.metrics.requests.getCount()); + } + } + + private static final class ResponseRate extends RatioGauge { + + private final RntbdMetrics metrics; + + private ResponseRate(RntbdMetrics metrics) { + this.metrics = metrics; + } + + @Override + protected Ratio getRatio() { + return Ratio.of(this.metrics.responses.getCount(), this.metrics.requests.getCount()); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdObjectMapper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdObjectMapper.java new file mode 100644 index 0000000000000..5b67ecf321514 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdObjectMapper.java @@ -0,0 +1,106 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.ser.PropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.handler.codec.CorruptedFrameException; +import io.netty.handler.codec.EncoderException; + +import java.io.IOException; +import java.io.InputStream; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class RntbdObjectMapper { + + private static final SimpleFilterProvider filterProvider; + private static final ObjectMapper objectMapper; + private static final ObjectWriter objectWriter; + + static { + objectMapper = new ObjectMapper().setFilterProvider(filterProvider = new SimpleFilterProvider()); + objectWriter = objectMapper.writer(); + } + + private RntbdObjectMapper() { + } + + static ObjectNode readTree(final RntbdResponse response) { + checkNotNull(response, "response"); + return readTree(response.getContent()); + } + + static ObjectNode readTree(final ByteBuf in) { + + checkNotNull(in, "in"); + final JsonNode node; + + try (final InputStream istream = new ByteBufInputStream(in)) { + node = objectMapper.readTree(istream); + } catch (final IOException error) { + throw new CorruptedFrameException(error); + } + + if (node.isObject()) { + return (ObjectNode)node; + } + + final String cause = String.format("Expected %s, not %s", JsonNodeType.OBJECT, node.getNodeType()); + throw new CorruptedFrameException(cause); + } + + static void registerPropertyFilter(final Class type, final Class filter) { + + checkNotNull(type, "type"); + checkNotNull(filter, "filter"); + + try { + filterProvider.addFilter(type.getSimpleName(), filter.newInstance()); + } catch (final ReflectiveOperationException error) { + throw new IllegalStateException(error); + } + } + + public static String toJson(Object value) { + try { + return objectWriter.writeValueAsString(value); + } catch (final JsonProcessingException error) { + throw new EncoderException(error); + } + } + + public static ObjectWriter writer() { + return objectWriter; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdReporter.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdReporter.java new file mode 100644 index 0000000000000..c47aa2f9e4933 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdReporter.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.helpers.FormattingTuple; +import org.slf4j.helpers.MessageFormatter; + +import java.io.File; +import java.net.URL; + +public final class RntbdReporter { + + private static final String codeSource; + + static { + String value; + try { + URL url = RntbdReporter.class.getProtectionDomain().getCodeSource().getLocation(); + File file = new File(url.toURI()); + value = file.getName(); + } catch (Throwable error) { + value = "azure-cosmosdb-direct"; + } + codeSource = value; + } + + private RntbdReporter() { + } + + public static void reportIssue(Logger logger, Object subject, String format, Object... arguments) { + if (logger.isErrorEnabled()) { + doReportIssue(logger, subject, format, arguments); + } + } + + public static void reportIssueUnless( + boolean predicate, Logger logger, Object subject, String format, Object... arguments + ) { + if (!predicate && logger.isErrorEnabled()) { + doReportIssue(logger, subject, format, arguments); + } + } + + private static void doReportIssue(Logger logger, Object subject, String format, Object[] arguments) { + + FormattingTuple formattingTuple = MessageFormatter.arrayFormat(format, arguments); + StackTraceElement[] stackTraceElements = new Exception().getStackTrace(); + Throwable throwable = formattingTuple.getThrowable(); + + if (throwable == null) { + logger.error("Report this {} issue to ensure it is addressed:\n[{}]\n[{}]\n[{}]", + codeSource, subject, stackTraceElements[2], formattingTuple.getMessage() + ); + } else { + logger.error("Report this {} issue to ensure it is addressed:\n[{}]\n[{}]\n[{}{}{}]", + codeSource, subject, stackTraceElements[2], formattingTuple.getMessage(), + throwable, ExceptionUtils.getStackTrace(throwable) + ); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequest.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequest.java new file mode 100644 index 0000000000000..777e439396358 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequest.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.netty.buffer.ByteBuf; + +import java.util.UUID; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdRequestHeader; +import static com.google.common.base.Preconditions.checkNotNull; + +public final class RntbdRequest { + + private static final byte[] EmptyByteArray = {}; + + private final RntbdRequestFrame frame; + private final RntbdRequestHeaders headers; + private final byte[] payload; + + private RntbdRequest(final RntbdRequestFrame frame, final RntbdRequestHeaders headers, final byte[] payload) { + + checkNotNull(frame, "frame"); + checkNotNull(headers, "headers"); + + this.frame = frame; + this.headers = headers; + this.payload = payload == null ? EmptyByteArray : payload; + } + + public UUID getActivityId() { + return this.frame.getActivityId(); + } + + @JsonIgnore + @SuppressWarnings("unchecked") + public T getHeader(final RntbdRequestHeader header) { + return (T)this.headers.get(header).getValue(); + } + + public Long getTransportRequestId() { + return this.getHeader(RntbdRequestHeader.TransportRequestID); + } + + public static RntbdRequest decode(final ByteBuf in) { + + final int resourceOperationCode = in.getInt(in.readerIndex() + Integer.BYTES); + + if (resourceOperationCode == 0) { + final String reason = String.format("resourceOperationCode=0x%08X", resourceOperationCode); + throw new IllegalStateException(reason); + } + + final int start = in.readerIndex(); + final int expectedLength = in.readIntLE(); + + final RntbdRequestFrame header = RntbdRequestFrame.decode(in); + final RntbdRequestHeaders metadata = RntbdRequestHeaders.decode(in); + final ByteBuf payloadBuf = in.readSlice(expectedLength - (in.readerIndex() - start)); + + final int observedLength = in.readerIndex() - start; + + if (observedLength != expectedLength) { + final String reason = String.format("expectedLength=%d, observedLength=%d", expectedLength, observedLength); + throw new IllegalStateException(reason); + } + + final byte[] payload = new byte[payloadBuf.readableBytes()]; + payloadBuf.readBytes(payload); + in.discardReadBytes(); + + return new RntbdRequest(header, metadata, payload); + } + + void encode(final ByteBuf out) { + + final int expectedLength = RntbdRequestFrame.LENGTH + this.headers.computeLength(); + final int start = out.readerIndex(); + + out.writeIntLE(expectedLength); + this.frame.encode(out); + this.headers.encode(out); + + assert out.writerIndex() - start == expectedLength; + + if (this.payload.length > 0) { + out.writeIntLE(this.payload.length); + out.writeBytes(this.payload); + } + } + + public static RntbdRequest from(final RntbdRequestArgs args) { + + final RxDocumentServiceRequest serviceRequest = args.getServiceRequest(); + + final RntbdRequestFrame frame = new RntbdRequestFrame( + args.getActivityId(), + serviceRequest.getOperationType(), + serviceRequest.getResourceType()); + + final RntbdRequestHeaders headers = new RntbdRequestHeaders(args, frame); + + return new RntbdRequest(frame, headers, serviceRequest.getContent()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestArgs.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestArgs.java new file mode 100644 index 0000000000000..bf350c0e9b048 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestArgs.java @@ -0,0 +1,130 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.google.common.base.Stopwatch; +import io.netty.channel.ChannelHandlerContext; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; + +import java.math.BigDecimal; +import java.net.URI; +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; + +@JsonPropertyOrder({ + "transportRequestId", "origin", "replicaPath", "activityId", "operationType", "resourceType", "birthTime", + "lifetime" +}) +public final class RntbdRequestArgs { + + private static final AtomicLong instanceCount = new AtomicLong(); + private static final String simpleClassName = RntbdRequestArgs.class.getSimpleName(); + + private final UUID activityId; + private final long birthTime; + private final Stopwatch lifetime; + private final String origin; + private final URI physicalAddress; + private final String replicaPath; + private final RxDocumentServiceRequest serviceRequest; + private final long transportRequestId; + + public RntbdRequestArgs(final RxDocumentServiceRequest serviceRequest, final URI physicalAddress) { + this.activityId = UUID.fromString(serviceRequest.getActivityId()); + this.birthTime = System.nanoTime(); + this.lifetime = Stopwatch.createStarted(); + this.origin = physicalAddress.getScheme() + "://" + physicalAddress.getAuthority(); + this.physicalAddress = physicalAddress; + this.replicaPath = StringUtils.stripEnd(physicalAddress.getPath(), "/"); + this.serviceRequest = serviceRequest; + this.transportRequestId = instanceCount.incrementAndGet(); + } + + public UUID getActivityId() { + return this.activityId; + } + + public long getBirthTime() { + return this.birthTime; + } + + @JsonSerialize(using = ToStringSerializer.class) + public Duration getLifetime() { + return this.lifetime.elapsed(); + } + + public String getOrigin() { + return this.origin; + } + + @JsonIgnore + public URI getPhysicalAddress() { + return this.physicalAddress; + } + + public String getReplicaPath() { + return this.replicaPath; + } + + @JsonIgnore + public RxDocumentServiceRequest getServiceRequest() { + return this.serviceRequest; + } + + public long getTransportRequestId() { + return this.transportRequestId; + } + + @Override + public String toString() { + return simpleClassName + '(' + RntbdObjectMapper.toJson(this) + ')'; + } + + public void traceOperation(final Logger logger, final ChannelHandlerContext context, final String operationName, final Object... args) { + + checkNotNull(logger, "logger"); + + if (logger.isTraceEnabled()) { + final BigDecimal lifetime = BigDecimal.valueOf(this.lifetime.elapsed().toNanos(), 6); + logger.trace("{},{},\"{}({})\",\"{}\",\"{}\"", this.birthTime, lifetime, operationName, + Stream.of(args).map(arg -> + arg == null ? "null" : arg.toString()).collect(Collectors.joining(",") + ), + this, context + ); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestDecoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestDecoder.java new file mode 100644 index 0000000000000..53837fcfb2ac2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestDecoder.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.List; + +public final class RntbdRequestDecoder extends ByteToMessageDecoder { + /** + * Prepare for decoding an @{link RntbdRequest} or fire a channel readTree event to pass the input message along + * + * @param context the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to + * @param message the message to be decoded + * @throws Exception thrown if an error occurs + */ + @Override + public void channelRead(final ChannelHandlerContext context, final Object message) throws Exception { + + if (message instanceof ByteBuf) { + + final ByteBuf in = (ByteBuf)message; + final int resourceOperationType = in.getInt(in.readerIndex() + Integer.BYTES); + + if (resourceOperationType != 0) { + super.channelRead(context, message); + return; + } + } + + context.fireChannelRead(message); + } + + /** + * Decode the input {@link ByteBuf} to an RntbdRequest instance + *

    + * This method will be called till either the input {@link ByteBuf} has nothing to readTree after return from this + * method or till nothing was readTree from the input {@link ByteBuf}. + * + * @param context the {@link ChannelHandlerContext} which this {@link ByteToMessageDecoder} belongs to + * @param in the {@link ByteBuf} from which to readTree data + * @param out the {@link List} to which decoded messages should be added + * @throws IllegalStateException thrown if an error occurs + */ + @Override + protected void decode(final ChannelHandlerContext context, final ByteBuf in, final List out) throws IllegalStateException { + + final RntbdRequest request; + in.markReaderIndex(); + + try { + request = RntbdRequest.decode(in); + } catch (final IllegalStateException error) { + in.resetReaderIndex(); + throw error; + } + + in.discardReadBytes(); + out.add(request); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestEncoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestEncoder.java new file mode 100644 index 0000000000000..d96fd9c9df3ba --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestEncoder.java @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandler; +import io.netty.handler.codec.MessageToByteEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class RntbdRequestEncoder extends MessageToByteEncoder { + + private static final Logger logger = LoggerFactory.getLogger(RntbdRequestEncoder.class); + + /** + * Returns {@code true} if the given message is an @{link RntbdRequest} instance + *

    + * If {@code false} this message should be passed to the next {@link ChannelOutboundHandler} in the pipeline. + * + * @param message the message to encode + * @return {@code true}, if the given message is an an {@link RntbdRequest} instance; otherwise @{false} + */ + @Override + public boolean acceptOutboundMessage(final Object message) { + return message instanceof RntbdRequestArgs; + } + + /** + * Encode a message into a {@link ByteBuf} + *

    + * This method will be called for each message that can be written by this encoder. + * + * @param context the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs encode + * @param message the message to encode + * @param out the {@link ByteBuf} into which the encoded message will be written + */ + @Override + protected void encode(final ChannelHandlerContext context, final Object message, final ByteBuf out) throws Exception { + + final RntbdRequest request = RntbdRequest.from((RntbdRequestArgs)message); + final int start = out.writerIndex(); + + try { + request.encode(out); + } catch (final Throwable error) { + out.writerIndex(start); + throw error; + } + + if (logger.isDebugEnabled()) { + final int length = out.writerIndex() - start; + logger.debug("{}: ENCODE COMPLETE: length={}, request={}", context.channel(), length, request); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFrame.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFrame.java new file mode 100644 index 0000000000000..d650ce5be4a59 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFrame.java @@ -0,0 +1,234 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import io.netty.buffer.ByteBuf; + +import java.util.Locale; +import java.util.UUID; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdOperationType; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdResourceType; + +final class RntbdRequestFrame { + + // region Fields + + static final int LENGTH = Integer.BYTES // messageLength + + Short.BYTES // resourceType + + Short.BYTES // operationType + + 2 * Long.BYTES; // activityId + + private final UUID activityId; + private final RntbdOperationType operationType; + private final RntbdResourceType resourceType; + + // region Constructors + + RntbdRequestFrame(final UUID activityId, final OperationType operationType, final ResourceType resourceType) { + this(activityId, map(operationType), map(resourceType)); + } + + RntbdRequestFrame(final UUID activityId, final RntbdOperationType operationType, final RntbdResourceType resourceType) { + this.activityId = activityId; + this.operationType = operationType; + this.resourceType = resourceType; + } + + // endregion + + // region Methods + + UUID getActivityId() { + return this.activityId; + } + + RntbdOperationType getOperationType() { + return this.operationType; + } + + RntbdResourceType getResourceType() { + return this.resourceType; + } + + static RntbdRequestFrame decode(final ByteBuf in) { + + final RntbdResourceType resourceType = RntbdResourceType.fromId(in.readShortLE()); + final RntbdOperationType operationType = RntbdOperationType.fromId(in.readShortLE()); + final UUID activityId = RntbdUUID.decode(in); + + return new RntbdRequestFrame(activityId, operationType, resourceType); + } + + void encode(final ByteBuf out) { + out.writeShortLE(this.resourceType.id()); + out.writeShortLE(this.operationType.id()); + RntbdUUID.encode(this.activityId, out); + } + + private static RntbdResourceType map(final ResourceType resourceType) { + + switch (resourceType) { + case Attachment: + return RntbdResourceType.Attachment; + case DocumentCollection: + return RntbdResourceType.Collection; + case Conflict: + return RntbdResourceType.Conflict; + case Database: + return RntbdResourceType.Database; + case Document: + return RntbdResourceType.Document; + case Module: + return RntbdResourceType.Module; + case ModuleCommand: + return RntbdResourceType.ModuleCommand; + case Record: + return RntbdResourceType.Record; + case Permission: + return RntbdResourceType.Permission; + case Replica: + return RntbdResourceType.Replica; + case StoredProcedure: + return RntbdResourceType.StoredProcedure; + case Trigger: + return RntbdResourceType.Trigger; + case User: + return RntbdResourceType.User; + case UserDefinedType: + return RntbdResourceType.UserDefinedType; + case UserDefinedFunction: + return RntbdResourceType.UserDefinedFunction; + case Offer: + return RntbdResourceType.Offer; + case PartitionSetInformation: + return RntbdResourceType.PartitionSetInformation; + case XPReplicatorAddress: + return RntbdResourceType.XPReplicatorAddress; + case MasterPartition: + return RntbdResourceType.MasterPartition; + case ServerPartition: + return RntbdResourceType.ServerPartition; + case DatabaseAccount: + return RntbdResourceType.DatabaseAccount; + case Topology: + return RntbdResourceType.Topology; + case PartitionKeyRange: + return RntbdResourceType.PartitionKeyRange; + case Schema: + return RntbdResourceType.Schema; + case BatchApply: + return RntbdResourceType.BatchApply; + case RestoreMetadata: + return RntbdResourceType.RestoreMetadata; + case ComputeGatewayCharges: + return RntbdResourceType.ComputeGatewayCharges; + case RidRange: + return RntbdResourceType.RidRange; + default: + final String reason = String.format(Locale.ROOT, "Unrecognized resource type: %s", resourceType); + throw new UnsupportedOperationException(reason); + } + } + + private static RntbdOperationType map(final OperationType operationType) { + + switch (operationType) { + case Crash: + return RntbdOperationType.Crash; + case Create: + return RntbdOperationType.Create; + case Delete: + return RntbdOperationType.Delete; + case ExecuteJavaScript: + return RntbdOperationType.ExecuteJavaScript; + case Query: + return RntbdOperationType.Query; + case Pause: + return RntbdOperationType.Pause; + case Read: + return RntbdOperationType.Read; + case ReadFeed: + return RntbdOperationType.ReadFeed; + case Recreate: + return RntbdOperationType.Recreate; + case Recycle: + return RntbdOperationType.Recycle; + case Replace: + return RntbdOperationType.Replace; + case Resume: + return RntbdOperationType.Resume; + case Stop: + return RntbdOperationType.Stop; + case SqlQuery: + return RntbdOperationType.SQLQuery; + case Update: + return RntbdOperationType.Update; + case ForceConfigRefresh: + return RntbdOperationType.ForceConfigRefresh; + case Head: + return RntbdOperationType.Head; + case HeadFeed: + return RntbdOperationType.HeadFeed; + case Upsert: + return RntbdOperationType.Upsert; + case Throttle: + return RntbdOperationType.Throttle; + case PreCreateValidation: + return RntbdOperationType.PreCreateValidation; + case GetSplitPoint: + return RntbdOperationType.GetSplitPoint; + case AbortSplit: + return RntbdOperationType.AbortSplit; + case CompleteSplit: + return RntbdOperationType.CompleteSplit; + case BatchApply: + return RntbdOperationType.BatchApply; + case OfferUpdateOperation: + return RntbdOperationType.OfferUpdateOperation; + case OfferPreGrowValidation: + return RntbdOperationType.OfferPreGrowValidation; + case BatchReportThroughputUtilization: + return RntbdOperationType.BatchReportThroughputUtilization; + case AbortPartitionMigration: + return RntbdOperationType.AbortPartitionMigration; + case CompletePartitionMigration: + return RntbdOperationType.CompletePartitionMigration; + case PreReplaceValidation: + return RntbdOperationType.PreReplaceValidation; + case MigratePartition: + return RntbdOperationType.MigratePartition; + case AddComputeGatewayRequestCharges: + return RntbdOperationType.AddComputeGatewayRequestCharges; + default: + final String reason = String.format(Locale.ROOT, "Unrecognized operation type: %s", operationType); + throw new UnsupportedOperationException(reason); + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFramer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFramer.java new file mode 100644 index 0000000000000..1dda4f7d544ad --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestFramer.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; + +import java.nio.ByteOrder; + +public final class RntbdRequestFramer extends LengthFieldBasedFrameDecoder { + + public RntbdRequestFramer() { + super(ByteOrder.LITTLE_ENDIAN, Integer.MAX_VALUE, 0, Integer.BYTES, -Integer.BYTES, 0, true); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestHeaders.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestHeaders.java new file mode 100644 index 0000000000000..4a07dbb95744a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestHeaders.java @@ -0,0 +1,1273 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.IndexingDirective; +import com.azure.data.cosmos.internal.ContentSerializationFormat; +import com.azure.data.cosmos.internal.EnumerationDirection; +import com.azure.data.cosmos.internal.FanoutOperationState; +import com.azure.data.cosmos.internal.MigrateCollectionDirective; +import com.azure.data.cosmos.internal.Paths; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.ReadFeedKeyType; +import com.azure.data.cosmos.internal.RemoteStorageType; +import com.azure.data.cosmos.internal.ResourceId; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.fasterxml.jackson.annotation.JsonFilter; +import io.netty.buffer.ByteBuf; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; + +import java.util.Base64; +import java.util.Locale; +import java.util.Map; +import java.util.function.Supplier; + +import static com.azure.data.cosmos.internal.HttpConstants.HttpHeaders; +import static com.azure.data.cosmos.internal.directconnectivity.WFConstants.BackendHeaders; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdConsistencyLevel; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdContentSerializationFormat; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdEnumerationDirection; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdFanoutOperationState; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdIndexingDirective; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdMigrateCollectionDirective; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdOperationType; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdReadFeedKeyType; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdRemoteStorageType; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdRequestHeader; +import static com.google.common.base.Preconditions.checkNotNull; + +@JsonFilter("RntbdToken") +final class RntbdRequestHeaders extends RntbdTokenStream { + + // region Fields + + private static final String UrlTrim = "/+"; + + // endregion + + // region Constructors + + RntbdRequestHeaders(final RntbdRequestArgs args, final RntbdRequestFrame frame) { + + this(); + + checkNotNull(args, "args"); + checkNotNull(frame, "frame"); + + final RxDocumentServiceRequest request = args.getServiceRequest(); + final byte[] content = request.getContent(); + + this.getPayloadPresent().setValue(content != null && content.length > 0); + this.getReplicaPath().setValue(args.getReplicaPath()); + this.getTransportRequestID().setValue(args.getTransportRequestId()); + + final Map headers = request.getHeaders(); + + // Special-case headers + + this.addAimHeader(headers); + this.addAllowScanOnQuery(headers); + this.addBinaryIdIfPresent(headers); + this.addCanCharge(headers); + this.addCanOfferReplaceComplete(headers); + this.addCanThrottle(headers); + this.addCollectionRemoteStorageSecurityIdentifier(headers); + this.addConsistencyLevelHeader(headers); + this.addContentSerializationFormat(headers); + this.addContinuationToken(request); + this.addDateHeader(headers); + this.addDisableRUPerMinuteUsage(headers); + this.addEmitVerboseTracesInQuery(headers); + this.addEnableLogging(headers); + this.addEnableLowPrecisionOrderBy(headers); + this.addEntityId(headers); + this.addEnumerationDirection(headers); + this.addExcludeSystemProperties(headers); + this.addFanoutOperationStateHeader(headers); + this.addIfModifiedSinceHeader(headers); + this.addIndexingDirectiveHeader(headers); + this.addIsAutoScaleRequest(headers); + this.addIsFanout(headers); + this.addIsReadOnlyScript(headers); + this.addIsUserRequest(headers); + this.addMatchHeader(headers, frame.getOperationType()); + this.addMigrateCollectionDirectiveHeader(headers); + this.addPageSize(headers); + this.addPopulateCollectionThroughputInfo(headers); + this.addPopulatePartitionStatistics(headers); + this.addPopulateQueryMetrics(headers); + this.addPopulateQuotaInfo(headers); + this.addProfileRequest(headers); + this.addQueryForceScan(headers); + this.addRemoteStorageType(headers); + this.addResourceIdOrPathHeaders(request); + this.addResponseContinuationTokenLimitInKb(headers); + this.addShareThroughput(headers); + this.addStartAndEndKeys(headers); + this.addSupportSpatialLegacyCoordinates(headers); + this.addUsePolygonsSmallerThanAHemisphere(headers); + + // Normal headers (Strings, Ints, Longs, etc.) + + this.fillTokenFromHeader(headers, this::getAllowTentativeWrites, BackendHeaders.ALLOW_TENTATIVE_WRITES); + this.fillTokenFromHeader(headers, this::getAuthorizationToken, HttpHeaders.AUTHORIZATION); + this.fillTokenFromHeader(headers, this::getBinaryPassThroughRequest, BackendHeaders.BINARY_PASSTHROUGH_REQUEST); + this.fillTokenFromHeader(headers, this::getBindReplicaDirective, BackendHeaders.BIND_REPLICA_DIRECTIVE); + this.fillTokenFromHeader(headers, this::getClientRetryAttemptCount, HttpHeaders.CLIENT_RETRY_ATTEMPT_COUNT); + this.fillTokenFromHeader(headers, this::getCollectionPartitionIndex, BackendHeaders.COLLECTION_PARTITION_INDEX); + this.fillTokenFromHeader(headers, this::getCollectionRid, BackendHeaders.COLLECTION_RID); + this.fillTokenFromHeader(headers, this::getCollectionServiceIndex, BackendHeaders.COLLECTION_SERVICE_INDEX); + this.fillTokenFromHeader(headers, this::getEffectivePartitionKey, BackendHeaders.EFFECTIVE_PARTITION_KEY); + this.fillTokenFromHeader(headers, this::getEnableDynamicRidRangeAllocation, BackendHeaders.ENABLE_DYNAMIC_RID_RANGE_ALLOCATION); + this.fillTokenFromHeader(headers, this::getFilterBySchemaRid, HttpHeaders.FILTER_BY_SCHEMA_RESOURCE_ID); + this.fillTokenFromHeader(headers, this::getGatewaySignature, HttpHeaders.GATEWAY_SIGNATURE); + this.fillTokenFromHeader(headers, this::getPartitionCount, BackendHeaders.PARTITION_COUNT); + this.fillTokenFromHeader(headers, this::getPartitionKey, HttpHeaders.PARTITION_KEY); + this.fillTokenFromHeader(headers, this::getPartitionKeyRangeId, HttpHeaders.PARTITION_KEY_RANGE_ID); + this.fillTokenFromHeader(headers, this::getPartitionResourceFilter, BackendHeaders.PARTITION_RESOURCE_FILTER); + this.fillTokenFromHeader(headers, this::getPostTriggerExclude, HttpHeaders.POST_TRIGGER_EXCLUDE); + this.fillTokenFromHeader(headers, this::getPostTriggerInclude, HttpHeaders.POST_TRIGGER_INCLUDE); + this.fillTokenFromHeader(headers, this::getPreTriggerExclude, HttpHeaders.PRE_TRIGGER_EXCLUDE); + this.fillTokenFromHeader(headers, this::getPreTriggerInclude, HttpHeaders.PRE_TRIGGER_INCLUDE); + this.fillTokenFromHeader(headers, this::getPrimaryMasterKey, BackendHeaders.PRIMARY_MASTER_KEY); + this.fillTokenFromHeader(headers, this::getPrimaryReadonlyKey, BackendHeaders.PRIMARY_READONLY_KEY); + this.fillTokenFromHeader(headers, this::getRemainingTimeInMsOnClientRequest, HttpHeaders.REMAINING_TIME_IN_MS_ON_CLIENT_REQUEST); + this.fillTokenFromHeader(headers, this::getResourceSchemaName, BackendHeaders.RESOURCE_SCHEMA_NAME); + this.fillTokenFromHeader(headers, this::getResourceTokenExpiry, HttpHeaders.RESOURCE_TOKEN_EXPIRY); + this.fillTokenFromHeader(headers, this::getRestoreMetadataFilter, HttpHeaders.RESTORE_METADATA_FILTER); + this.fillTokenFromHeader(headers, this::getRestoreParams, BackendHeaders.RESTORE_PARAMS); + this.fillTokenFromHeader(headers, this::getSecondaryMasterKey, BackendHeaders.SECONDARY_MASTER_KEY); + this.fillTokenFromHeader(headers, this::getSecondaryReadonlyKey, BackendHeaders.SECONDARY_READONLY_KEY); + this.fillTokenFromHeader(headers, this::getSessionToken, HttpHeaders.SESSION_TOKEN); + this.fillTokenFromHeader(headers, this::getSharedOfferThroughput, HttpHeaders.SHARED_OFFER_THROUGHPUT); + this.fillTokenFromHeader(headers, this::getTargetGlobalCommittedLsn, HttpHeaders.TARGET_GLOBAL_COMMITTED_LSN); + this.fillTokenFromHeader(headers, this::getTargetLsn, HttpHeaders.TARGET_LSN); + this.fillTokenFromHeader(headers, this::getTimeToLiveInSeconds, BackendHeaders.TIME_TO_LIVE_IN_SECONDS); + this.fillTokenFromHeader(headers, this::getTransportRequestID, HttpHeaders.TRANSPORT_REQUEST_ID); + + // Will be null in case of direct, which is fine - BE will use the value slice the connection context this. + // When this is used in Gateway, the header value will be populated with the proxied HTTP request's header, + // and BE will respect the per-request value. + + this.fillTokenFromHeader(headers, this::getClientVersion, HttpHeaders.VERSION); + } + + private RntbdRequestHeaders() { + super(RntbdRequestHeader.set, RntbdRequestHeader.map); + } + + // endregion + + // region Methods + + static RntbdRequestHeaders decode(final ByteBuf in) { + final RntbdRequestHeaders metadata = new RntbdRequestHeaders(); + return RntbdRequestHeaders.decode(in, metadata); + } + + // endregion + + // region Privates + + private RntbdToken getAIM() { + return this.get(RntbdRequestHeader.A_IM); + } + + private RntbdToken getAllowTentativeWrites() { + return this.get(RntbdRequestHeader.AllowTentativeWrites); + } + + private RntbdToken getAttachmentName() { + return this.get(RntbdRequestHeader.AttachmentName); + } + + private RntbdToken getAuthorizationToken() { + return this.get(RntbdRequestHeader.AuthorizationToken); + } + + private RntbdToken getBinaryId() { + return this.get(RntbdRequestHeader.BinaryId); + } + + private RntbdToken getBinaryPassThroughRequest() { + return this.get(RntbdRequestHeader.BinaryPassthroughRequest); + } + + private RntbdToken getBindReplicaDirective() { + return this.get(RntbdRequestHeader.BindReplicaDirective); + } + + private RntbdToken getCanCharge() { + return this.get(RntbdRequestHeader.CanCharge); + } + + private RntbdToken getCanOfferReplaceComplete() { + return this.get(RntbdRequestHeader.CanOfferReplaceComplete); + } + + private RntbdToken getCanThrottle() { + return this.get(RntbdRequestHeader.CanThrottle); + } + + private RntbdToken getClientRetryAttemptCount() { + return this.get(RntbdRequestHeader.ClientRetryAttemptCount); + } + + private RntbdToken getClientVersion() { + return this.get(RntbdRequestHeader.ClientVersion); + } + + private RntbdToken getCollectionName() { + return this.get(RntbdRequestHeader.CollectionName); + } + + private RntbdToken getCollectionPartitionIndex() { + return this.get(RntbdRequestHeader.CollectionPartitionIndex); + } + + private RntbdToken getCollectionRemoteStorageSecurityIdentifier() { + return this.get(RntbdRequestHeader.CollectionRemoteStorageSecurityIdentifier); + } + + private RntbdToken getCollectionRid() { + return this.get(RntbdRequestHeader.CollectionRid); + } + + private RntbdToken getCollectionServiceIndex() { + return this.get(RntbdRequestHeader.CollectionServiceIndex); + } + + private RntbdToken getConflictName() { + return this.get(RntbdRequestHeader.ConflictName); + } + + private RntbdToken getConsistencyLevel() { + return this.get(RntbdRequestHeader.ConsistencyLevel); + } + + private RntbdToken getContentSerializationFormat() { + return this.get(RntbdRequestHeader.ContentSerializationFormat); + } + + private RntbdToken getContinuationToken() { + return this.get(RntbdRequestHeader.ContinuationToken); + } + + private RntbdToken getDatabaseName() { + return this.get(RntbdRequestHeader.DatabaseName); + } + + private RntbdToken getDate() { + return this.get(RntbdRequestHeader.Date); + } + + private RntbdToken getDisableRUPerMinuteUsage() { + return this.get(RntbdRequestHeader.DisableRUPerMinuteUsage); + } + + private RntbdToken getDocumentName() { + return this.get(RntbdRequestHeader.DocumentName); + } + + private RntbdToken getEffectivePartitionKey() { + return this.get(RntbdRequestHeader.EffectivePartitionKey); + } + + private RntbdToken getEmitVerboseTracesInQuery() { + return this.get(RntbdRequestHeader.EmitVerboseTracesInQuery); + } + + private RntbdToken getEnableDynamicRidRangeAllocation() { + return this.get(RntbdRequestHeader.EnableDynamicRidRangeAllocation); + } + + private RntbdToken getEnableLogging() { + return this.get(RntbdRequestHeader.EnableLogging); + } + + private RntbdToken getEnableLowPrecisionOrderBy() { + return this.get(RntbdRequestHeader.EnableLowPrecisionOrderBy); + } + + private RntbdToken getEnableScanInQuery() { + return this.get(RntbdRequestHeader.EnableScanInQuery); + } + + private RntbdToken getEndEpk() { + return this.get(RntbdRequestHeader.EndEpk); + } + + private RntbdToken getEndId() { + return this.get(RntbdRequestHeader.EndId); + } + + private RntbdToken getEntityId() { + return this.get(RntbdRequestHeader.EntityId); + } + + private RntbdToken getEnumerationDirection() { + return this.get(RntbdRequestHeader.EnumerationDirection); + } + + private RntbdToken getExcludeSystemProperties() { + return this.get(RntbdRequestHeader.ExcludeSystemProperties); + } + + private RntbdToken getFanoutOperationState() { + return this.get(RntbdRequestHeader.FanoutOperationState); + } + + private RntbdToken getFilterBySchemaRid() { + return this.get(RntbdRequestHeader.FilterBySchemaRid); + } + + private RntbdToken getForceQueryScan() { + return this.get(RntbdRequestHeader.ForceQueryScan); + } + + private RntbdToken getGatewaySignature() { + return this.get(RntbdRequestHeader.GatewaySignature); + } + + private RntbdToken getIfModifiedSince() { + return this.get(RntbdRequestHeader.IfModifiedSince); + } + + private RntbdToken getIndexingDirective() { + return this.get(RntbdRequestHeader.IndexingDirective); + } + + private RntbdToken getIsAutoScaleRequest() { + return this.get(RntbdRequestHeader.IsAutoScaleRequest); + } + + private RntbdToken getIsFanout() { + return this.get(RntbdRequestHeader.IsFanout); + } + + private RntbdToken getIsReadOnlyScript() { + return this.get(RntbdRequestHeader.IsReadOnlyScript); + } + + private RntbdToken getIsUserRequest() { + return this.get(RntbdRequestHeader.IsUserRequest); + } + + private RntbdToken getMatch() { + return this.get(RntbdRequestHeader.Match); + } + + private RntbdToken getMigrateCollectionDirective() { + return this.get(RntbdRequestHeader.MigrateCollectionDirective); + } + + private RntbdToken getPageSize() { + return this.get(RntbdRequestHeader.PageSize); + } + + private RntbdToken getPartitionCount() { + return this.get(RntbdRequestHeader.PartitionCount); + } + + private RntbdToken getPartitionKey() { + return this.get(RntbdRequestHeader.PartitionKey); + } + + private RntbdToken getPartitionKeyRangeId() { + return this.get(RntbdRequestHeader.PartitionKeyRangeId); + } + + private RntbdToken getPartitionKeyRangeName() { + return this.get(RntbdRequestHeader.PartitionKeyRangeName); + } + + private RntbdToken getPartitionResourceFilter() { + return this.get(RntbdRequestHeader.PartitionResourceFilter); + } + + private RntbdToken getPayloadPresent() { + return this.get(RntbdRequestHeader.PayloadPresent); + } + + private RntbdToken getPermissionName() { + return this.get(RntbdRequestHeader.PermissionName); + } + + private RntbdToken getPopulateCollectionThroughputInfo() { + return this.get(RntbdRequestHeader.PopulateCollectionThroughputInfo); + } + + private RntbdToken getPopulatePartitionStatistics() { + return this.get(RntbdRequestHeader.PopulatePartitionStatistics); + } + + private RntbdToken getPopulateQueryMetrics() { + return this.get(RntbdRequestHeader.PopulateQueryMetrics); + } + + private RntbdToken getPopulateQuotaInfo() { + return this.get(RntbdRequestHeader.PopulateQuotaInfo); + } + + private RntbdToken getPostTriggerExclude() { + return this.get(RntbdRequestHeader.PostTriggerExclude); + } + + private RntbdToken getPostTriggerInclude() { + return this.get(RntbdRequestHeader.PostTriggerInclude); + } + + private RntbdToken getPreTriggerExclude() { + return this.get(RntbdRequestHeader.PreTriggerExclude); + } + + private RntbdToken getPreTriggerInclude() { + return this.get(RntbdRequestHeader.PreTriggerInclude); + } + + private RntbdToken getPrimaryMasterKey() { + return this.get(RntbdRequestHeader.PrimaryMasterKey); + } + + private RntbdToken getPrimaryReadonlyKey() { + return this.get(RntbdRequestHeader.PrimaryReadonlyKey); + } + + private RntbdToken getProfileRequest() { + return this.get(RntbdRequestHeader.ProfileRequest); + } + + private RntbdToken getReadFeedKeyType() { + return this.get(RntbdRequestHeader.ReadFeedKeyType); + } + + private RntbdToken getRemainingTimeInMsOnClientRequest() { + return this.get(RntbdRequestHeader.RemainingTimeInMsOnClientRequest); + } + + private RntbdToken getRemoteStorageType() { + return this.get(RntbdRequestHeader.RemoteStorageType); + } + + private RntbdToken getReplicaPath() { + return this.get(RntbdRequestHeader.ReplicaPath); + } + + private RntbdToken getResourceId() { + return this.get(RntbdRequestHeader.ResourceId); + } + + private RntbdToken getResourceSchemaName() { + return this.get(RntbdRequestHeader.ResourceSchemaName); + } + + private RntbdToken getResourceTokenExpiry() { + return this.get(RntbdRequestHeader.ResourceTokenExpiry); + } + + private RntbdToken getResponseContinuationTokenLimitInKb() { + return this.get(RntbdRequestHeader.ResponseContinuationTokenLimitInKb); + } + + private RntbdToken getRestoreMetadataFilter() { + return this.get(RntbdRequestHeader.RestoreMetadaFilter); + } + + private RntbdToken getRestoreParams() { + return this.get(RntbdRequestHeader.RestoreParams); + } + + private RntbdToken getSchemaName() { + return this.get(RntbdRequestHeader.SchemaName); + } + + private RntbdToken getSecondaryMasterKey() { + return this.get(RntbdRequestHeader.SecondaryMasterKey); + } + + private RntbdToken getSecondaryReadonlyKey() { + return this.get(RntbdRequestHeader.SecondaryReadonlyKey); + } + + private RntbdToken getSessionToken() { + return this.get(RntbdRequestHeader.SessionToken); + } + + private RntbdToken getShareThroughput() { + return this.get(RntbdRequestHeader.ShareThroughput); + } + + private RntbdToken getSharedOfferThroughput() { + return this.get(RntbdRequestHeader.SharedOfferThroughput); + } + + private RntbdToken getStartEpk() { + return this.get(RntbdRequestHeader.StartEpk); + } + + private RntbdToken getStartId() { + return this.get(RntbdRequestHeader.StartId); + } + + private RntbdToken getStoredProcedureName() { + return this.get(RntbdRequestHeader.StoredProcedureName); + } + + private RntbdToken getSupportSpatialLegacyCoordinates() { + return this.get(RntbdRequestHeader.SupportSpatialLegacyCoordinates); + } + + private RntbdToken getTargetGlobalCommittedLsn() { + return this.get(RntbdRequestHeader.TargetGlobalCommittedLsn); + } + + private RntbdToken getTargetLsn() { + return this.get(RntbdRequestHeader.TargetLsn); + } + + private RntbdToken getTimeToLiveInSeconds() { + return this.get(RntbdRequestHeader.TimeToLiveInSeconds); + } + + private RntbdToken getTransportRequestID() { + return this.get(RntbdRequestHeader.TransportRequestID); + } + + private RntbdToken getTriggerName() { + return this.get(RntbdRequestHeader.TriggerName); + } + + private RntbdToken getUsePolygonsSmallerThanAHemisphere() { + return this.get(RntbdRequestHeader.UsePolygonsSmallerThanAHemisphere); + } + + private RntbdToken getUserDefinedFunctionName() { + return this.get(RntbdRequestHeader.UserDefinedFunctionName); + } + + private RntbdToken getUserDefinedTypeName() { + return this.get(RntbdRequestHeader.UserDefinedTypeName); + } + + private RntbdToken getUserName() { + return this.get(RntbdRequestHeader.UserName); + } + + private void addAimHeader(final Map headers) { + + final String value = headers.get(HttpHeaders.A_IM); + + if (StringUtils.isNotEmpty(value)) { + this.getAIM().setValue(value); + } + } + + private void addAllowScanOnQuery(final Map headers) { + final String value = headers.get(HttpHeaders.ENABLE_SCAN_IN_QUERY); + if (StringUtils.isNotEmpty(value)) { + this.getEnableScanInQuery().setValue(Boolean.parseBoolean(value)); + } + } + + private void addBinaryIdIfPresent(final Map headers) { + final String value = headers.get(BackendHeaders.BINARY_ID); + if (StringUtils.isNotEmpty(value)) { + this.getBinaryId().setValue(Base64.getDecoder().decode(value)); + } + } + + private void addCanCharge(final Map headers) { + final String value = headers.get(HttpHeaders.CAN_CHARGE); + if (StringUtils.isNotEmpty(value)) { + this.getCanCharge().setValue(Boolean.parseBoolean(value)); + } + } + + private void addCanOfferReplaceComplete(final Map headers) { + final String value = headers.get(HttpHeaders.CAN_OFFER_REPLACE_COMPLETE); + if (StringUtils.isNotEmpty(value)) { + this.getCanOfferReplaceComplete().setValue(Boolean.parseBoolean(value)); + } + } + + private void addCanThrottle(final Map headers) { + final String value = headers.get(HttpHeaders.CAN_THROTTLE); + if (StringUtils.isNotEmpty(value)) { + this.getCanThrottle().setValue(Boolean.parseBoolean(value)); + } + } + + private void addCollectionRemoteStorageSecurityIdentifier(final Map headers) { + final String value = headers.get(HttpHeaders.COLLECTION_REMOTE_STORAGE_SECURITY_IDENTIFIER); + if (StringUtils.isNotEmpty(value)) { + this.getCollectionRemoteStorageSecurityIdentifier().setValue(value); + } + } + + private void addConsistencyLevelHeader(final Map headers) { + + final String value = headers.get(HttpHeaders.CONSISTENCY_LEVEL); + + if (StringUtils.isNotEmpty(value)) { + + final ConsistencyLevel level = EnumUtils.getEnumIgnoreCase(ConsistencyLevel.class, value); + + if (level == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.CONSISTENCY_LEVEL, + value); + throw new IllegalStateException(reason); + } + + switch (level) { + case STRONG: + this.getConsistencyLevel().setValue(RntbdConsistencyLevel.Strong.id()); + break; + case BOUNDED_STALENESS: + this.getConsistencyLevel().setValue(RntbdConsistencyLevel.BoundedStaleness.id()); + break; + case SESSION: + this.getConsistencyLevel().setValue(RntbdConsistencyLevel.Session.id()); + break; + case EVENTUAL: + this.getConsistencyLevel().setValue(RntbdConsistencyLevel.Eventual.id()); + break; + case CONSISTENT_PREFIX: + this.getConsistencyLevel().setValue(RntbdConsistencyLevel.ConsistentPrefix.id()); + break; + default: + assert false; + break; + } + } + } + + private void addContentSerializationFormat(final Map headers) { + + final String value = headers.get(HttpHeaders.CONTENT_SERIALIZATION_FORMAT); + + if (StringUtils.isNotEmpty(value)) { + + final ContentSerializationFormat format = EnumUtils.getEnumIgnoreCase(ContentSerializationFormat.class, value); + + if (format == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.CONTENT_SERIALIZATION_FORMAT, + value); + throw new IllegalStateException(reason); + } + + switch (format) { + case JsonText: + this.getContentSerializationFormat().setValue(RntbdContentSerializationFormat.JsonText.id()); + break; + case CosmosBinary: + this.getContentSerializationFormat().setValue(RntbdContentSerializationFormat.CosmosBinary.id()); + break; + default: + assert false; + } + } + } + + private void addContinuationToken(final RxDocumentServiceRequest request) { + final String value = request.getContinuation(); + if (StringUtils.isNotEmpty(value)) { + this.getContinuationToken().setValue(value); + } + } + + private void addDateHeader(final Map headers) { + + // Since the HTTP date header is overridden by some proxies/http client libraries, we support an additional date + // header and prefer that to the (regular) date header + + String value = headers.get(HttpHeaders.X_DATE); + + if (StringUtils.isEmpty(value)) { + value = headers.get(HttpHeaders.HTTP_DATE); + } + + if (StringUtils.isNotEmpty(value)) { + this.getDate().setValue(value); + } + } + + private void addDisableRUPerMinuteUsage(final Map headers) { + final String value = headers.get(HttpHeaders.DISABLE_RU_PER_MINUTE_USAGE); + if (StringUtils.isNotEmpty(value)) { + this.getDisableRUPerMinuteUsage().setValue(Boolean.parseBoolean(value)); + } + } + + private void addEmitVerboseTracesInQuery(final Map headers) { + final String value = headers.get(HttpHeaders.EMIT_VERBOSE_TRACES_IN_QUERY); + if (StringUtils.isNotEmpty(value)) { + this.getEmitVerboseTracesInQuery().setValue(Boolean.parseBoolean(value)); + } + } + + private void addEnableLogging(final Map headers) { + final String value = headers.get(HttpHeaders.ENABLE_LOGGING); + if (StringUtils.isNotEmpty(value)) { + this.getEnableLogging().setValue(Boolean.parseBoolean(value)); + } + } + + private void addEnableLowPrecisionOrderBy(final Map headers) { + final String value = headers.get(HttpHeaders.ENABLE_LOW_PRECISION_ORDER_BY); + if (StringUtils.isNotEmpty(value)) { + this.getEnableLowPrecisionOrderBy().setValue(Boolean.parseBoolean(value)); + } + } + + private void addEntityId(final Map headers) { + final String value = headers.get(BackendHeaders.ENTITY_ID); + if (StringUtils.isNotEmpty(value)) { + this.getEntityId().setValue(value); + } + } + + private void addEnumerationDirection(final Map headers) { + + final String value = headers.get(HttpHeaders.ENUMERATION_DIRECTION); + + if (StringUtils.isNotEmpty(value)) { + + final EnumerationDirection direction = EnumUtils.getEnumIgnoreCase(EnumerationDirection.class, value); + + if (direction == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.ENUMERATION_DIRECTION, + value); + throw new IllegalStateException(reason); + } + + switch (direction) { + case Forward: + this.getEnumerationDirection().setValue(RntbdEnumerationDirection.Forward.id()); + break; + case Reverse: + this.getEnumerationDirection().setValue(RntbdEnumerationDirection.Reverse.id()); + break; + default: + assert false; + } + } + } + + private void addExcludeSystemProperties(final Map headers) { + final String value = headers.get(BackendHeaders.EXCLUDE_SYSTEM_PROPERTIES); + if (StringUtils.isNotEmpty(value)) { + this.getExcludeSystemProperties().setValue(Boolean.parseBoolean(value)); + } + } + + private void addFanoutOperationStateHeader(final Map headers) { + + final String value = headers.get(BackendHeaders.FANOUT_OPERATION_STATE); + + if (StringUtils.isNotEmpty(value)) { + + final FanoutOperationState format = EnumUtils.getEnumIgnoreCase(FanoutOperationState.class, value); + + if (format == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + BackendHeaders.FANOUT_OPERATION_STATE, + value); + throw new IllegalStateException(reason); + } + + switch (format) { + case Started: + this.getFanoutOperationState().setValue(RntbdFanoutOperationState.Started.id()); + break; + case Completed: + this.getFanoutOperationState().setValue(RntbdFanoutOperationState.Completed.id()); + break; + default: + assert false; + } + } + } + + private void addIfModifiedSinceHeader(final Map headers) { + final String value = headers.get(HttpHeaders.IF_MODIFIED_SINCE); + if (StringUtils.isNotEmpty(value)) { + this.getIfModifiedSince().setValue(value); + } + } + + private void addIndexingDirectiveHeader(final Map headers) { + + final String value = headers.get(HttpHeaders.INDEXING_DIRECTIVE); + + if (StringUtils.isNotEmpty(value)) { + + final IndexingDirective directive = EnumUtils.getEnumIgnoreCase(IndexingDirective.class, value); + + if (directive == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.INDEXING_DIRECTIVE, + value); + throw new IllegalStateException(reason); + } + + switch (directive) { + case DEFAULT: + this.getIndexingDirective().setValue(RntbdIndexingDirective.Default.id()); + break; + case EXCLUDE: + this.getIndexingDirective().setValue(RntbdIndexingDirective.Exclude.id()); + break; + case INCLUDE: + this.getIndexingDirective().setValue(RntbdIndexingDirective.Include.id()); + break; + default: + assert false; + } + } + } + + private void addIsAutoScaleRequest(final Map headers) { + final String value = headers.get(HttpHeaders.IS_AUTO_SCALE_REQUEST); + if (StringUtils.isNotEmpty(value)) { + this.getIsAutoScaleRequest().setValue(Boolean.parseBoolean(value)); + } + } + + private void addIsFanout(final Map headers) { + final String value = headers.get(BackendHeaders.IS_FANOUT_REQUEST); + if (StringUtils.isNotEmpty(value)) { + this.getIsFanout().setValue(Boolean.parseBoolean(value)); + } + } + + private void addIsReadOnlyScript(final Map headers) { + final String value = headers.get(HttpHeaders.IS_READ_ONLY_SCRIPT); + if (StringUtils.isNotEmpty(value)) { + this.getIsReadOnlyScript().setValue(Boolean.parseBoolean(value)); + } + } + + private void addIsUserRequest(final Map headers) { + final String value = headers.get(BackendHeaders.IS_USER_REQUEST); + if (StringUtils.isNotEmpty(value)) { + this.getIsUserRequest().setValue(Boolean.parseBoolean(value)); + } + } + + private void addMatchHeader(final Map headers, final RntbdOperationType operationType) { + + String match = null; + + switch (operationType) { + case Read: + case ReadFeed: + match = headers.get(HttpHeaders.IF_NONE_MATCH); + break; + default: + match = headers.get(HttpHeaders.IF_MATCH); + break; + } + + if (StringUtils.isNotEmpty(match)) { + this.getMatch().setValue(match); + } + } + + private void addMigrateCollectionDirectiveHeader(final Map headers) { + + final String value = headers.get(HttpHeaders.MIGRATE_COLLECTION_DIRECTIVE); + + if (StringUtils.isNotEmpty(value)) { + + final MigrateCollectionDirective directive = EnumUtils.getEnumIgnoreCase(MigrateCollectionDirective.class, value); + + if (directive == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.MIGRATE_COLLECTION_DIRECTIVE, + value); + throw new IllegalStateException(reason); + } + + switch (directive) { + case Freeze: + this.getMigrateCollectionDirective().setValue(RntbdMigrateCollectionDirective.Freeze.id()); + break; + case Thaw: + this.getMigrateCollectionDirective().setValue(RntbdMigrateCollectionDirective.Thaw.id()); + break; + default: + assert false; + break; + } + } + } + + private void addPageSize(final Map headers) { + + final String value = headers.get(HttpHeaders.PAGE_SIZE); + + if (StringUtils.isNotEmpty(value)) { + final long aLong = parseLong(HttpHeaders.PAGE_SIZE, value, -1, 0xFFFFFFFFL); + this.getPageSize().setValue((int)(aLong < 0 ? 0xFFFFFFFFL : aLong)); + } + } + + private void addPopulateCollectionThroughputInfo(final Map headers) { + final String value = headers.get(HttpHeaders.POPULATE_COLLECTION_THROUGHPUT_INFO); + if (StringUtils.isNotEmpty(value)) { + this.getPopulateCollectionThroughputInfo().setValue(Boolean.parseBoolean(value)); + } + } + + private void addPopulatePartitionStatistics(final Map headers) { + final String value = headers.get(HttpHeaders.POPULATE_PARTITION_STATISTICS); + if (StringUtils.isNotEmpty(value)) { + this.getPopulatePartitionStatistics().setValue(Boolean.parseBoolean(value)); + } + } + + private void addPopulateQueryMetrics(final Map headers) { + final String value = headers.get(HttpHeaders.POPULATE_QUERY_METRICS); + if (StringUtils.isNotEmpty(value)) { + this.getPopulateQueryMetrics().setValue(Boolean.parseBoolean(value)); + } + } + + private void addPopulateQuotaInfo(final Map headers) { + final String value = headers.get(HttpHeaders.POPULATE_QUOTA_INFO); + if (StringUtils.isNotEmpty(value)) { + this.getPopulateQuotaInfo().setValue(Boolean.parseBoolean(value)); + } + } + + private void addProfileRequest(final Map headers) { + final String value = headers.get(HttpHeaders.PROFILE_REQUEST); + if (StringUtils.isNotEmpty(value)) { + this.getProfileRequest().setValue(Boolean.parseBoolean(value)); + } + } + + private void addQueryForceScan(final Map headers) { + final String value = headers.get(HttpHeaders.FORCE_QUERY_SCAN); + if (StringUtils.isNotEmpty(value)) { + this.getForceQueryScan().setValue(Boolean.parseBoolean(value)); + } + } + + private void addRemoteStorageType(final Map headers) { + + final String value = headers.get(BackendHeaders.REMOTE_STORAGE_TYPE); + + if (StringUtils.isNotEmpty(value)) { + + final RemoteStorageType type = EnumUtils.getEnumIgnoreCase(RemoteStorageType.class, value); + + if (type == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + BackendHeaders.REMOTE_STORAGE_TYPE, + value); + throw new IllegalStateException(reason); + } + + switch (type) { + case Standard: + this.getRemoteStorageType().setValue(RntbdRemoteStorageType.Standard.id()); + break; + case Premium: + this.getRemoteStorageType().setValue(RntbdRemoteStorageType.Premium.id()); + break; + default: + assert false; + } + } + } + + private void addResourceIdOrPathHeaders(final RxDocumentServiceRequest request) { + + final String value = request.getResourceId(); + + if (StringUtils.isNotEmpty(value)) { + // Name-based can also have ResourceId because gateway might have generated it + this.getResourceId().setValue(ResourceId.parse(request.getResourceType(), value)); + } + + if (request.getIsNameBased()) { + + // Assumption: format is like "dbs/dbName/colls/collName/docs/docName" or "/dbs/dbName/colls/collName", + // not "apps/appName/partitions/partitionKey/replicas/replicaId/dbs/dbName" + + final String address = request.getResourceAddress(); + final String[] fragments = address.split(UrlTrim); + int count = fragments.length; + int index = 0; + + if (count > 0 && fragments[0].isEmpty()) { + ++index; + --count; + } + + if (count >= 2) { + switch (fragments[index]) { + case Paths.DATABASES_PATH_SEGMENT: + this.getDatabaseName().setValue(fragments[index + 1]); + break; + default: + final String reason = String.format(Locale.ROOT, RMResources.InvalidResourceAddress, + value, address); + throw new IllegalStateException(reason); + } + } + + if (count >= 4) { + switch (fragments[index + 2]) { + case Paths.COLLECTIONS_PATH_SEGMENT: + this.getCollectionName().setValue(fragments[index + 3]); + break; + case Paths.USERS_PATH_SEGMENT: + this.getUserName().setValue(fragments[index + 3]); + break; + case Paths.USER_DEFINED_TYPES_PATH_SEGMENT: + this.getUserDefinedTypeName().setValue(fragments[index + 3]); + break; + } + } + + if (count >= 6) { + switch (fragments[index + 4]) { + case Paths.DOCUMENTS_PATH_SEGMENT: + this.getDocumentName().setValue(fragments[index + 5]); + break; + case Paths.STORED_PROCEDURES_PATH_SEGMENT: + this.getStoredProcedureName().setValue(fragments[index + 5]); + break; + case Paths.PERMISSIONS_PATH_SEGMENT: + this.getPermissionName().setValue(fragments[index + 5]); + break; + case Paths.USER_DEFINED_FUNCTIONS_PATH_SEGMENT: + this.getUserDefinedFunctionName().setValue(fragments[index + 5]); + break; + case Paths.TRIGGERS_PATH_SEGMENT: + this.getTriggerName().setValue(fragments[index + 5]); + break; + case Paths.CONFLICTS_PATH_SEGMENT: + this.getConflictName().setValue(fragments[index + 5]); + break; + case Paths.PARTITION_KEY_RANGES_PATH_SEGMENT: + this.getPartitionKeyRangeName().setValue(fragments[index + 5]); + break; + case Paths.SCHEMAS_PATH_SEGMENT: + this.getSchemaName().setValue(fragments[index + 5]); + break; + } + } + + if (count >= 8) { + switch (fragments[index + 6]) { + case Paths.ATTACHMENTS_PATH_SEGMENT: + this.getAttachmentName().setValue(fragments[index + 7]); + break; + } + } + } + } + + private void addResponseContinuationTokenLimitInKb(final Map headers) { + + final String value = headers.get(HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB); + + if (StringUtils.isNotEmpty(value)) { + final long aLong = parseLong(HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB, value, 0, 0xFFFFFFFFL); + this.getResponseContinuationTokenLimitInKb().setValue((int)(aLong < 0 ? 0xFFFFFFFFL : aLong)); + } + } + + private void addShareThroughput(final Map headers) { + final String value = headers.get(BackendHeaders.SHARE_THROUGHPUT); + if (StringUtils.isNotEmpty(value)) { + this.getShareThroughput().setValue(Boolean.parseBoolean(value)); + } + } + + private void addStartAndEndKeys(final Map headers) { + + String value = headers.get(HttpHeaders.READ_FEED_KEY_TYPE); + + if (StringUtils.isNotEmpty(value)) { + + final ReadFeedKeyType type = EnumUtils.getEnumIgnoreCase(ReadFeedKeyType.class, value); + + if (type == null) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, + HttpHeaders.READ_FEED_KEY_TYPE, + value); + throw new IllegalStateException(reason); + } + + switch (type) { + case ResourceId: + this.getReadFeedKeyType().setValue(RntbdReadFeedKeyType.ResourceId.id()); + break; + case EffectivePartitionKey: + this.getReadFeedKeyType().setValue(RntbdReadFeedKeyType.EffectivePartitionKey.id()); + break; + default: + assert false; + } + } + + final Base64.Decoder decoder = Base64.getDecoder(); + + value = headers.get(HttpHeaders.START_ID); + + if (StringUtils.isNotEmpty(value)) { + this.getStartId().setValue(decoder.decode(value)); + } + + value = headers.get(HttpHeaders.END_ID); + + if (StringUtils.isNotEmpty(value)) { + this.getEndId().setValue(decoder.decode(value)); + } + + value = headers.get(HttpHeaders.START_EPK); + + if (StringUtils.isNotEmpty(value)) { + this.getStartEpk().setValue(decoder.decode(value)); + } + + value = headers.get(HttpHeaders.END_EPK); + + if (StringUtils.isNotEmpty(value)) { + this.getEndEpk().setValue(decoder.decode(value)); + } + } + + private void addSupportSpatialLegacyCoordinates(final Map headers) { + final String value = headers.get(HttpHeaders.SUPPORT_SPATIAL_LEGACY_COORDINATES); + if (StringUtils.isNotEmpty(value)) { + this.getSupportSpatialLegacyCoordinates().setValue(Boolean.parseBoolean(value)); + } + } + + private void addUsePolygonsSmallerThanAHemisphere(final Map headers) { + final String value = headers.get(HttpHeaders.USE_POLYGONS_SMALLER_THAN_AHEMISPHERE); + if (StringUtils.isNotEmpty(value)) { + this.getUsePolygonsSmallerThanAHemisphere().setValue(Boolean.parseBoolean(value)); + } + } + + private void fillTokenFromHeader(final Map headers, final Supplier supplier, final String name) { + + final String value = headers.get(name); + + if (StringUtils.isNotEmpty(value)) { + + final RntbdToken token = supplier.get(); + + switch (token.getTokenType()) { + + case SmallString: + case String: + case ULongString: { + + token.setValue(value); + break; + } + case Byte: { + + token.setValue(Boolean.parseBoolean(value)); + break; + } + case Double: { + + token.setValue(parseDouble(name, value)); + break; + } + case Long: { + + final long aLong = parseLong(name, value, Integer.MIN_VALUE, Integer.MAX_VALUE); + token.setValue(aLong); + break; + } + case ULong: { + + final long aLong = parseLong(name, value, 0, 0xFFFFFFFFL); + token.setValue(aLong); + break; + } + case LongLong: { + + final long aLong = parseLong(name, value); + token.setValue(aLong); + break; + } + default: { + assert false : "Recognized header has neither special-case nor default handling to convert " + + "from header String to RNTBD token"; + break; + } + } + } + } + + private static double parseDouble(final String name, final String value) { + + final double aDouble; + + try { + aDouble = Double.parseDouble(value); + } catch (final NumberFormatException error) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, name, value); + throw new IllegalStateException(reason); + } + return aDouble; + } + + private static long parseLong(final String name, final String value) { + final long aLong; + try { + aLong = Long.parseLong(value); + } catch (final NumberFormatException error) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, name, value); + throw new IllegalStateException(reason); + } + return aLong; + } + + private static long parseLong(final String name, final String value, final long min, final long max) { + final long aLong = parseLong(name, value); + if (!(min <= aLong && aLong <= max)) { + final String reason = String.format(Locale.ROOT, RMResources.InvalidRequestHeaderValue, name, aLong); + throw new IllegalStateException(reason); + } + return aLong; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestManager.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestManager.java new file mode 100644 index 0000000000000..5f270c5136925 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestManager.java @@ -0,0 +1,796 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConflictException; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.ForbiddenException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.LockedException; +import com.azure.data.cosmos.MethodNotAllowedException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.PreconditionFailedException; +import com.azure.data.cosmos.RequestEntityTooLargeException; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.RetryWithException; +import com.azure.data.cosmos.ServiceUnavailableException; +import com.azure.data.cosmos.UnauthorizedException; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdResponseHeader; +import com.google.common.base.Strings; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelException; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandler; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelOutboundHandler; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.ChannelPromise; +import io.netty.channel.CoalescingBufferQueue; +import io.netty.channel.EventLoop; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.ssl.SslHandler; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.Timeout; +import io.netty.util.concurrent.EventExecutor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.SocketAddress; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import static com.azure.data.cosmos.internal.HttpConstants.StatusCodes; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdReporter.reportIssue; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdReporter.reportIssueUnless; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +public final class RntbdRequestManager implements ChannelHandler, ChannelInboundHandler, ChannelOutboundHandler { + + // region Fields + + private static final Logger logger = LoggerFactory.getLogger(RntbdRequestManager.class); + + private final CompletableFuture contextFuture = new CompletableFuture<>(); + private final CompletableFuture contextRequestFuture = new CompletableFuture<>(); + private final ConcurrentHashMap pendingRequests; + private final int pendingRequestLimit; + + private boolean closingExceptionally = false; + private CoalescingBufferQueue pendingWrites; + + // endregion + + public RntbdRequestManager(int capacity) { + checkArgument(capacity > 0, "capacity: %s", capacity); + this.pendingRequests = new ConcurrentHashMap<>(capacity); + this.pendingRequestLimit = capacity; + } + + // region ChannelHandler methods + + /** + * Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void handlerAdded(final ChannelHandlerContext context) { + this.traceOperation(context, "handlerAdded"); + } + + /** + * Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events + * anymore. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void handlerRemoved(final ChannelHandlerContext context) { + this.traceOperation(context, "handlerRemoved"); + } + + // endregion + + // region ChannelInboundHandler methods + + /** + * The {@link Channel} of the {@link ChannelHandlerContext} is now active + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void channelActive(final ChannelHandlerContext context) { + this.traceOperation(context, "channelActive"); + context.fireChannelActive(); + } + + /** + * Completes all pending requests exceptionally when a channel reaches the end of its lifetime + *

    + * This method will only be called after the channel is closed. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void channelInactive(final ChannelHandlerContext context) { + this.traceOperation(context, "channelInactive"); + context.fireChannelInactive(); + } + + @Override + public void channelRead(final ChannelHandlerContext context, final Object message) { + + this.traceOperation(context, "channelRead"); + + if (message instanceof RntbdResponse) { + + try { + this.messageReceived(context, (RntbdResponse)message); + } catch (Throwable throwable) { + reportIssue(logger, context, "{} ", message, throwable); + this.exceptionCaught(context, throwable); + } finally { + ReferenceCountUtil.release(message); + } + + } else { + + final IllegalStateException error = new IllegalStateException( + Strings.lenientFormat("expected message of %s, not %s: %s", + RntbdResponse.class, message.getClass(), message + ) + ); + + reportIssue(logger, context, "", error); + this.exceptionCaught(context, error); + } + } + + /** + * Invoked when the last message read by the current read operation has been consumed + *

    + * If {@link ChannelOption#AUTO_READ} is off, no further attempt to read an inbound data from the current + * {@link Channel} will be made until {@link ChannelHandlerContext#read} is called. This leaves time + * for outbound messages to be written. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void channelReadComplete(final ChannelHandlerContext context) { + this.traceOperation(context, "channelReadComplete"); + context.fireChannelReadComplete(); + } + + /** + * Constructs a {@link CoalescingBufferQueue} for buffering encoded requests until we have an {@link RntbdRequest} + *

    + * This method then calls {@link ChannelHandlerContext#fireChannelRegistered()} to forward to the next + * {@link ChannelInboundHandler} in the {@link ChannelPipeline}. + *

    + * Sub-classes may override this method to change behavior. + * + * @param context the {@link ChannelHandlerContext} for which the bind operation is made + */ + @Override + public void channelRegistered(final ChannelHandlerContext context) { + + this.traceOperation(context, "channelRegistered"); + + checkState(this.pendingWrites == null, "pendingWrites: %s", this.pendingWrites); + this.pendingWrites = new CoalescingBufferQueue(context.channel()); + + context.fireChannelRegistered(); + } + + /** + * The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop} + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void channelUnregistered(final ChannelHandlerContext context) { + + this.traceOperation(context, "channelUnregistered"); + + checkState(this.pendingWrites != null, "pendingWrites: null"); + this.completeAllPendingRequestsExceptionally(context, ClosedWithPendingRequestsException.INSTANCE); + this.pendingWrites = null; + + context.fireChannelUnregistered(); + } + + /** + * Gets called once the writable state of a {@link Channel} changed. You can check the state with + * {@link Channel#isWritable()}. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + */ + @Override + public void channelWritabilityChanged(final ChannelHandlerContext context) { + this.traceOperation(context, "channelWritabilityChanged"); + context.fireChannelWritabilityChanged(); + } + + /** + * Processes {@link ChannelHandlerContext#fireExceptionCaught(Throwable)} in the {@link ChannelPipeline} + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + * @param cause Exception caught + */ + @Override + @SuppressWarnings("deprecation") + public void exceptionCaught(final ChannelHandlerContext context, final Throwable cause) { + + // TODO: DANOBLE: replace RntbdRequestManager.exceptionCaught with read/write listeners + // Notes: + // ChannelInboundHandler.exceptionCaught is deprecated and--today, prior to deprecation--only catches read-- + // i.e., inbound--exceptions. + // Replacements: + // * read listener: unclear as there is no obvious replacement + // * write listener: implemented by RntbdTransportClient.DefaultEndpoint.doWrite + // Links: + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/373213 + + this.traceOperation(context, "exceptionCaught", cause); + + if (!this.closingExceptionally) { + + reportIssueUnless(cause != ClosedWithPendingRequestsException.INSTANCE, logger, context, + "expected an exception other than ", ClosedWithPendingRequestsException.INSTANCE); + + this.completeAllPendingRequestsExceptionally(context, cause); + context.pipeline().flush().close(); + } + } + + /** + * Processes inbound events triggered by channel handlers in the {@link RntbdClientChannelHandler} pipeline + *

    + * All but inbound request management events are ignored. + * + * @param context {@link ChannelHandlerContext} to which this {@link RntbdRequestManager} belongs + * @param event An object representing a user event + */ + @Override + public void userEventTriggered(final ChannelHandlerContext context, final Object event) { + + this.traceOperation(context, "userEventTriggered", event); + + try { + if (event instanceof RntbdContext) { + this.contextFuture.complete((RntbdContext)event); + this.removeContextNegotiatorAndFlushPendingWrites(context); + return; + } + if (event instanceof RntbdContextException) { + this.contextFuture.completeExceptionally((RntbdContextException)event); + context.pipeline().flush().close(); + return; + } + context.fireUserEventTriggered(event); + + } catch (Throwable error) { + reportIssue(logger, context, "{}: ", event, error); + this.exceptionCaught(context, error); + } + } + + // endregion + + // region ChannelOutboundHandler methods + + /** + * Called once a bind operation is made. + * + * @param context the {@link ChannelHandlerContext} for which the bind operation is made + * @param localAddress the {@link SocketAddress} to which it should bound + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void bind(final ChannelHandlerContext context, final SocketAddress localAddress, final ChannelPromise promise) { + this.traceOperation(context, "bind", localAddress); + context.bind(localAddress, promise); + } + + /** + * Called once a close operation is made. + * + * @param context the {@link ChannelHandlerContext} for which the close operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void close(final ChannelHandlerContext context, final ChannelPromise promise) { + + this.traceOperation(context, "close"); + + this.completeAllPendingRequestsExceptionally(context, ClosedWithPendingRequestsException.INSTANCE); + final SslHandler sslHandler = context.pipeline().get(SslHandler.class); + + if (sslHandler != null) { + // Netty 4.1.36.Final: SslHandler.closeOutbound must be called before closing the pipeline + // This ensures that all SSL engine and ByteBuf resources are released + // This is something that does not occur in the call to ChannelPipeline.close that follows + sslHandler.closeOutbound(); + } + + context.close(promise); + } + + /** + * Called once a connect operation is made. + * + * @param context the {@link ChannelHandlerContext} for which the connect operation is made + * @param remoteAddress the {@link SocketAddress} to which it should connect + * @param localAddress the {@link SocketAddress} which is used as source on connect + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void connect( + final ChannelHandlerContext context, final SocketAddress remoteAddress, final SocketAddress localAddress, + final ChannelPromise promise + ) { + this.traceOperation(context, "connect", remoteAddress, localAddress); + context.connect(remoteAddress, localAddress, promise); + } + + /** + * Called once a deregister operation is made from the current registered {@link EventLoop}. + * + * @param context the {@link ChannelHandlerContext} for which the close operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void deregister(final ChannelHandlerContext context, final ChannelPromise promise) { + this.traceOperation(context, "deregister"); + context.deregister(promise); + } + + /** + * Called once a disconnect operation is made. + * + * @param context the {@link ChannelHandlerContext} for which the disconnect operation is made + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void disconnect(final ChannelHandlerContext context, final ChannelPromise promise) { + this.traceOperation(context, "disconnect"); + context.disconnect(promise); + } + + /** + * Called once a flush operation is made + *

    + * The flush operation will try to flush out all previous written messages that are pending. + * + * @param context the {@link ChannelHandlerContext} for which the flush operation is made + */ + @Override + public void flush(final ChannelHandlerContext context) { + this.traceOperation(context, "flush"); + context.flush(); + } + + /** + * Intercepts {@link ChannelHandlerContext#read} + * + * @param context the {@link ChannelHandlerContext} for which the read operation is made + */ + @Override + public void read(final ChannelHandlerContext context) { + this.traceOperation(context, "read"); + context.read(); + } + + /** + * Called once a write operation is made + *

    + * The write operation will send messages through the {@link ChannelPipeline} which are then ready to be flushed + * to the actual {@link Channel}. This will occur when {@link Channel#flush} is called. + * + * @param context the {@link ChannelHandlerContext} for which the write operation is made + * @param message the message to write + * @param promise the {@link ChannelPromise} to notify once the operation completes + */ + @Override + public void write(final ChannelHandlerContext context, final Object message, final ChannelPromise promise) { + + // TODO: DANOBLE: Ensure that all write errors are reported with a root cause of type EncoderException + + this.traceOperation(context, "write", message); + + if (message instanceof RntbdRequestRecord) { + + context.write(this.addPendingRequestRecord(context, (RntbdRequestRecord)message), promise); + + } else { + + final IllegalStateException error = new IllegalStateException( + Strings.lenientFormat("expected message of %s, not %s: %s", + RntbdRequestRecord.class, message.getClass(), message + ) + ); + + reportIssue(logger, context, "", error); + this.exceptionCaught(context, error); + } + } + + // endregion + + // region Private and package private methods + + CompletableFuture getRntbdContextRequestFuture() { + return this.contextRequestFuture; + } + + boolean hasRntbdContext() { + return this.contextFuture.getNow(null) != null; + } + + boolean isServiceable(final int demand) { + final int limit = this.hasRntbdContext() ? this.pendingRequestLimit : Math.min(this.pendingRequestLimit, demand); + return this.pendingRequests.size() < limit; + } + + void pendWrite(final ByteBuf out, final ChannelPromise promise) { + this.pendingWrites.add(out, promise); + } + + private RntbdRequestArgs addPendingRequestRecord(final ChannelHandlerContext context, final RntbdRequestRecord record) { + + return this.pendingRequests.compute(record.getTransportRequestId(), (id, current) -> { + + reportIssueUnless(current == null, logger, context, "id: {}, current: {}, request: {}", id, current, record); + + final Timeout pendingRequestTimeout = record.newTimeout(timeout -> { + + // We don't wish to complete on the timeout thread, but rather on a thread doled out by our executor + + EventExecutor executor = context.executor(); + + if (executor.inEventLoop()) { + record.expire(); + } else { + executor.next().execute(record::expire); + } + }); + + record.whenComplete((response, error) -> { + this.pendingRequests.remove(id); + pendingRequestTimeout.cancel(); + }); + + return record; + + }).getArgs(); + } + + private Optional getRntbdContext() { + return Optional.of(this.contextFuture.getNow(null)); + } + + private void completeAllPendingRequestsExceptionally(final ChannelHandlerContext context, final Throwable throwable) { + + if (this.closingExceptionally) { + + reportIssueUnless(throwable == ClosedWithPendingRequestsException.INSTANCE, logger, context, + "throwable: ", throwable); + + reportIssueUnless(this.pendingRequests.isEmpty() && this.pendingWrites.isEmpty(), logger, context, + "pendingRequests: {}, pendingWrites: {}", this.pendingRequests.isEmpty(), + this.pendingWrites.isEmpty()); + + return; + } + + this.closingExceptionally = true; + + if (!this.pendingWrites.isEmpty()) { + this.pendingWrites.releaseAndFailAll(context, ClosedWithPendingRequestsException.INSTANCE); + } + + if (!this.pendingRequests.isEmpty()) { + + if (!this.contextRequestFuture.isDone()) { + this.contextRequestFuture.completeExceptionally(throwable); + } + + if (!this.contextFuture.isDone()) { + this.contextFuture.completeExceptionally(throwable); + } + + final int count = this.pendingRequests.size(); + Exception contextRequestException = null; + String phrase = null; + + if (this.contextRequestFuture.isCompletedExceptionally()) { + + try { + this.contextRequestFuture.get(); + } catch (final CancellationException error) { + phrase = "RNTBD context request write cancelled"; + contextRequestException = error; + } catch (final Exception error) { + phrase = "RNTBD context request write failed"; + contextRequestException = error; + } catch (final Throwable error) { + phrase = "RNTBD context request write failed"; + contextRequestException = new ChannelException(error); + } + + } else if (this.contextFuture.isCompletedExceptionally()) { + + try { + this.contextFuture.get(); + } catch (final CancellationException error) { + phrase = "RNTBD context request read cancelled"; + contextRequestException = error; + } catch (final Exception error) { + phrase = "RNTBD context request read failed"; + contextRequestException = error; + } catch (final Throwable error) { + phrase = "RNTBD context request read failed"; + contextRequestException = new ChannelException(error); + } + + } else { + + phrase = "closed exceptionally"; + } + + final String message = Strings.lenientFormat("%s %s with %s pending requests", context, phrase, count); + final Exception cause; + + if (throwable == ClosedWithPendingRequestsException.INSTANCE) { + + cause = contextRequestException == null + ? ClosedWithPendingRequestsException.INSTANCE + : contextRequestException; + + } else { + + cause = throwable instanceof Exception + ? (Exception)throwable + : new ChannelException(throwable); + } + + for (RntbdRequestRecord record : this.pendingRequests.values()) { + + final Map requestHeaders = record.getArgs().getServiceRequest().getHeaders(); + final String requestUri = record.getArgs().getPhysicalAddress().toString(); + + final GoneException error = new GoneException(message, cause, (Map)null, requestUri); + BridgeInternal.setRequestHeaders(error, requestHeaders); + + record.completeExceptionally(error); + } + } + } + + /** + * This method is called for each incoming message of type {@link StoreResponse} to complete a request + * + * @param context {@link ChannelHandlerContext} encode to which this {@link RntbdRequestManager} belongs + * @param response the message encode handle + */ + private void messageReceived(final ChannelHandlerContext context, final RntbdResponse response) { + + final Long transportRequestId = response.getTransportRequestId(); + + if (transportRequestId == null) { + reportIssue(logger, context, "{} ignored because there is no transport request identifier, response"); + return; + } + + final RntbdRequestRecord pendingRequest = this.pendingRequests.get(transportRequestId); + + if (pendingRequest == null) { + reportIssue(logger, context, "{} ignored because there is no matching pending request", response); + return; + } + + final HttpResponseStatus status = response.getStatus(); + final UUID activityId = response.getActivityId(); + + if (HttpResponseStatus.OK.code() <= status.code() && status.code() < HttpResponseStatus.MULTIPLE_CHOICES.code()) { + + final StoreResponse storeResponse = response.toStoreResponse(this.contextFuture.getNow(null)); + pendingRequest.complete(storeResponse); + + } else { + + // Map response to a CosmosClientException + + final CosmosClientException cause; + + // ..Fetch required header values + + final long lsn = response.getHeader(RntbdResponseHeader.LSN); + final String partitionKeyRangeId = response.getHeader(RntbdResponseHeader.PartitionKeyRangeId); + + // ..Create Error instance + + final CosmosError cosmosError = response.hasPayload() ? + BridgeInternal.createCosmosError(RntbdObjectMapper.readTree(response)) : + new CosmosError(Integer.toString(status.code()), status.reasonPhrase(), status.codeClass().name()); + + // ..Map RNTBD response headers to HTTP response headers + + final Map responseHeaders = response.getHeaders().asMap( + this.getRntbdContext().orElseThrow(IllegalStateException::new), activityId + ); + + // ..Create CosmosClientException based on status and sub-status codes + + switch (status.code()) { + + case StatusCodes.BADREQUEST: + cause = new BadRequestException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.CONFLICT: + cause = new ConflictException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.FORBIDDEN: + cause = new ForbiddenException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.GONE: + + final int subStatusCode = Math.toIntExact(response.getHeader(RntbdResponseHeader.SubStatus)); + + switch (subStatusCode) { + case SubStatusCodes.COMPLETING_SPLIT: + cause = new PartitionKeyRangeIsSplittingException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + case SubStatusCodes.COMPLETING_PARTITION_MIGRATION: + cause = new PartitionIsMigratingException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + case SubStatusCodes.NAME_CACHE_IS_STALE: + cause = new InvalidPartitionException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + case SubStatusCodes.PARTITION_KEY_RANGE_GONE: + cause = new PartitionKeyRangeGoneException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + default: + cause = new GoneException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + } + break; + + case StatusCodes.INTERNAL_SERVER_ERROR: + cause = new InternalServerErrorException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.LOCKED: + cause = new LockedException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.METHOD_NOT_ALLOWED: + cause = new MethodNotAllowedException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.NOTFOUND: + cause = new NotFoundException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.PRECONDITION_FAILED: + cause = new PreconditionFailedException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.REQUEST_ENTITY_TOO_LARGE: + cause = new RequestEntityTooLargeException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.REQUEST_TIMEOUT: + cause = new RequestTimeoutException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.RETRY_WITH: + cause = new RetryWithException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.SERVICE_UNAVAILABLE: + cause = new ServiceUnavailableException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.TOO_MANY_REQUESTS: + cause = new RequestRateTooLargeException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + case StatusCodes.UNAUTHORIZED: + cause = new UnauthorizedException(cosmosError, lsn, partitionKeyRangeId, responseHeaders); + break; + + default: + cause = BridgeInternal.createCosmosClientException(status.code(), cosmosError, responseHeaders); + break; + } + + pendingRequest.completeExceptionally(cause); + } + } + + private void removeContextNegotiatorAndFlushPendingWrites(final ChannelHandlerContext context) { + + final RntbdContextNegotiator negotiator = context.pipeline().get(RntbdContextNegotiator.class); + negotiator.removeInboundHandler(); + negotiator.removeOutboundHandler(); + + if (!this.pendingWrites.isEmpty()) { + this.pendingWrites.writeAndRemoveAll(context); + } + } + + private void traceOperation(final ChannelHandlerContext context, final String operationName, final Object... args) { + logger.trace("{}\n{}\n{}", operationName, context, args); + } + + // endregion + + // region Types + + private static class ClosedWithPendingRequestsException extends RuntimeException { + + static ClosedWithPendingRequestsException INSTANCE = new ClosedWithPendingRequestsException(); + + // TODO: DANOBLE: Consider revising strategy for closing an RntbdTransportClient with pending requests + // One possibility: + // A channel associated with an RntbdTransportClient will not be closed immediately, if there are any pending + // requests on it. Instead it will be scheduled to close after the request timeout interval (default: 60s) has + // elapsed. + // Algorithm: + // When the RntbdTransportClient is closed, it closes each of its RntbdServiceEndpoint instances. In turn each + // RntbdServiceEndpoint closes its RntbdClientChannelPool. The RntbdClientChannelPool.close method should + // schedule closure of any channel with pending requests for later; when the request timeout interval has + // elapsed or--ideally--when all pending requests have completed. + // Links: + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/388987 + + private ClosedWithPendingRequestsException() { + super(null, null, /* enableSuppression */ false, /* writableStackTrace */ false); + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestRecord.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestRecord.java new file mode 100644 index 0000000000000..405a9673019ab --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestRecord.java @@ -0,0 +1,94 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; + +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class RntbdRequestRecord extends CompletableFuture { + + private static final String simpleClassName = RntbdRequestRecord.class.getSimpleName(); + + private final RntbdRequestArgs args; + private final RntbdRequestTimer timer; + + public RntbdRequestRecord(final RntbdRequestArgs args, final RntbdRequestTimer timer) { + + checkNotNull(args, "args"); + checkNotNull(timer, "timer"); + + this.args = args; + this.timer = timer; + } + + public UUID getActivityId() { + return this.args.getActivityId(); + } + + public RntbdRequestArgs getArgs() { + return this.args; + } + + public long getBirthTime() { + return this.args.getBirthTime(); + } + + public Duration getLifetime() { + return this.args.getLifetime(); + } + + public long getTransportRequestId() { + return this.args.getTransportRequestId(); + } + + public boolean expire() { + + final long timeoutInterval = this.timer.getRequestTimeout(TimeUnit.MILLISECONDS); + final String message = String.format("Request timeout interval (%,d ms) elapsed", timeoutInterval); + final RequestTimeoutException error = new RequestTimeoutException(message, this.args.getPhysicalAddress()); + + BridgeInternal.setRequestHeaders(error, this.args.getServiceRequest().getHeaders()); + + return this.completeExceptionally(error); + } + + public Timeout newTimeout(final TimerTask task) { + return this.timer.newTimeout(task); + } + + @Override + public String toString() { + return simpleClassName + '(' + RntbdObjectMapper.toJson(this.args) + ')'; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestTimer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestTimer.java new file mode 100644 index 0000000000000..54d6ae366dd1e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdRequestTimer.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; + +import java.util.concurrent.TimeUnit; + +public final class RntbdRequestTimer implements AutoCloseable { + + private static final long FIVE_MILLISECONDS = 5000000L; + private final long requestTimeout; + private final Timer timer; + + public RntbdRequestTimer(final long requestTimeout) { + + // Inspection of the HashWheelTimer code indicates that our choice of a 5 millisecond timer resolution ensures + // a request will timeout within 10 milliseconds of the specified requestTimeout interval. This is because + // cancellation of a timeout takes two timer resolution units to complete. + + this.timer = new HashedWheelTimer(FIVE_MILLISECONDS, TimeUnit.NANOSECONDS); + this.requestTimeout = requestTimeout; + } + + public long getRequestTimeout(TimeUnit unit) { + return unit.convert(requestTimeout, TimeUnit.NANOSECONDS); + } + + @Override + public void close() throws RuntimeException { + this.timer.stop(); + } + + public Timeout newTimeout(final TimerTask task) { + return this.timer.newTimeout(task, this.requestTimeout, TimeUnit.NANOSECONDS); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponse.java new file mode 100644 index 0000000000000..fcb19bb4647da --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponse.java @@ -0,0 +1,287 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.EmptyByteBuf; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.util.ReferenceCounted; +import io.netty.util.ResourceLeakDetector; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdResponseHeader; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static java.lang.Math.min; + +@JsonPropertyOrder({ "frame", "headers", "content" }) +public final class RntbdResponse implements ReferenceCounted { + + // region Fields + + private static final String simpleClassName = RntbdResponse.class.getSimpleName(); + + @JsonProperty + @JsonSerialize(using = PayloadSerializer.class) + private final ByteBuf content; + + @JsonProperty + private final RntbdResponseStatus frame; + + @JsonProperty + private final RntbdResponseHeaders headers; + + private AtomicInteger referenceCount = new AtomicInteger(); + + // endregion + + public RntbdResponse(final UUID activityId, final int statusCode, final Map map, final ByteBuf content) { + + this.headers = RntbdResponseHeaders.fromMap(map, content.readableBytes() > 0); + this.content = content.retain(); + + final HttpResponseStatus status = HttpResponseStatus.valueOf(statusCode); + final int length = RntbdResponseStatus.LENGTH + this.headers.computeLength(); + + this.frame = new RntbdResponseStatus(length, status, activityId); + } + + private RntbdResponse(final RntbdResponseStatus frame, final RntbdResponseHeaders headers, final ByteBuf content) { + + this.frame = frame; + this.headers = headers; + this.content = content.retain(); + } + + public UUID getActivityId() { + return this.frame.getActivityId(); + } + + @JsonIgnore + public ByteBuf getContent() { + return this.content; + } + + @JsonIgnore + public RntbdResponseHeaders getHeaders() { + return this.headers; + } + + @JsonIgnore + public HttpResponseStatus getStatus() { + return this.frame.getStatus(); + } + + @JsonIgnore + public Long getTransportRequestId() { + return this.getHeader(RntbdResponseHeader.TransportRequestID); + } + + static RntbdResponse decode(final ByteBuf in) { + + in.markReaderIndex(); + + final RntbdResponseStatus frame = RntbdResponseStatus.decode(in); + final RntbdResponseHeaders headers = RntbdResponseHeaders.decode(in.readSlice(frame.getHeadersLength())); + + final boolean hasPayload = headers.isPayloadPresent(); + final ByteBuf content; + + if (hasPayload) { + + if (!RntbdFramer.canDecodePayload(in)) { + in.resetReaderIndex(); + return null; + } + + content = in.readSlice(in.readIntLE()); + + } else { + + content = new EmptyByteBuf(in.alloc()); + } + + return new RntbdResponse(frame, headers, content); + } + + public void encode(final ByteBuf out) { + + final int start = out.writerIndex(); + + this.frame.encode(out); + this.headers.encode(out); + + final int length = out.writerIndex() - start; + checkState(length == this.frame.getLength()); + + if (this.hasPayload()) { + out.writeIntLE(this.content.readableBytes()); + out.writeBytes(this.content); + } else if (this.content.readableBytes() > 0) { + throw new IllegalStateException(); + } + } + + @JsonIgnore + @SuppressWarnings("unchecked") + public T getHeader(final RntbdResponseHeader header) { + return (T)this.headers.get(header).getValue(); + } + + public boolean hasPayload() { + return this.headers.isPayloadPresent(); + } + + /** + * Returns the reference count of this object. If {@code 0}, it means this object has been deallocated. + */ + @Override + public int refCnt() { + return this.referenceCount.get(); + } + + /** + * Decreases the reference count by {@code 1} and deallocate this object if the reference count reaches {@code 0} + * + * @return {@code true} if and only if the reference count became {@code 0} and this object is de-allocated + */ + @Override + public boolean release() { + return this.release(1); + } + + /** + * Decreases the reference count by {@code decrement} and de-allocates this object if the reference count reaches {@code 0} + * + * @param decrement amount of the decrease + * @return {@code true} if and only if the reference count became {@code 0} and this object has been de-allocated + */ + @Override + public boolean release(final int decrement) { + + return this.referenceCount.getAndAccumulate(decrement, (value, n) -> { + value = value - min(value, n); + if (value == 0) { + assert this.headers != null && this.content != null; + this.headers.releaseBuffers(); + this.content.release(); + } + return value; + }) == 0; + } + + /** + * Increases the reference count by {@code 1}. + */ + @Override + public ReferenceCounted retain() { + this.referenceCount.incrementAndGet(); + return this; + } + + /** + * Increases the reference count by the specified {@code increment}. + * + * @param increment amount of the increase + */ + @Override + public ReferenceCounted retain(final int increment) { + this.referenceCount.addAndGet(increment); + return this; + } + + StoreResponse toStoreResponse(final RntbdContext context) { + + checkNotNull(context, "context"); + final int length = this.content.readableBytes(); + + return new StoreResponse( + this.getStatus().code(), + this.headers.asList(context, this.getActivityId()), + length == 0 ? null : this.content.readCharSequence(length, StandardCharsets.UTF_8).toString() + ); + } + + @Override + public String toString() { + return simpleClassName + '(' + RntbdObjectMapper.toJson(this) + ')'; + } + + /** + * Records the current access location of this object for debugging purposes + *

    + * If this object is determined to be leaked, the information recorded by this operation will be provided to you + * via {@link ResourceLeakDetector}. This method is a shortcut to {@link #touch(Object) touch(null)}. + */ + @Override + public ReferenceCounted touch() { + return this; + } + + /** + * Records the current access location of this object with additional arbitrary information for debugging purposes + *

    + * If this object is determined to be leaked, the information recorded by this operation will be + * provided to you via {@link ResourceLeakDetector}. + * + * @param hint information useful for debugging (unused) + */ + @Override + public ReferenceCounted touch(final Object hint) { + return this; + } + + private static class PayloadSerializer extends StdSerializer { + + public PayloadSerializer() { + super(ByteBuf.class, true); + } + + @Override + public void serialize(final ByteBuf value, final JsonGenerator generator, final SerializerProvider provider) throws IOException { + + final int length = value.readableBytes(); + + generator.writeStartObject(); + generator.writeObjectField("length", length); + generator.writeObjectField("content", ByteBufUtil.hexDump(value, 0, length)); + generator.writeEndObject(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseDecoder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseDecoder.java new file mode 100644 index 0000000000000..5c26cdfe0d490 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseDecoder.java @@ -0,0 +1,62 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public final class RntbdResponseDecoder extends ByteToMessageDecoder { + + private static final Logger Logger = LoggerFactory.getLogger(RntbdResponseDecoder.class); + + /** + * Deserialize from an input {@link ByteBuf} to an {@link RntbdResponse} instance + *

    + * This method is called till it reads no bytes from the {@link ByteBuf} or there is no more data to be readTree. + * + * @param context the {@link ChannelHandlerContext} to which this {@link RntbdResponseDecoder} belongs + * @param in the {@link ByteBuf} to which data to be decoded is readTree + * @param out the {@link List} to which decoded messages are added + */ + @Override + protected void decode(final ChannelHandlerContext context, final ByteBuf in, final List out) { + + if (RntbdFramer.canDecodeHead(in)) { + + final RntbdResponse response = RntbdResponse.decode(in); + + if (response != null) { + Logger.debug("{} DECODE COMPLETE: {}", context.channel(), response); + in.discardReadBytes(); + out.add(response.retain()); + } + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseHeaders.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseHeaders.java new file mode 100644 index 0000000000000..de97775a2a527 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseHeaders.java @@ -0,0 +1,535 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.fasterxml.jackson.annotation.JsonFilter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.CorruptedFrameException; + +import java.math.BigDecimal; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.function.Function; + +import static com.azure.data.cosmos.internal.HttpConstants.HttpHeaders; +import static com.azure.data.cosmos.internal.directconnectivity.WFConstants.BackendHeaders; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdIndexingDirective; +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdResponseHeader; + +@JsonFilter("RntbdToken") +class RntbdResponseHeaders extends RntbdTokenStream { + + // region Fields + + @JsonProperty + private final RntbdToken LSN; + @JsonProperty + private final RntbdToken collectionLazyIndexProgress; + @JsonProperty + private final RntbdToken collectionPartitionIndex; + @JsonProperty + private final RntbdToken collectionSecurityIdentifier; + @JsonProperty + private final RntbdToken collectionServiceIndex; + @JsonProperty + private final RntbdToken collectionUpdateProgress; + @JsonProperty + private final RntbdToken continuationToken; + @JsonProperty + private final RntbdToken currentReplicaSetSize; + @JsonProperty + private final RntbdToken currentWriteQuorum; + @JsonProperty + private final RntbdToken databaseAccountId; + @JsonProperty + private final RntbdToken disableRntbdChannel; + @JsonProperty + private final RntbdToken eTag; + @JsonProperty + private final RntbdToken globalCommittedLSN; + @JsonProperty + private final RntbdToken hasTentativeWrites; + @JsonProperty + private final RntbdToken indexTermsGenerated; + @JsonProperty + private final RntbdToken indexingDirective; + @JsonProperty + private final RntbdToken isRUPerMinuteUsed; + @JsonProperty + private final RntbdToken itemCount; + @JsonProperty + private final RntbdToken itemLSN; + @JsonProperty + private final RntbdToken itemLocalLSN; + @JsonProperty + private final RntbdToken lastStateChangeDateTime; + @JsonProperty + private final RntbdToken localLSN; + @JsonProperty + private final RntbdToken logResults; + @JsonProperty + private final RntbdToken numberOfReadRegions; + @JsonProperty + private final RntbdToken offerReplacePending; + @JsonProperty + private final RntbdToken ownerFullName; + @JsonProperty + private final RntbdToken ownerId; + @JsonProperty + private final RntbdToken partitionKeyRangeId; + @JsonProperty + private final RntbdToken payloadPresent; + @JsonProperty + private final RntbdToken queriesPerformed; + @JsonProperty + private final RntbdToken queryMetrics; + @JsonProperty + private final RntbdToken quorumAckedLSN; + @JsonProperty + private final RntbdToken quorumAckedLocalLSN; + @JsonProperty + private final RntbdToken readsPerformed; + @JsonProperty + private final RntbdToken requestCharge; + @JsonProperty + private final RntbdToken requestValidationFailure; + @JsonProperty + private final RntbdToken restoreState; + @JsonProperty + private final RntbdToken retryAfterMilliseconds; + @JsonProperty + private final RntbdToken schemaVersion; + @JsonProperty + private final RntbdToken scriptsExecuted; + @JsonProperty + private final RntbdToken serverDateTimeUtc; + @JsonProperty + private final RntbdToken sessionToken; + @JsonProperty + private final RntbdToken shareThroughput; + @JsonProperty + private final RntbdToken storageMaxResoureQuota; + @JsonProperty + private final RntbdToken storageResourceQuotaUsage; + @JsonProperty + private final RntbdToken subStatus; + @JsonProperty + private final RntbdToken transportRequestID; + @JsonProperty + private final RntbdToken writesPerformed; + @JsonProperty + private final RntbdToken xpRole; + + // endregion + + private RntbdResponseHeaders() { + + super(RntbdResponseHeader.set, RntbdResponseHeader.map); + + this.LSN = this.get(RntbdResponseHeader.LSN); + this.collectionLazyIndexProgress = this.get(RntbdResponseHeader.CollectionLazyIndexProgress); + this.collectionPartitionIndex = this.get(RntbdResponseHeader.CollectionPartitionIndex); + this.collectionSecurityIdentifier = this.get(RntbdResponseHeader.CollectionSecurityIdentifier); + this.collectionServiceIndex = this.get(RntbdResponseHeader.CollectionServiceIndex); + this.collectionUpdateProgress = this.get(RntbdResponseHeader.CollectionUpdateProgress); + this.continuationToken = this.get(RntbdResponseHeader.ContinuationToken); + this.currentReplicaSetSize = this.get(RntbdResponseHeader.CurrentReplicaSetSize); + this.currentWriteQuorum = this.get(RntbdResponseHeader.CurrentWriteQuorum); + this.databaseAccountId = this.get(RntbdResponseHeader.DatabaseAccountId); + this.disableRntbdChannel = this.get(RntbdResponseHeader.DisableRntbdChannel); + this.eTag = this.get(RntbdResponseHeader.ETag); + this.globalCommittedLSN = this.get(RntbdResponseHeader.GlobalCommittedLSN); + this.hasTentativeWrites = this.get(RntbdResponseHeader.HasTentativeWrites); + this.indexTermsGenerated = this.get(RntbdResponseHeader.IndexTermsGenerated); + this.indexingDirective = this.get(RntbdResponseHeader.IndexingDirective); + this.isRUPerMinuteUsed = this.get(RntbdResponseHeader.IsRUPerMinuteUsed); + this.itemCount = this.get(RntbdResponseHeader.ItemCount); + this.itemLSN = this.get(RntbdResponseHeader.ItemLSN); + this.itemLocalLSN = this.get(RntbdResponseHeader.ItemLocalLSN); + this.lastStateChangeDateTime = this.get(RntbdResponseHeader.LastStateChangeDateTime); + this.localLSN = this.get(RntbdResponseHeader.LocalLSN); + this.logResults = this.get(RntbdResponseHeader.LogResults); + this.numberOfReadRegions = this.get(RntbdResponseHeader.NumberOfReadRegions); + this.offerReplacePending = this.get(RntbdResponseHeader.OfferReplacePending); + this.ownerFullName = this.get(RntbdResponseHeader.OwnerFullName); + this.ownerId = this.get(RntbdResponseHeader.OwnerId); + this.partitionKeyRangeId = this.get(RntbdResponseHeader.PartitionKeyRangeId); + this.payloadPresent = this.get(RntbdResponseHeader.PayloadPresent); + this.queriesPerformed = this.get(RntbdResponseHeader.QueriesPerformed); + this.queryMetrics = this.get(RntbdResponseHeader.QueryMetrics); + this.quorumAckedLSN = this.get(RntbdResponseHeader.QuorumAckedLSN); + this.quorumAckedLocalLSN = this.get(RntbdResponseHeader.QuorumAckedLocalLSN); + this.readsPerformed = this.get(RntbdResponseHeader.ReadsPerformed); + this.requestCharge = this.get(RntbdResponseHeader.RequestCharge); + this.requestValidationFailure = this.get(RntbdResponseHeader.RequestValidationFailure); + this.restoreState = this.get(RntbdResponseHeader.RestoreState); + this.retryAfterMilliseconds = this.get(RntbdResponseHeader.RetryAfterMilliseconds); + this.schemaVersion = this.get(RntbdResponseHeader.SchemaVersion); + this.scriptsExecuted = this.get(RntbdResponseHeader.ScriptsExecuted); + this.serverDateTimeUtc = this.get(RntbdResponseHeader.ServerDateTimeUtc); + this.sessionToken = this.get(RntbdResponseHeader.SessionToken); + this.shareThroughput = this.get(RntbdResponseHeader.ShareThroughput); + this.storageMaxResoureQuota = this.get(RntbdResponseHeader.StorageMaxResoureQuota); + this.storageResourceQuotaUsage = this.get(RntbdResponseHeader.StorageResourceQuotaUsage); + this.subStatus = this.get(RntbdResponseHeader.SubStatus); + this.transportRequestID = this.get(RntbdResponseHeader.TransportRequestID); + this.writesPerformed = this.get(RntbdResponseHeader.WritesPerformed); + this.xpRole = this.get(RntbdResponseHeader.XPRole); + } + + boolean isPayloadPresent() { + return this.payloadPresent.isPresent() && this.payloadPresent.getValue(Byte.class) != 0x00; + } + + List> asList(final RntbdContext context, final UUID activityId) { + + final ImmutableList.Builder> builder = ImmutableList.builderWithExpectedSize(this.computeCount() + 2); + builder.add(new Entry(HttpHeaders.SERVER_VERSION, context.getServerVersion())); + builder.add(new Entry(HttpHeaders.ACTIVITY_ID, activityId.toString())); + + this.collectEntries((token, toEntry) -> { + if (token.isPresent()) { + builder.add(toEntry.apply(token)); + } + }); + + return builder.build(); + } + + public Map asMap(final RntbdContext context, final UUID activityId) { + + final ImmutableMap.Builder builder = ImmutableMap.builderWithExpectedSize(this.computeCount() + 2); + builder.put(new Entry(HttpHeaders.SERVER_VERSION, context.getServerVersion())); + builder.put(new Entry(HttpHeaders.ACTIVITY_ID, activityId.toString())); + + this.collectEntries((token, toEntry) -> { + if (token.isPresent()) { + builder.put(toEntry.apply(token)); + } + }); + + return builder.build(); + } + + static RntbdResponseHeaders decode(final ByteBuf in) { + final RntbdResponseHeaders headers = new RntbdResponseHeaders(); + RntbdTokenStream.decode(in, headers); + return headers; + } + + public static RntbdResponseHeaders fromMap(final Map map, final boolean payloadPresent) { + + final RntbdResponseHeaders headers = new RntbdResponseHeaders(); + headers.payloadPresent.setValue(payloadPresent); + headers.setValues(map); + + return headers; + } + + public void setValues(final Map headers) { + + this.mapValue(this.LSN, BackendHeaders.LSN, Long::parseLong, headers); + this.mapValue(this.collectionLazyIndexProgress, HttpHeaders.COLLECTION_LAZY_INDEXING_PROGRESS, Integer::parseInt, headers); + this.mapValue(this.collectionLazyIndexProgress, BackendHeaders.COLLECTION_PARTITION_INDEX, Integer::parseInt, headers); + this.mapValue(this.collectionSecurityIdentifier, BackendHeaders.COLLECTION_SECURITY_IDENTIFIER, String::toString, headers); + this.mapValue(this.collectionServiceIndex, BackendHeaders.COLLECTION_SERVICE_INDEX, Integer::parseInt, headers); + this.mapValue(this.collectionUpdateProgress, HttpHeaders.COLLECTION_INDEX_TRANSFORMATION_PROGRESS, Integer::parseInt, headers); + this.mapValue(this.continuationToken, HttpHeaders.CONTINUATION, String::toString, headers); + this.mapValue(this.currentReplicaSetSize, BackendHeaders.CURRENT_REPLICA_SET_SIZE, Integer::parseInt, headers); + this.mapValue(this.currentWriteQuorum, BackendHeaders.CURRENT_WRITE_QUORUM, Integer::parseInt, headers); + this.mapValue(this.databaseAccountId, BackendHeaders.DATABASE_ACCOUNT_ID, String::toString, headers); + this.mapValue(this.disableRntbdChannel, HttpHeaders.DISABLE_RNTBD_CHANNEL, Boolean::parseBoolean, headers); + this.mapValue(this.eTag, HttpHeaders.E_TAG, String::toString, headers); + this.mapValue(this.globalCommittedLSN, BackendHeaders.GLOBAL_COMMITTED_LSN, Long::parseLong, headers); + this.mapValue(this.hasTentativeWrites, BackendHeaders.HAS_TENTATIVE_WRITES, Boolean::parseBoolean, headers); + this.mapValue(this.indexingDirective, HttpHeaders.INDEXING_DIRECTIVE, RntbdIndexingDirective::valueOf, headers); + this.mapValue(this.isRUPerMinuteUsed, BackendHeaders.IS_RU_PER_MINUTE_USED, Byte::parseByte, headers); + this.mapValue(this.itemCount, HttpHeaders.ITEM_COUNT, Integer::parseInt, headers); + this.mapValue(this.itemLSN, BackendHeaders.ITEM_LSN, Long::parseLong, headers); + this.mapValue(this.itemLocalLSN, BackendHeaders.ITEM_LOCAL_LSN, Long::parseLong, headers); + this.mapValue(this.lastStateChangeDateTime, HttpHeaders.LAST_STATE_CHANGE_UTC, String::toString, headers); + this.mapValue(this.lastStateChangeDateTime, HttpHeaders.LAST_STATE_CHANGE_UTC, String::toString, headers); + this.mapValue(this.localLSN, BackendHeaders.LOCAL_LSN, Long::parseLong, headers); + this.mapValue(this.logResults, HttpHeaders.LOG_RESULTS, String::toString, headers); + this.mapValue(this.numberOfReadRegions, BackendHeaders.NUMBER_OF_READ_REGIONS, Integer::parseInt, headers); + this.mapValue(this.offerReplacePending, BackendHeaders.OFFER_REPLACE_PENDING, Boolean::parseBoolean, headers); + this.mapValue(this.ownerFullName, HttpHeaders.OWNER_FULL_NAME, String::toString, headers); + this.mapValue(this.ownerId, HttpHeaders.OWNER_ID, String::toString, headers); + this.mapValue(this.partitionKeyRangeId, BackendHeaders.PARTITION_KEY_RANGE_ID, String::toString, headers); + this.mapValue(this.queryMetrics, BackendHeaders.QUERY_METRICS, String::toString, headers); + this.mapValue(this.quorumAckedLSN, BackendHeaders.QUORUM_ACKED_LSN, Long::parseLong, headers); + this.mapValue(this.quorumAckedLocalLSN, BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long::parseLong, headers); + this.mapValue(this.requestCharge, HttpHeaders.REQUEST_CHARGE, Double::parseDouble, headers); + this.mapValue(this.requestValidationFailure, BackendHeaders.REQUEST_VALIDATION_FAILURE, Byte::parseByte, headers); + this.mapValue(this.restoreState, BackendHeaders.RESTORE_STATE, String::toString, headers); + this.mapValue(this.retryAfterMilliseconds, HttpHeaders.RETRY_AFTER_IN_MILLISECONDS, Integer::parseInt, headers); + this.mapValue(this.schemaVersion, HttpHeaders.SCHEMA_VERSION, String::toString, headers); + this.mapValue(this.serverDateTimeUtc, HttpHeaders.X_DATE, String::toString, headers); + this.mapValue(this.sessionToken, HttpHeaders.SESSION_TOKEN, String::toString, headers); + this.mapValue(this.shareThroughput, BackendHeaders.SHARE_THROUGHPUT, Boolean::parseBoolean, headers); + this.mapValue(this.storageMaxResoureQuota, HttpHeaders.MAX_RESOURCE_QUOTA, String::toString, headers); + this.mapValue(this.storageResourceQuotaUsage, HttpHeaders.CURRENT_RESOURCE_QUOTA_USAGE, String::toString, headers); + this.mapValue(this.subStatus, BackendHeaders.SUB_STATUS, Integer::parseInt, headers); + this.mapValue(this.transportRequestID, HttpHeaders.TRANSPORT_REQUEST_ID, Integer::parseInt, headers); + this.mapValue(this.xpRole, BackendHeaders.XP_ROLE, Integer::parseInt, headers); + } + + @Override + public String toString() { + final ObjectWriter writer = RntbdObjectMapper.writer(); + try { + return writer.writeValueAsString(this); + } catch (final JsonProcessingException error) { + throw new CorruptedFrameException(error); + } + } + + private void collectEntries(final BiConsumer>> collector) { + + collector.accept(this.LSN, token -> + toLongEntry(BackendHeaders.LSN, token) + ); + + collector.accept(this.collectionLazyIndexProgress, token -> + toIntegerEntry(HttpHeaders.COLLECTION_LAZY_INDEXING_PROGRESS, token) + ); + + collector.accept(this.collectionPartitionIndex, token -> + toIntegerEntry(BackendHeaders.COLLECTION_PARTITION_INDEX, token) + ); + + collector.accept(this.collectionSecurityIdentifier, token -> + toStringEntry(BackendHeaders.COLLECTION_SECURITY_IDENTIFIER, token) + ); + + collector.accept(this.collectionServiceIndex, token -> + toIntegerEntry(BackendHeaders.COLLECTION_SERVICE_INDEX, token) + ); + + collector.accept(this.collectionUpdateProgress, token -> + toIntegerEntry(HttpHeaders.COLLECTION_INDEX_TRANSFORMATION_PROGRESS, token) + ); + + collector.accept(this.continuationToken, token -> + toStringEntry(HttpHeaders.CONTINUATION, token) + ); + + collector.accept(this.currentReplicaSetSize, token -> + toIntegerEntry(BackendHeaders.CURRENT_REPLICA_SET_SIZE, token) + ); + + collector.accept(this.currentWriteQuorum, token -> + toIntegerEntry(BackendHeaders.CURRENT_WRITE_QUORUM, token) + ); + + collector.accept(this.databaseAccountId, token -> + toStringEntry(BackendHeaders.DATABASE_ACCOUNT_ID, token) + ); + + collector.accept(this.disableRntbdChannel, token -> + toBooleanEntry(HttpHeaders.DISABLE_RNTBD_CHANNEL, token) + ); + + collector.accept(this.eTag, token -> + toStringEntry(HttpHeaders.E_TAG, token) + ); + + collector.accept(this.globalCommittedLSN, token -> + toLongEntry(BackendHeaders.GLOBAL_COMMITTED_LSN, token) + ); + + collector.accept(this.hasTentativeWrites, token -> + toBooleanEntry(BackendHeaders.HAS_TENTATIVE_WRITES, token) + ); + + collector.accept(this.indexingDirective, token -> + new Entry(HttpHeaders.INDEXING_DIRECTIVE, RntbdIndexingDirective.fromId(token.getValue(Byte.class)).name()) + ); + + collector.accept(this.isRUPerMinuteUsed, token -> + toByteEntry(BackendHeaders.IS_RU_PER_MINUTE_USED, token) + ); + + collector.accept(this.itemCount, token -> + toIntegerEntry(HttpHeaders.ITEM_COUNT, token) + ); + + collector.accept(this.itemLSN, token -> + toLongEntry(BackendHeaders.ITEM_LSN, token) + ); + + collector.accept(this.itemLocalLSN, token -> + toLongEntry(BackendHeaders.ITEM_LOCAL_LSN, token) + ); + + collector.accept(this.lastStateChangeDateTime, token -> + toStringEntry(HttpHeaders.LAST_STATE_CHANGE_UTC, token) + ); + + collector.accept(this.localLSN, token -> + toLongEntry(BackendHeaders.LOCAL_LSN, token) + ); + + collector.accept(this.logResults, token -> + toStringEntry(HttpHeaders.LOG_RESULTS, token) + ); + + collector.accept(this.numberOfReadRegions, token -> + toIntegerEntry(BackendHeaders.NUMBER_OF_READ_REGIONS, token) + ); + + collector.accept(this.offerReplacePending, token -> + toBooleanEntry(BackendHeaders.OFFER_REPLACE_PENDING, token) + ); + + collector.accept(this.ownerFullName, token -> + toStringEntry(HttpHeaders.OWNER_FULL_NAME, token) + ); + + collector.accept(this.ownerId, token -> + toStringEntry(HttpHeaders.OWNER_ID, token) + ); + + collector.accept(this.partitionKeyRangeId, token -> + toStringEntry(BackendHeaders.PARTITION_KEY_RANGE_ID, token) + ); + + collector.accept(this.queryMetrics, token -> + toStringEntry(BackendHeaders.QUERY_METRICS, token) + ); + + collector.accept(this.quorumAckedLSN, token -> + toLongEntry(BackendHeaders.QUORUM_ACKED_LSN, token) + ); + + collector.accept(this.quorumAckedLocalLSN, token -> + toLongEntry(BackendHeaders.QUORUM_ACKED_LOCAL_LSN, token) + ); + + collector.accept(this.requestCharge, token -> + toCurrencyEntry(HttpHeaders.REQUEST_CHARGE, token) + ); + + collector.accept(this.requestValidationFailure, token -> + toByteEntry(BackendHeaders.REQUEST_VALIDATION_FAILURE, token) + ); + + collector.accept(this.restoreState, token -> + toStringEntry(BackendHeaders.RESTORE_STATE, token) + ); + + collector.accept(this.retryAfterMilliseconds, token -> + toIntegerEntry(HttpHeaders.RETRY_AFTER_IN_MILLISECONDS, token) + ); + + collector.accept(this.schemaVersion, token -> + toStringEntry(HttpHeaders.SCHEMA_VERSION, token) + ); + + collector.accept(this.serverDateTimeUtc, token -> + toStringEntry(HttpHeaders.X_DATE, token) + ); + + collector.accept(this.sessionToken, token -> + this.toSessionTokenEntry(HttpHeaders.SESSION_TOKEN, token) + ); + + collector.accept(this.shareThroughput, token -> + toBooleanEntry(BackendHeaders.SHARE_THROUGHPUT, token) + ); + + collector.accept(this.storageMaxResoureQuota, token -> + toStringEntry(HttpHeaders.MAX_RESOURCE_QUOTA, token) + ); + + collector.accept(this.storageResourceQuotaUsage, token -> + toStringEntry(HttpHeaders.CURRENT_RESOURCE_QUOTA_USAGE, token) + ); + + collector.accept(this.subStatus, token -> + toIntegerEntry(BackendHeaders.SUB_STATUS, token) + ); + + collector.accept(this.transportRequestID, token -> + toIntegerEntry(HttpHeaders.TRANSPORT_REQUEST_ID, token) + ); + + collector.accept(this.xpRole, token -> + toIntegerEntry(BackendHeaders.XP_ROLE, token) + ); + } + + private void mapValue(final RntbdToken token, final String name, final Function parse, final Map headers) { + + final String value = headers.get(name); + + if (value != null) { + token.setValue(parse.apply(value)); + } + } + + private static Map.Entry toBooleanEntry(final String name, final RntbdToken token) { + return new Entry(name, String.valueOf(token.getValue(Byte.class) != 0)); + } + + private static Map.Entry toByteEntry(final String name, final RntbdToken token) { + return new Entry(name, Byte.toString(token.getValue(Byte.class))); + } + + private static Map.Entry toCurrencyEntry(final String name, final RntbdToken token) { + final BigDecimal value = new BigDecimal(Math.round(token.getValue(Double.class) * 100D)).scaleByPowerOfTen(-2); + return new Entry(name, value.toString()); + } + + private static Map.Entry toIntegerEntry(final String name, final RntbdToken token) { + return new Entry(name, Long.toString(token.getValue(Long.class))); + } + + private static Map.Entry toLongEntry(final String name, final RntbdToken token) { + return new Entry(name, Long.toString(token.getValue(Long.class))); + } + + private Map.Entry toSessionTokenEntry(final String name, final RntbdToken token) { + return new Entry(name, this.partitionKeyRangeId.getValue(String.class) + ":" + this.sessionToken.getValue(String.class)); + } + + private static Map.Entry toStringEntry(final String name, final RntbdToken token) { + return new Entry(name, token.getValue(String.class)); + } + + private static final class Entry extends AbstractMap.SimpleImmutableEntry { + Entry(final String name, final String value) { + super(name, value); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseStatus.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseStatus.java new file mode 100644 index 0000000000000..c5c3ad68f36de --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdResponseStatus.java @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectWriter; +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.CorruptedFrameException; +import io.netty.handler.codec.http.HttpResponseStatus; + +import java.util.UUID; + +@JsonPropertyOrder({ "length", "status", "activityId" }) +final class RntbdResponseStatus { + + // region Fields + + static final int LENGTH = Integer.BYTES // length + + Integer.BYTES // status + + 2 * Long.BYTES; // activityId + + @JsonProperty("activityId") + private final UUID activityId; + + @JsonProperty("length") + private final int length; + + private final HttpResponseStatus status; + + // endregion + + RntbdResponseStatus(final int length, final HttpResponseStatus status, final UUID activityId) { + this.length = length; + this.status = status; + this.activityId = activityId; + } + + public UUID getActivityId() { + return this.activityId; + } + + int getHeadersLength() { + return this.length - LENGTH; + } + + public int getLength() { + return this.length; + } + + public HttpResponseStatus getStatus() { + return this.status; + } + + @JsonProperty("status") + public int getStatusCode() { + return this.status.code(); + } + + static RntbdResponseStatus decode(final ByteBuf in) { + + final long length = in.readUnsignedIntLE(); + + if (!(LENGTH <= length && length <= Integer.MAX_VALUE)) { + final String reason = String.format("frame length: %d", length); + throw new CorruptedFrameException(reason); + } + + final int code = in.readIntLE(); + final HttpResponseStatus status = HttpResponseStatus.valueOf(code); + + if (status == null) { + final String reason = String.format("status code: %d", code); + throw new CorruptedFrameException(reason); + } + + final UUID activityId = RntbdUUID.decode(in); + return new RntbdResponseStatus((int)length, status, activityId); + } + + void encode(final ByteBuf out) { + out.writeIntLE(this.getLength()); + out.writeIntLE(this.getStatusCode()); + RntbdUUID.encode(this.getActivityId(), out); + } + + @Override + public String toString() { + final ObjectWriter writer = RntbdObjectMapper.writer(); + try { + return writer.writeValueAsString(this); + } catch (final JsonProcessingException error) { + throw new CorruptedFrameException(error); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdServiceEndpoint.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdServiceEndpoint.java new file mode 100644 index 0000000000000..c9a131243f08c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdServiceEndpoint.java @@ -0,0 +1,354 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.directconnectivity.RntbdTransportClient.Options; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import com.google.common.collect.ImmutableMap; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelOption; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.ssl.SslContext; +import io.netty.util.concurrent.DefaultThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.SocketAddress; +import java.net.URI; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +@JsonSerialize(using = RntbdServiceEndpoint.JsonSerializer.class) +public final class RntbdServiceEndpoint implements RntbdEndpoint { + + private static final AtomicLong instanceCount = new AtomicLong(); + private static final Logger logger = LoggerFactory.getLogger(RntbdServiceEndpoint.class); + private static final String namePrefix = RntbdServiceEndpoint.class.getSimpleName() + '-'; + + private final RntbdClientChannelPool channelPool; + private final AtomicBoolean closed; + private final RntbdMetrics metrics; + private final String name; + private final SocketAddress remoteAddress; + private final RntbdRequestTimer requestTimer; + + // region Constructors + + private RntbdServiceEndpoint( + final Config config, final NioEventLoopGroup group, final RntbdRequestTimer timer, final URI physicalAddress + ) { + + final Bootstrap bootstrap = new Bootstrap() + .channel(NioSocketChannel.class) + .group(group) + .option(ChannelOption.AUTO_READ, true) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getConnectionTimeout()) + .option(ChannelOption.SO_KEEPALIVE, true) + .remoteAddress(physicalAddress.getHost(), physicalAddress.getPort()); + + this.name = RntbdServiceEndpoint.namePrefix + instanceCount.incrementAndGet(); + this.channelPool = new RntbdClientChannelPool(bootstrap, config); + this.remoteAddress = bootstrap.config().remoteAddress(); + this.metrics = new RntbdMetrics(this.name); + this.closed = new AtomicBoolean(); + this.requestTimer = timer; + } + + // endregion + + // region Accessors + + @Override + public String getName() { + return this.name; + } + + // endregion + + // region Methods + + @Override + public void close() { + if (this.closed.compareAndSet(false, true)) { + this.channelPool.close(); + this.metrics.close(); + } + } + + public RntbdRequestRecord request(final RntbdRequestArgs args) { + + this.throwIfClosed(); + + if (logger.isDebugEnabled()) { + args.traceOperation(logger, null, "request"); + logger.debug("\n {}\n {}\n REQUEST", this, args); + } + + final RntbdRequestRecord requestRecord = this.write(args); + this.metrics.incrementRequestCount(); + + requestRecord.whenComplete((response, error) -> { + + args.traceOperation(logger, null, "requestComplete", response, error); + this.metrics.incrementResponseCount(); + + if (error != null) { + this.metrics.incrementErrorResponseCount(); + } + + if (logger.isDebugEnabled()) { + if (error == null) { + final int status = response.getStatus(); + logger.debug("\n [{}]\n {}\n request succeeded with response status: {}", this, args, status); + } else { + logger.debug("\n [{}]\n {}\n request failed due to ", this, args, error); + } + } + }); + + return requestRecord; + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + // endregion + + // region Privates + + private void releaseToPool(final Channel channel) { + + logger.debug("\n [{}]\n {}\n RELEASE", this, channel); + + this.channelPool.release(channel).addListener(future -> { + if (logger.isDebugEnabled()) { + if (future.isSuccess()) { + logger.debug("\n [{}]\n {}\n release succeeded", this, channel); + } else { + logger.debug("\n [{}]\n {}\n release failed due to {}", this, channel, future.cause()); + } + } + }); + } + + private void throwIfClosed() { + checkState(!this.closed.get(), "%s is closed", this); + } + + private RntbdRequestRecord write(final RntbdRequestArgs requestArgs) { + + final RntbdRequestRecord requestRecord = new RntbdRequestRecord(requestArgs, this.requestTimer); + logger.debug("\n [{}]\n {}\n WRITE", this, requestArgs); + + this.channelPool.acquire().addListener(connected -> { + + if (connected.isSuccess()) { + + requestArgs.traceOperation(logger, null, "write"); + final Channel channel = (Channel)connected.get(); + this.releaseToPool(channel); + + channel.write(requestRecord).addListener((ChannelFuture future) -> { + requestArgs.traceOperation(logger, null, "writeComplete", channel); + if (!future.isSuccess()) { + this.metrics.incrementErrorResponseCount(); + } + }); + + return; + } + + final UUID activityId = requestArgs.getActivityId(); + final Throwable cause = connected.cause(); + + if (connected.isCancelled()) { + + logger.debug("\n [{}]\n {}\n write cancelled: {}", this, requestArgs, cause); + requestRecord.cancel(true); + + } else { + + logger.debug("\n [{}]\n {}\n write failed due to {} ", this, requestArgs, cause); + final String reason = cause.getMessage(); + + final GoneException goneException = new GoneException( + String.format("failed to establish connection to %s: %s", this.remoteAddress, reason), + cause instanceof Exception ? (Exception)cause : new IOException(reason, cause), + ImmutableMap.of(HttpConstants.HttpHeaders.ACTIVITY_ID, activityId.toString()), + requestArgs.getReplicaPath() + ); + + BridgeInternal.setRequestHeaders(goneException, requestArgs.getServiceRequest().getHeaders()); + requestRecord.completeExceptionally(goneException); + } + }); + + return requestRecord; + } + + // endregion + + // region Types + + static final class JsonSerializer extends StdSerializer { + + public JsonSerializer() { + this(null); + } + + public JsonSerializer(Class type) { + super(type); + } + + @Override + public void serialize(RntbdServiceEndpoint value, JsonGenerator generator, SerializerProvider provider) + throws IOException { + + generator.writeStartObject(); + generator.writeStringField(value.name, value.remoteAddress.toString()); + generator.writeObjectField("channelPool", value.channelPool); + generator.writeEndObject(); + } + } + + public static final class Provider implements RntbdEndpoint.Provider { + + private static final Logger logger = LoggerFactory.getLogger(Provider.class); + + private final AtomicBoolean closed = new AtomicBoolean(); + private final Config config; + private final ConcurrentHashMap endpoints = new ConcurrentHashMap<>(); + private final NioEventLoopGroup eventLoopGroup; + private final RntbdRequestTimer requestTimer; + + public Provider(final Options options, final SslContext sslContext) { + + checkNotNull(options, "options"); + checkNotNull(sslContext, "sslContext"); + + final DefaultThreadFactory threadFactory = new DefaultThreadFactory("CosmosEventLoop", true); + final int threadCount = Runtime.getRuntime().availableProcessors(); + final LogLevel wireLogLevel; + + if (logger.isTraceEnabled()) { + wireLogLevel = LogLevel.TRACE; + } else if (logger.isDebugEnabled()) { + wireLogLevel = LogLevel.DEBUG; + } else { + wireLogLevel = null; + } + + this.config = new Config(options, sslContext, wireLogLevel); + this.requestTimer = new RntbdRequestTimer(config.getRequestTimeout()); + this.eventLoopGroup = new NioEventLoopGroup(threadCount, threadFactory); + } + + @Override + public void close() throws RuntimeException { + + if (this.closed.compareAndSet(false, true)) { + + this.requestTimer.close(); + + for (final RntbdEndpoint endpoint : this.endpoints.values()) { + endpoint.close(); + } + + this.eventLoopGroup.shutdownGracefully().addListener(future -> { + if (future.isSuccess()) { + logger.debug("\n [{}]\n closed endpoints", this); + return; + } + logger.error("\n [{}]\n failed to close endpoints due to ", this, future.cause()); + }); + return; + } + + logger.debug("\n [{}]\n already closed", this); + } + + @Override + public Config config() { + return this.config; + } + + @Override + public int count() { + return this.endpoints.size(); + } + + @Override + public RntbdEndpoint get(URI physicalAddress) { + return endpoints.computeIfAbsent(physicalAddress.getAuthority(), authority -> + new RntbdServiceEndpoint(config, eventLoopGroup, requestTimer, physicalAddress) + ); + } + + @Override + public Stream list() { + return this.endpoints.values().stream(); + } + + private void deleteEndpoint(final URI physicalAddress) { + + // TODO: DANOBLE: Utilize this method of tearing down unhealthy endpoints + // Specifically, ensure that this method is called when a Read/WriteTimeoutException occurs or a health + // check request fails. This perhaps likely requires a change to RntbdClientChannelPool. + // Links: + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/331552 + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/331593 + + checkNotNull(physicalAddress, "physicalAddress: %s", physicalAddress); + + final String authority = physicalAddress.getAuthority(); + final RntbdEndpoint endpoint = this.endpoints.remove(authority); + + if (endpoint != null) { + endpoint.close(); + } + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdToken.java new file mode 100644 index 0000000000000..513bc27b67924 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdToken.java @@ -0,0 +1,234 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.PropertyWriter; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import io.netty.buffer.ByteBuf; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdHeader; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +@JsonPropertyOrder({ "id", "name", "type", "present", "required", "value" }) +final class RntbdToken { + + // region Fields + + private static final int HEADER_LENGTH = Short.BYTES + Byte.BYTES; + + static { + RntbdObjectMapper.registerPropertyFilter(RntbdToken.class, RntbdToken.PropertyFilter.class); + } + + private final RntbdHeader header; + private int length; + private Object value; + + // endregion + + // region Constructors + + private RntbdToken(final RntbdHeader header) { + checkNotNull(header, "header"); + this.header = header; + this.value = null; + this.length = Integer.MIN_VALUE; + } + + // endregion + + // region Accessors + + @JsonProperty + public short getId() { + return this.header.id(); + } + + @JsonProperty + public String getName() { + return this.header.name(); + } + + @JsonProperty + public RntbdTokenType getTokenType() { + return this.header.type(); + } + + @JsonProperty + public Object getValue() { + + if (this.value == null) { + return this.header.type().codec().defaultValue(); + } + + if (this.value instanceof ByteBuf) { + final ByteBuf buffer = (ByteBuf)this.value; + this.value = this.header.type().codec().read(buffer); + buffer.release(); + } else { + this.value = this.header.type().codec().convert(this.value); + } + + return this.value; + } + + public T getValue(final Class cls) { + return cls.cast(this.getValue()); + } + + @JsonProperty + public void setValue(final Object value) { + this.ensureValid(value); + this.length = Integer.MIN_VALUE; + this.value = value; + } + + @JsonIgnore + public final Class getValueType() { + return this.header.type().codec().valueType(); + } + + @JsonProperty + public boolean isPresent() { + return this.value != null; + } + + @JsonProperty + public boolean isRequired() { + return this.header.isRequired(); + } + + // endregion + + // region Methods + + public int computeLength() { + + if (!this.isPresent()) { + return 0; + } + + if (this.value instanceof ByteBuf) { + final ByteBuf buffer = (ByteBuf)this.value; + assert buffer.readerIndex() == 0; + return HEADER_LENGTH + buffer.readableBytes(); + } + + if (this.length == Integer.MIN_VALUE) { + this.length = HEADER_LENGTH + this.header.type().codec().computeLength(this.value); + } + + return this.length; + } + + public static RntbdToken create(final RntbdHeader header) { + return new RntbdToken(header); + } + + public void decode(final ByteBuf in) { + + checkNotNull(in, "in"); + + if (this.value instanceof ByteBuf) { + ((ByteBuf)this.value).release(); + } + + this.value = this.header.type().codec().readSlice(in).retain(); // No data transfer until the first call to RntbdToken.getValue + } + + public void encode(final ByteBuf out) { + + checkNotNull(out, "out"); + + if (!this.isPresent()) { + if (this.isRequired()) { + final String message = String.format("Missing value for required header: %s", this); + throw new IllegalStateException(message); + } + return; + } + + out.writeShortLE(this.getId()); + out.writeByte(this.getTokenType().id()); + + if (this.value instanceof ByteBuf) { + out.writeBytes((ByteBuf)this.value); + } else { + this.ensureValid(this.value); + this.header.type().codec().write(this.value, out); + } + } + + public void releaseBuffer() { + if (this.value instanceof ByteBuf) { + final ByteBuf buffer = (ByteBuf)this.value; + buffer.release(); + } + } + + @Override + public String toString() { + return RntbdObjectMapper.toJson(this); + } + + // endregion + + // region Privates + + private void ensureValid(final Object value) { + checkNotNull(value, "value"); + checkArgument(this.header.type().codec().isValid(value), "value: %s", value.getClass()); + } + + // endregion + + // region Types + + static class PropertyFilter extends SimpleBeanPropertyFilter { + + @Override + public void serializeAsField(final Object object, final JsonGenerator generator, final SerializerProvider provider, final PropertyWriter writer) throws Exception { + + if (generator.canOmitFields()) { + + final Object value = writer.getMember().getValue(object); + + if (value instanceof RntbdToken && !((RntbdToken)value).isPresent()) { + return; + } + } + + writer.serializeAsField(object, generator, provider); + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenStream.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenStream.java new file mode 100644 index 0000000000000..7ddd442819527 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenStream.java @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import io.netty.buffer.ByteBuf; + +import java.util.stream.Collector; + +import static com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdConstants.RntbdHeader; +import static com.google.common.base.Preconditions.checkNotNull; + +@SuppressWarnings("UnstableApiUsage") +abstract class RntbdTokenStream & RntbdHeader> { + + final ImmutableMap headers; + final ImmutableMap tokens; + + RntbdTokenStream(final ImmutableSet headers, final ImmutableMap ids) { + + checkNotNull(headers, "headers"); + checkNotNull(ids, "ids"); + + final Collector> collector = Maps.toImmutableEnumMap(h -> h, RntbdToken::create); + this.tokens = headers.stream().collect(collector); + this.headers = ids; + } + + final int computeCount() { + + int count = 0; + + for (final RntbdToken token : this.tokens.values()) { + if (token.isPresent()) { + ++count; + } + } + + return count; + } + + final int computeLength() { + + int total = 0; + + for (final RntbdToken token : this.tokens.values()) { + total += token.computeLength(); + } + + return total; + } + + static > T decode(final ByteBuf in, final T stream) { + + while (in.readableBytes() > 0) { + + final short id = in.readShortLE(); + final RntbdTokenType type = RntbdTokenType.fromId(in.readByte()); + + RntbdToken token = stream.tokens.get(stream.headers.get(id)); + + if (token == null) { + token = RntbdToken.create(new UndefinedHeader(id, type)); + } + + token.decode(in); + } + + for (final RntbdToken token : stream.tokens.values()) { + if (!token.isPresent() && token.isRequired()) { + final String reason = String.format("Required token not found on RNTBD stream: type: %s, identifier: %s", + token.getTokenType(), token.getId()); + throw new IllegalStateException(reason); + } + } + + return stream; + } + + final void encode(final ByteBuf out) { + for (final RntbdToken token : this.tokens.values()) { + token.encode(out); + } + } + + final RntbdToken get(final T header) { + return this.tokens.get(header); + } + + final void releaseBuffers() { + for (final RntbdToken token : this.tokens.values()) { + token.releaseBuffer(); + } + } + + private static final class UndefinedHeader implements RntbdHeader { + + private final short id; + private final RntbdTokenType type; + + UndefinedHeader(final short id, final RntbdTokenType type) { + this.id = id; + this.type = type; + } + + @Override + public boolean isRequired() { + return false; + } + + @Override + public short id() { + return this.id; + } + + @Override + public String name() { + return "Undefined"; + } + + @Override + public RntbdTokenType type() { + return this.type; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenType.java new file mode 100644 index 0000000000000..c92562376cb10 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdTokenType.java @@ -0,0 +1,896 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import com.google.common.base.Strings; +import com.google.common.base.Utf8; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.handler.codec.DecoderException; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +enum RntbdTokenType { + + // All values are encoded as little endian byte sequences except for Guid + // Guid values are serialized in Microsoft GUID byte order + // Reference: GUID structure and System.Guid type + + Byte((byte)0x00, RntbdByte.codec), // byte => byte + UShort((byte)0x01, RntbdUnsignedShort.codec), // short => int + ULong((byte)0x02, RntbdUnsignedInteger.codec), // int => long + Long((byte)0x03, RntbdInteger.codec), // int => int + ULongLong((byte)0x04, RntbdLong.codec), // long => long + LongLong((byte)0x05, RntbdLong.codec), // long => long + + Guid((byte)0x06, RntbdGuid.codec), // byte[16] => UUID + SmallString((byte)0x07, RntbdShortString.codec), // (byte, byte[0..255]) => String + String((byte)0x08, RntbdString.codec), // (short, byte[0..64KiB]) => String + ULongString((byte)0x09, RntbdLongString.codec), // (int, byte[0..2GiB-1]) => String + + SmallBytes((byte)0x0A, RntbdShortBytes.codec), // (byte, byte[0..255]) => byte[] + Bytes((byte)0x0B, RntbdBytes.codec), // (short, byte[0..64KiB]) => byte[] + ULongBytes((byte)0x0C, RntbdLongBytes.codec), // (int, byte[0..2GiB-1]) => byte[] + + Float((byte)0x0D, RntbdFloat.codec), // float => float + Double((byte)0x0E, RntbdDouble.codec), // double => double + + Invalid((byte)0xFF, RntbdNone.codec); // no data + + // region Implementation + + private Codec codec; + private byte id; + + RntbdTokenType(final byte id, final Codec codec) { + this.codec = codec; + this.id = id; + } + + public Codec codec() { + return this.codec; + } + + public static RntbdTokenType fromId(final byte value) { + + for (final RntbdTokenType tokenType : RntbdTokenType.values()) { + if (value == tokenType.id) { + return tokenType; + } + } + return Invalid; + } + + public byte id() { + return this.id; + } + + // endregion + + // region Types + + public interface Codec { + + int computeLength(Object value); + + Object convert(Object value); + + Object defaultValue(); + + boolean isValid(Object value); + + Object read(ByteBuf in); + + ByteBuf readSlice(ByteBuf in); + + Class valueType(); + + void write(Object value, ByteBuf out); + } + + private static class RntbdByte implements Codec { + + public static final Codec codec = new RntbdByte(); + + private RntbdByte() { + } + + @Override + public final int computeLength(final Object value) { + return java.lang.Byte.BYTES; + } + + @Override + public final Object convert(final Object value) { + + assert this.isValid(value); + + if (value instanceof Number) { + return ((Number)value).byteValue(); + } + return (boolean)value ? (byte)0x01 : (byte)0x00; + } + + @Override + public final Object defaultValue() { + return (byte)0; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number || value instanceof Boolean; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readByte(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Byte.BYTES); + } + + @Override + public final Class valueType() { + return java.lang.Byte.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeByte(value instanceof java.lang.Byte ? (byte)value : ((boolean)value ? 0x01 : 0x00)); + } + } + + private static class RntbdBytes implements Codec { + + public static final Codec codec = new RntbdBytes(); + private static final byte[] defaultValue = {}; + + private RntbdBytes() { + } + + @Override + public int computeLength(final Object value) { + assert this.isValid(value); + return Short.BYTES + ((byte[])value).length; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return value; + } + + @Override + public final Object defaultValue() { + return defaultValue; + } + + @Override + public boolean isValid(final Object value) { + return value instanceof byte[] && ((byte[])value).length < 0xFFFF; + } + + @Override + public Object read(final ByteBuf in) { + final int length = in.readUnsignedShortLE(); + return in.readBytes(length); + } + + @Override + public ByteBuf readSlice(final ByteBuf in) { + final int length = in.getUnsignedShortLE(in.readerIndex()); + return in.readSlice(Short.BYTES + length); + } + + @Override + public Class valueType() { + return java.lang.Byte[].class; + } + + @Override + public void write(final Object value, final ByteBuf out) { + + assert this.isValid(value); + + final byte[] bytes = (byte[])value; + final int length = bytes.length; + + if (length > 0xFFFF) { + throw new IllegalStateException(); + } + + out.writeShortLE((short)length); + out.writeBytes(bytes); + } + } + + private static class RntbdDouble implements Codec { + + public static final Codec codec = new RntbdDouble(); + + private RntbdDouble() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return java.lang.Double.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).doubleValue(); + } + + @Override + public final Object defaultValue() { + return 0.0D; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readDoubleLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Double.BYTES); + } + + @Override + public Class valueType() { + return java.lang.Double.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeDoubleLE(((Number)value).doubleValue()); + } + } + + private static class RntbdFloat implements Codec { + + public static final Codec codec = new RntbdFloat(); + + private RntbdFloat() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return java.lang.Float.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).floatValue(); + } + + @Override + public final Object defaultValue() { + return 0.0F; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readFloatLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Float.BYTES); + } + + @Override + public Class valueType() { + return java.lang.Float.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeFloatLE(((Number)value).floatValue()); + } + } + + private static class RntbdGuid implements Codec { + + public static final Codec codec = new RntbdGuid(); + + private RntbdGuid() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return 2 * java.lang.Long.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return value; + } + + @Override + public final Object defaultValue() { + return RntbdUUID.EMPTY; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof UUID; + } + + @Override + public final Object read(final ByteBuf in) { + return RntbdUUID.decode(in); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(2 * java.lang.Long.BYTES); + } + + @Override + public Class valueType() { + return UUID.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + RntbdUUID.encode((UUID)value, out); + } + } + + private static class RntbdInteger implements Codec { + + public static final Codec codec = new RntbdInteger(); + + private RntbdInteger() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return Integer.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).intValue(); + } + + @Override + public final Object defaultValue() { + return 0; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readIntLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(Integer.BYTES); + } + + @Override + public Class valueType() { + return Integer.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeIntLE(((Number)value).intValue()); + } + } + + private static class RntbdLong implements Codec { + + public static final Codec codec = new RntbdLong(); + + private RntbdLong() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return java.lang.Long.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).longValue(); + } + + @Override + public final Object defaultValue() { + return 0L; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readLongLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Long.BYTES); + } + + @Override + public Class valueType() { + return java.lang.Long.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeLongLE(((Number)value).longValue()); + } + } + + private static class RntbdLongBytes extends RntbdBytes { + + public static final Codec codec = new RntbdLongBytes(); + + private RntbdLongBytes() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return Integer.BYTES + ((byte[])value).length; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof byte[] && ((byte[])value).length < 0xFFFF; + } + + @Override + public final Object read(final ByteBuf in) { + + final long length = in.readUnsignedIntLE(); + + if (length > Integer.MAX_VALUE) { + throw new IllegalStateException(); + } + return in.readBytes((int)length); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + + final long length = in.getUnsignedIntLE(in.readerIndex()); + + if (length > Integer.MAX_VALUE) { + throw new IllegalStateException(); + } + return in.readSlice(Integer.BYTES + (int)length); + } + + @Override + public final void write(final Object value, final ByteBuf out) { + + assert this.isValid(value); + + final byte[] bytes = (byte[])value; + out.writeIntLE(bytes.length); + out.writeBytes(bytes); + } + } + + private static class RntbdLongString extends RntbdString { + + public static final Codec codec = new RntbdLongString(); + + private RntbdLongString() { + } + + @Override + public final int computeLength(final Object value) { + return Integer.BYTES + this.computeLength(value, Integer.MAX_VALUE); + } + + @Override + public final Object read(final ByteBuf in) { + + final long length = in.readUnsignedIntLE(); + + if (length > Integer.MAX_VALUE) { + throw new IllegalStateException(); + } + + return in.readCharSequence((int)length, StandardCharsets.UTF_8).toString(); + } + + @Override + public final void write(final Object value, final ByteBuf out) { + + final int length = this.computeLength(value, Integer.MAX_VALUE); + out.writeIntLE(length); + writeValue(out, value, length); + } + } + + private static class RntbdNone implements Codec { + + public static final Codec codec = new RntbdNone(); + + @Override + public final int computeLength(final Object value) { + return 0; + } + + @Override + public final Object convert(final Object value) { + return null; + } + + @Override + public final Object defaultValue() { + return null; + } + + @Override + public final boolean isValid(final Object value) { + return true; + } + + @Override + public final Object read(final ByteBuf in) { + return null; + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return null; + } + + @Override + public Class valueType() { + return null; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + } + } + + private static class RntbdShortBytes extends RntbdBytes { + + public static final Codec codec = new RntbdShortBytes(); + + private RntbdShortBytes() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return java.lang.Byte.BYTES + ((byte[])value).length; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof byte[] && ((byte[])value).length < 0xFFFF; + } + + @Override + public final Object read(final ByteBuf in) { + + final int length = in.readUnsignedByte(); + final byte[] bytes = new byte[length]; + in.readBytes(bytes); + + return bytes; + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Byte.BYTES + in.getUnsignedByte(in.readerIndex())); + } + + @Override + public final void write(final Object value, final ByteBuf out) { + + assert this.isValid(value); + + final byte[] bytes = (byte[])value; + final int length = bytes.length; + + if (length > 0xFF) { + throw new IllegalStateException(); + } + + out.writeByte((byte)length); + out.writeBytes(bytes); + } + } + + private static class RntbdShortString extends RntbdString { + + public static final Codec codec = new RntbdShortString(); + + private RntbdShortString() { + } + + @Override + public final int computeLength(final Object value) { + return java.lang.Byte.BYTES + this.computeLength(value, 0xFF); + } + + @Override + public final Object read(final ByteBuf in) { + return in.readCharSequence(in.readUnsignedByte(), StandardCharsets.UTF_8).toString(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(java.lang.Byte.BYTES + in.getUnsignedByte(in.readerIndex())); + } + + @Override + public final void write(final Object value, final ByteBuf out) { + + final int length = this.computeLength(value, 0xFF); + out.writeByte(length); + writeValue(out, value, length); + } + } + + private static class RntbdString implements Codec { + + public static final Codec codec = new RntbdString(); + + private RntbdString() { + } + + final int computeLength(final Object value, final int maxLength) { + + assert this.isValid(value); + final int length; + + if (value instanceof java.lang.String) { + + final java.lang.String string = (java.lang.String)value; + length = Utf8.encodedLength(string); + + } else { + + final byte[] string = (byte[])value; + + if (!Utf8.isWellFormed(string)) { + final java.lang.String reason = Strings.lenientFormat("UTF-8 byte string is ill-formed: %s", ByteBufUtil.hexDump(string)); + throw new DecoderException(reason); + } + + length = string.length; + } + + if (length > maxLength) { + final java.lang.String reason = Strings.lenientFormat("UTF-8 byte string exceeds %s bytes: %s bytes", maxLength, length); + throw new DecoderException(reason); + } + + return length; + } + + @Override + public int computeLength(final Object value) { + return Short.BYTES + this.computeLength(value, 0xFFFF); + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return value instanceof java.lang.String ? value : new String((byte[])value, StandardCharsets.UTF_8); + } + + @Override + public final Object defaultValue() { + return ""; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof java.lang.String || value instanceof byte[]; + } + + @Override + public Object read(final ByteBuf in) { + final int length = in.readUnsignedShortLE(); + return in.readCharSequence(length, StandardCharsets.UTF_8).toString(); + } + + @Override + public ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(Short.BYTES + in.getUnsignedShortLE(in.readerIndex())); + } + + @Override + public Class valueType() { + return java.lang.String.class; + } + + @Override + public void write(final Object value, final ByteBuf out) { + + final int length = this.computeLength(value, 0xFFFF); + out.writeShortLE(length); + writeValue(out, value, length); + } + + static void writeValue(final ByteBuf out, final Object value, final int length) { + + final int start = out.writerIndex(); + + if (value instanceof java.lang.String) { + out.writeCharSequence((java.lang.String)value, StandardCharsets.UTF_8); + } else { + out.writeBytes((byte[])value); + } + + assert out.writerIndex() - start == length; + } + } + + private static class RntbdUnsignedInteger implements Codec { + + public static final Codec codec = new RntbdUnsignedInteger(); + + private RntbdUnsignedInteger() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return Integer.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).longValue() & 0xFFFFFFFFL; + } + + @Override + public final Object defaultValue() { + return 0L; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readUnsignedIntLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(Integer.BYTES); + } + + @Override + public Class valueType() { + return java.lang.Long.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeIntLE(((Number)value).intValue()); + } + } + + private static class RntbdUnsignedShort implements Codec { + + public static final Codec codec = new RntbdUnsignedShort(); + + private RntbdUnsignedShort() { + } + + @Override + public final int computeLength(final Object value) { + assert this.isValid(value); + return Short.BYTES; + } + + @Override + public final Object convert(final Object value) { + assert this.isValid(value); + return ((Number)value).intValue() & 0xFFFF; + } + + @Override + public final Object defaultValue() { + return 0; + } + + @Override + public final boolean isValid(final Object value) { + return value instanceof Number; + } + + @Override + public final Object read(final ByteBuf in) { + return in.readUnsignedShortLE(); + } + + @Override + public final ByteBuf readSlice(final ByteBuf in) { + return in.readSlice(Short.BYTES); + } + + @Override + public Class valueType() { + return Integer.class; + } + + @Override + public final void write(final Object value, final ByteBuf out) { + assert this.isValid(value); + out.writeShortLE(((Number)value).shortValue()); + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdUUID.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdUUID.java new file mode 100644 index 0000000000000..c8a6dc9bd3056 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/directconnectivity/rntbd/RntbdUUID.java @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package com.azure.data.cosmos.internal.directconnectivity.rntbd; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.CorruptedFrameException; + +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +public final class RntbdUUID { + + public static final UUID EMPTY = new UUID(0L, 0L); + + private RntbdUUID() { + } + + /** + * Decode a {@link UUID} as serialized by Microsoft APIs like {@code System.Guid.ToByteArray} + * + * @param bytes a {@link byte} array containing the serialized {@link UUID} to be decoded + * @return a new {@link UUID} + */ + public static UUID decode(final byte[] bytes) { + return decode(Unpooled.wrappedBuffer(bytes)); + } + + /** + * Decode a {@link UUID} as serialized by Microsoft APIs like {@code System.Guid.ToByteArray} + * + * @param in a {@link ByteBuf} containing the serialized {@link UUID} to be decoded + * @return a new {@link UUID} + */ + public static UUID decode(final ByteBuf in) { + + checkNotNull(in, "in"); + + if (in.readableBytes() < 2 * Long.BYTES) { + final String reason = String.format("invalid frame length: %d", in.readableBytes()); + throw new CorruptedFrameException(reason); + } + + long mostSignificantBits = in.readUnsignedIntLE() << 32; + + mostSignificantBits |= (0x000000000000FFFFL & in.readShortLE()) << 16; + mostSignificantBits |= (0x000000000000FFFFL & in.readShortLE()); + + long leastSignificantBits = (0x000000000000FFFFL & in.readShortLE()) << (32 + 16); + + for (int shift = 32 + 8; shift >= 0; shift -= 8) { + leastSignificantBits |= (0x00000000000000FFL & in.readByte()) << shift; + } + + return new UUID(mostSignificantBits, leastSignificantBits); + } + + /** + * Encodes a {@link UUID} as serialized by Microsoft APIs like {@code System.Guid.ToByteArray} + * + * @param uuid a {@link UUID} to be encoded + * @return a new byte array containing the encoded + */ + public static byte[] encode(final UUID uuid) { + final byte[] bytes = new byte[2 * Integer.BYTES]; + encode(uuid, Unpooled.wrappedBuffer(bytes)); + return bytes; + } + + /** + * Encodes a {@link UUID} as serialized by Microsoft APIs like {@code System.Guid.ToByteArray} + * + * @param uuid a {@link UUID} to be encoded + * @param out an output {@link ByteBuf} + */ + public static void encode(final UUID uuid, final ByteBuf out) { + + final long mostSignificantBits = uuid.getMostSignificantBits(); + + out.writeIntLE((int)((mostSignificantBits & 0xFFFFFFFF00000000L) >>> 32)); + out.writeShortLE((short)((mostSignificantBits & 0x00000000FFFF0000L) >>> 16)); + out.writeShortLE((short)(mostSignificantBits & 0x000000000000FFFFL)); + + final long leastSignificantBits = uuid.getLeastSignificantBits(); + + out.writeShortLE((short)((leastSignificantBits & 0xFFFF000000000000L) >>> (32 + 16))); + out.writeShort((short)((leastSignificantBits & 0x0000FFFF00000000L) >>> 32)); + out.writeInt((int)(leastSignificantBits & 0x00000000FFFFFFFFL)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/BufferedHttpResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/BufferedHttpResponse.java new file mode 100644 index 0000000000000..79b7ed0f58cb8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/BufferedHttpResponse.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.http; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +/** + * HTTP response which will buffer the response's body when/if it is read. + */ +public class BufferedHttpResponse extends HttpResponse { + private final HttpResponse innerHttpResponse; + private final Mono cachedBody; + + /** + * Creates a buffered HTTP response. + * + * @param innerHttpResponse The HTTP response to buffer + */ + public BufferedHttpResponse(HttpResponse innerHttpResponse) { + this.innerHttpResponse = innerHttpResponse; + this.cachedBody = innerHttpResponse.bodyAsByteArray().cache(); + this.withRequest(innerHttpResponse.request()); + } + + @Override + public int statusCode() { + return innerHttpResponse.statusCode(); + } + + @Override + public String headerValue(String name) { + return innerHttpResponse.headerValue(name); + } + + @Override + public HttpHeaders headers() { + return innerHttpResponse.headers(); + } + + @Override + public Mono bodyAsByteArray() { + return cachedBody; + } + + @Override + public Flux body() { + return bodyAsByteArray().flatMapMany(bytes -> Flux.just(Unpooled.wrappedBuffer(bytes))); + } + + @Override + public Mono bodyAsString() { + return bodyAsByteArray() + .map(bytes -> bytes == null ? null : new String(bytes, StandardCharsets.UTF_8)); + } + + @Override + public Mono bodyAsString(Charset charset) { + return bodyAsByteArray() + .map(bytes -> bytes == null ? null : new String(bytes, charset)); + } + + @Override + public BufferedHttpResponse buffer() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClient.java new file mode 100644 index 0000000000000..1689d37511b76 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClient.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.http; + +import reactor.core.publisher.Mono; +import reactor.netty.resources.ConnectionProvider; + +/** + * A generic interface for sending HTTP requests and getting responses. + */ +public interface HttpClient { + + /** + * Send the provided request asynchronously. + * + * @param request The HTTP request to send + * @return A {@link Mono} that emits response asynchronously + */ + Mono send(HttpRequest request); + + /** + * Create fixed HttpClient with {@link HttpClientConfig} + * + * @return the HttpClient + */ + static HttpClient createFixed(HttpClientConfig httpClientConfig) { + if (httpClientConfig.getConfigs() == null) { + throw new IllegalArgumentException("HttpClientConfig is null"); + } + + if (httpClientConfig.getMaxPoolSize() == null) { + return new ReactorNettyClient(ConnectionProvider.fixed(httpClientConfig.getConfigs().getReactorNettyConnectionPoolName()), httpClientConfig); + } + return new ReactorNettyClient(ConnectionProvider.fixed(httpClientConfig.getConfigs().getReactorNettyConnectionPoolName(), httpClientConfig.getMaxPoolSize()), httpClientConfig); + } + + /** + * Shutdown the Http Client and clean up resources + */ + void shutdown(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClientConfig.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClientConfig.java new file mode 100644 index 0000000000000..971d1bf310ed6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpClientConfig.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.http; + +import com.azure.data.cosmos.internal.Configs; + +import java.net.InetSocketAddress; + +/** + * Helper class internally used for instantiating reactor netty http client. + */ +public class HttpClientConfig { + public final static String REACTOR_NETWORK_LOG_CATEGORY = "com.azure.data.cosmos.netty-network"; + + private final Configs configs; + private Integer maxPoolSize; + private Integer maxIdleConnectionTimeoutInMillis; + private Integer requestTimeoutInMillis; + private InetSocketAddress proxy; + + public HttpClientConfig(Configs configs) { + this.configs = configs; + } + + public HttpClientConfig withPoolSize(int maxPoolSize) { + this.maxPoolSize = maxPoolSize; + return this; + } + + public HttpClientConfig withHttpProxy(InetSocketAddress proxy) { + this.proxy = proxy; + return this; + } + + public HttpClientConfig withMaxIdleConnectionTimeoutInMillis(int maxIdleConnectionTimeoutInMillis) { + this.maxIdleConnectionTimeoutInMillis = maxIdleConnectionTimeoutInMillis; + return this; + } + + public HttpClientConfig withRequestTimeoutInMillis(int requestTimeoutInMillis) { + this.requestTimeoutInMillis = requestTimeoutInMillis; + return this; + } + + public Configs getConfigs() { + return configs; + } + + public Integer getMaxPoolSize() { + return maxPoolSize; + } + + public Integer getMaxIdleConnectionTimeoutInMillis() { + return maxIdleConnectionTimeoutInMillis; + } + + public Integer getRequestTimeoutInMillis() { + return requestTimeoutInMillis; + } + + public InetSocketAddress getProxy() { + return proxy; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeader.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeader.java new file mode 100644 index 0000000000000..e9cbca44a59fb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeader.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.http; + +import org.apache.commons.lang3.StringUtils; + +/** + * A single header within a HTTP request or response. + * + * If multiple header values are added to a HTTP request or response with + * the same name (case-insensitive), then the values will be appended + * to the end of the same Header with commas separating them. + */ +public class HttpHeader { + private final String name; + private String value; + + /** + * Create a HttpHeader instance using the provided name and value. + * + * @param name the name + * @param value the value + */ + public HttpHeader(String name, String value) { + this.name = name; + this.value = value; + } + + /** + * Get the header name. + * + * @return the name of this Header + */ + public String name() { + return name; + } + + /** + * Get the header value. + * + * @return the value of this Header + */ + public String value() { + return value; + } + + /** + * Get the comma separated value as an array. + * + * @return the values of this Header that are separated by a comma + */ + public String[] values() { + return value == null ? null : StringUtils.split(value, ","); + } + + /** + * Get the String representation of the header. + * + * @return the String representation of this HttpHeader + */ + @Override + public String toString() { + return name + ":" + value; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeaders.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeaders.java new file mode 100644 index 0000000000000..f1bf91509ce3d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpHeaders.java @@ -0,0 +1,154 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.http; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializable; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsontype.TypeSerializer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +/** + * A collection of headers on an HTTP request or response. + */ +public class HttpHeaders implements Iterable, JsonSerializable { + private Map headers; + + /** + * Create an empty HttpHeaders instance. + */ + public HttpHeaders() { + this.headers = new HashMap<>(); + } + + /** + * Create an HttpHeaders instance with the given size. + */ + public HttpHeaders(int size) { + this.headers = new HashMap<>(size); + } + + /** + * Create a HttpHeaders instance with the provided initial headers. + * + * @param headers the map of initial headers + */ + public HttpHeaders(Map headers) { + this.headers = new HashMap<>(headers.size()); + for (final Map.Entry header : headers.entrySet()) { + this.set(header.getKey(), header.getValue()); + } + } + + /** + * Gets the number of headers in the collection. + * + * @return the number of headers in this collection. + */ + public int size() { + return headers.size(); + } + + /** + * Set a header. + * + * if header with same name already exists then the value will be overwritten. + * if value is null and header with provided name already exists then it will be removed. + * + * @param name the name + * @param value the value + * @return this HttpHeaders + */ + public HttpHeaders set(String name, String value) { + final String headerKey = name.toLowerCase(Locale.ROOT); + if (value == null) { + headers.remove(headerKey); + } else { + headers.put(headerKey, new HttpHeader(name, value)); + } + return this; + } + + /** + * Get the header value for the provided header name. Null will be returned if the header + * name isn't found. + * + * @param name the name of the header to look for + * @return The String value of the header, or null if the header isn't found + */ + public String value(String name) { + final HttpHeader header = getHeader(name); + return header == null ? null : header.value(); + } + + /** + * Get the header values for the provided header name. Null will be returned if + * the header name isn't found. + * + * @param name the name of the header to look for + * @return the values of the header, or null if the header isn't found + */ + public String[] values(String name) { + final HttpHeader header = getHeader(name); + return header == null ? null : header.values(); + } + + private HttpHeader getHeader(String headerName) { + final String headerKey = headerName.toLowerCase(Locale.ROOT); + return headers.get(headerKey); + } + + /** + * Get {@link Map} representation of the HttpHeaders collection. + * + * @return the headers as map + */ + public Map toMap() { + final Map result = new HashMap<>(headers.size()); + for (final HttpHeader header : headers.values()) { + result.put(header.name(), header.value()); + } + return result; + } + + @Override + public Iterator iterator() { + return headers.values().iterator(); + } + + @Override + public void serialize(JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { + jsonGenerator.writeObject(toMap()); + } + + @Override + public void serializeWithType(JsonGenerator jsonGenerator, SerializerProvider serializerProvider, TypeSerializer typeSerializer) throws IOException { + serialize(jsonGenerator, serializerProvider); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpRequest.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpRequest.java new file mode 100644 index 0000000000000..f1aeb6172c63c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpRequest.java @@ -0,0 +1,225 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.http; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpMethod; +import reactor.core.publisher.Flux; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; + +/** + * The outgoing Http request. + */ +public class HttpRequest { + private HttpMethod httpMethod; + private URI uri; + private int port; + private HttpHeaders headers; + private Flux body; + + /** + * Create a new HttpRequest instance. + * + * @param httpMethod the HTTP request method + * @param uri the target address to send the request to + */ + public HttpRequest(HttpMethod httpMethod, URI uri, int port, HttpHeaders httpHeaders) { + this.httpMethod = httpMethod; + this.uri = uri; + this.port = port; + this.headers = httpHeaders; + } + + /** + * Create a new HttpRequest instance. + * + * @param httpMethod the HTTP request method + * @param uri the target address to send the request to + */ + public HttpRequest(HttpMethod httpMethod, String uri, int port) throws URISyntaxException { + this.httpMethod = httpMethod; + this.uri = new URI(uri); + this.port = port; + this.headers = new HttpHeaders(); + } + + /** + * Create a new HttpRequest instance. + * + * @param httpMethod the HTTP request method + * @param uri the target address to send the request to + * @param headers the HTTP headers to use with this request + * @param body the request content + */ + public HttpRequest(HttpMethod httpMethod, URI uri, int port, HttpHeaders headers, Flux body) { + this.httpMethod = httpMethod; + this.uri = uri; + this.port = port; + this.headers = headers; + this.body = body; + } + + /** + * Get the request method. + * + * @return the request method + */ + public HttpMethod httpMethod() { + return httpMethod; + } + + /** + * Set the request method. + * + * @param httpMethod the request method + * @return this HttpRequest + */ + public HttpRequest withHttpMethod(HttpMethod httpMethod) { + this.httpMethod = httpMethod; + return this; + } + + /** + * Get the target port. + * + * @return the target port + */ + public int port() { + return port; + } + + /** + * Set the target port to send the request to. + * + * @param port target port + * @return this HttpRequest + */ + public HttpRequest withPort(int port) { + this.port = port; + return this; + } + + /** + * Get the target address. + * + * @return the target address + */ + public URI uri() { + return uri; + } + + /** + * Set the target address to send the request to. + * + * @param uri target address as {@link URI} + * @return this HttpRequest + */ + public HttpRequest withUri(URI uri) { + this.uri = uri; + return this; + } + + /** + * Get the request headers. + * + * @return headers to be sent + */ + public HttpHeaders headers() { + return headers; + } + + /** + * Set the request headers. + * + * @param headers the set of headers + * @return this HttpRequest + */ + public HttpRequest withHeaders(HttpHeaders headers) { + this.headers = headers; + return this; + } + + /** + * Set a request header, replacing any existing value. + * A null for {@code value} will remove the header if one with matching name exists. + * + * @param name the header name + * @param value the header value + * @return this HttpRequest + */ + public HttpRequest withHeader(String name, String value) { + headers.set(name, value); + return this; + } + + /** + * Get the request content. + * + * @return the content to be send + */ + public Flux body() { + return body; + } + + /** + * Set the request content. + * + * @param content the request content + * @return this HttpRequest + */ + public HttpRequest withBody(String content) { + final byte[] bodyBytes = content.getBytes(StandardCharsets.UTF_8); + return withBody(bodyBytes); + } + + /** + * Set the request content. + * The Content-Length header will be set based on the given content's length + * + * @param content the request content + * @return this HttpRequest + */ + public HttpRequest withBody(byte[] content) { + headers.set("Content-Length", String.valueOf(content.length)); + // Unpooled.wrappedBuffer(body) allocates ByteBuf from unpooled heap + return withBody(Flux.defer(() -> Flux.just(Unpooled.wrappedBuffer(content)))); + } + + /** + * Set request content. + *

    + * Caller must set the Content-Length header to indicate the length of the content, + * or use Transfer-Encoding: chunked. + * + * @param content the request content + * @return this HttpRequest + */ + public HttpRequest withBody(Flux content) { + this.body = content; + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpResponse.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpResponse.java new file mode 100644 index 0000000000000..b9a48db61e331 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/HttpResponse.java @@ -0,0 +1,154 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.http; + +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.netty.Connection; + +import java.nio.charset.Charset; + +/** + * The type representing response of {@link HttpRequest}. + */ +public abstract class HttpResponse implements AutoCloseable { + private HttpRequest request; + + /** + * Get the response status code. + * + * @return the response status code + */ + public abstract int statusCode(); + + /** + * Lookup a response header with the provided name. + * + * @param name the name of the header to lookup. + * @return the value of the header, or null if the header doesn't exist in the response. + */ + public abstract String headerValue(String name); + + /** + * Get all response headers. + * + * @return the response headers + */ + public abstract HttpHeaders headers(); + + /** + * Get the publisher emitting response content chunks. + * + *

    + * Returns a stream of the response's body content. Emissions may occur on the + * Netty EventLoop threads which are shared across channels and should not be + * blocked. Blocking should be avoided as much as possible/practical in reactive + * programming but if you do use methods like {@code blockingSubscribe} or {@code blockingGet} + * on the stream then be sure to use {@code subscribeOn} and {@code observeOn} + * before the blocking call. For example: + * + *

    +     * {@code
    +     *   response.body()
    +     *     .map(bb -> bb.limit())
    +     *     .reduce((x,y) -> x + y)
    +     *     .subscribeOn(Schedulers.io())
    +     *     .observeOn(Schedulers.io())
    +     *     .blockingGet();
    +     * }
    +     * 
    + *

    + * The above code is a simplistic example and would probably run fine without + * the `subscribeOn` and `observeOn` but should be considered a template for + * more complex situations. + * + * @return The response's content as a stream of {@link ByteBuf}. + */ + public abstract Flux body(); + + /** + * Get the response content as a byte[]. + * + * @return this response content as a byte[] + */ + public abstract Mono bodyAsByteArray(); + + /** + * Get the response content as a string. + * + * @return This response content as a string + */ + public abstract Mono bodyAsString(); + + /** + * Get the response content as a string. + * + * @param charset the charset to use as encoding + * @return This response content as a string + */ + public abstract Mono bodyAsString(Charset charset); + + /** + * Get the request which resulted in this response. + * + * @return the request which resulted in this response. + */ + public final HttpRequest request() { + return request; + } + + /** + * Sets the request which resulted in this HttpResponse. + * + * @param request the request + * @return this HTTP response + */ + public final HttpResponse withRequest(HttpRequest request) { + this.request = request; + return this; + } + + /** + * Get a new Response object wrapping this response with it's content + * buffered into memory. + * + * @return the new Response object + */ + public HttpResponse buffer() { + return new BufferedHttpResponse(this); + } + + /** + * Closes the response content stream, if any. + */ + @Override + public void close() { + } + + // package private for test purpose + Connection internConnection() { + return null; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/ReactorNettyClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/ReactorNettyClient.java new file mode 100644 index 0000000000000..6776183c37c9f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/http/ReactorNettyClient.java @@ -0,0 +1,198 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.http; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.logging.LogLevel; +import org.reactivestreams.Publisher; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.netty.ByteBufFlux; +import reactor.netty.Connection; +import reactor.netty.NettyOutbound; +import reactor.netty.http.client.HttpClientRequest; +import reactor.netty.http.client.HttpClientResponse; +import reactor.netty.resources.ConnectionProvider; +import reactor.netty.tcp.ProxyProvider; +import reactor.netty.tcp.TcpResources; + +import java.nio.charset.Charset; +import java.util.Objects; +import java.util.function.BiFunction; + +import static com.azure.data.cosmos.internal.http.HttpClientConfig.REACTOR_NETWORK_LOG_CATEGORY; + +/** + * HttpClient that is implemented using reactor-netty. + */ +class ReactorNettyClient implements HttpClient { + + private final Logger logger = LoggerFactory.getLogger(getClass().getSimpleName()); + + private HttpClientConfig httpClientConfig; + private reactor.netty.http.client.HttpClient httpClient; + private ConnectionProvider connectionProvider; + + /** + * Creates ReactorNettyClient with {@link ConnectionProvider}. + */ + ReactorNettyClient(ConnectionProvider connectionProvider, HttpClientConfig httpClientConfig) { + this.connectionProvider = connectionProvider; + this.httpClientConfig = httpClientConfig; + this.httpClient = reactor.netty.http.client.HttpClient.create(connectionProvider); + configureChannelPipelineHandlers(); + } + + private void configureChannelPipelineHandlers() { + this.httpClient = this.httpClient.tcpConfiguration(tcpClient -> { + if (LoggerFactory.getLogger(REACTOR_NETWORK_LOG_CATEGORY).isTraceEnabled()) { + tcpClient = tcpClient.wiretap(REACTOR_NETWORK_LOG_CATEGORY, LogLevel.TRACE); + } + if (this.httpClientConfig.getProxy() != null) { + tcpClient = tcpClient.proxy(typeSpec -> typeSpec.type(ProxyProvider.Proxy.HTTP).address(this.httpClientConfig.getProxy())); + } + return tcpClient; + }); + } + + @Override + public Mono send(final HttpRequest request) { + Objects.requireNonNull(request.httpMethod()); + Objects.requireNonNull(request.uri()); + Objects.requireNonNull(this.httpClientConfig); + + return this.httpClient + .port(request.port()) + .request(HttpMethod.valueOf(request.httpMethod().toString())) + .uri(request.uri().toString()) + .send(bodySendDelegate(request)) + .responseConnection(responseDelegate(request)) + .single(); + } + + /** + * Delegate to send the request content. + * + * @param restRequest the Rest request contains the body to be sent + * @return a delegate upon invocation sets the request body in reactor-netty outbound object + */ + private static BiFunction> bodySendDelegate(final HttpRequest restRequest) { + return (reactorNettyRequest, reactorNettyOutbound) -> { + for (HttpHeader header : restRequest.headers()) { + reactorNettyRequest.header(header.name(), header.value()); + } + if (restRequest.body() != null) { + Flux nettyByteBufFlux = restRequest.body().map(Unpooled::wrappedBuffer); + return reactorNettyOutbound.options(sendOptions -> sendOptions.flushOnEach(false)).send(nettyByteBufFlux); + } else { + return reactorNettyOutbound.options(sendOptions -> sendOptions.flushOnEach(false)); + } + }; + } + + /** + * Delegate to receive response. + * + * @param restRequest the Rest request whose response this delegate handles + * @return a delegate upon invocation setup Rest response object + */ + private static BiFunction> responseDelegate(final HttpRequest restRequest) { + return (reactorNettyResponse, reactorNettyConnection) -> + Mono.just(new ReactorNettyHttpResponse(reactorNettyResponse, reactorNettyConnection).withRequest(restRequest)); + } + + @Override + public void shutdown() { + TcpResources.disposeLoopsAndConnections(); + this.connectionProvider.dispose(); + } + + private static class ReactorNettyHttpResponse extends HttpResponse { + private final HttpClientResponse reactorNettyResponse; + private final Connection reactorNettyConnection; + + ReactorNettyHttpResponse(HttpClientResponse reactorNettyResponse, Connection reactorNettyConnection) { + this.reactorNettyResponse = reactorNettyResponse; + this.reactorNettyConnection = reactorNettyConnection; + } + + @Override + public int statusCode() { + return reactorNettyResponse.status().code(); + } + + @Override + public String headerValue(String name) { + return reactorNettyResponse.responseHeaders().get(name); + } + + @Override + public HttpHeaders headers() { + HttpHeaders headers = new HttpHeaders(reactorNettyResponse.responseHeaders().size()); + reactorNettyResponse.responseHeaders().forEach(e -> headers.set(e.getKey(), e.getValue())); + return headers; + } + + @Override + public Flux body() { + return bodyIntern().doFinally(s -> this.close()); + } + + @Override + public Mono bodyAsByteArray() { + return bodyIntern().aggregate().asByteArray().doFinally(s -> this.close()); + } + + @Override + public Mono bodyAsString() { + return bodyIntern().aggregate().asString().doFinally(s -> this.close()); + } + + @Override + public Mono bodyAsString(Charset charset) { + return bodyIntern().aggregate().asString(charset).doFinally(s -> this.close()); + } + + @Override + public void close() { + if (reactorNettyConnection.channel().eventLoop().inEventLoop()) { + reactorNettyConnection.dispose(); + } else { + reactorNettyConnection.channel().eventLoop().execute(reactorNettyConnection::dispose); + } + } + + private ByteBufFlux bodyIntern() { + return reactorNettyConnection.inbound().receive(); + } + + @Override + Connection internConnection() { + return reactorNettyConnection; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/AggregateDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/AggregateDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..543d03b16cf5e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/AggregateDocumentQueryExecutionContext.java @@ -0,0 +1,150 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.query.aggregation.AggregateOperator; +import com.azure.data.cosmos.internal.query.aggregation.Aggregator; +import com.azure.data.cosmos.internal.query.aggregation.AverageAggregator; +import com.azure.data.cosmos.internal.query.aggregation.CountAggregator; +import com.azure.data.cosmos.internal.query.aggregation.MaxAggregator; +import com.azure.data.cosmos.internal.query.aggregation.MinAggregator; +import com.azure.data.cosmos.internal.query.aggregation.SumAggregator; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +public class AggregateDocumentQueryExecutionContext implements IDocumentQueryExecutionComponent{ + + private IDocumentQueryExecutionComponent component; + private Aggregator aggregator; + private ConcurrentMap queryMetricsMap = new ConcurrentHashMap<>(); + + //QueryInfo class used in PipelinedDocumentQueryExecutionContext returns a Collection of AggregateOperators + //while Multiple aggregates are allowed in queries targeted at a single partition, only a single aggregate is allowed in x-partition queries (currently) + public AggregateDocumentQueryExecutionContext (IDocumentQueryExecutionComponent component, Collection aggregateOperators) { + + this.component = component; + AggregateOperator aggregateOperator = aggregateOperators.iterator().next(); + + switch (aggregateOperator) { + case Average: + this.aggregator = new AverageAggregator(); + break; + case Count: + this.aggregator = new CountAggregator(); + break; + case Max: + this.aggregator = new MaxAggregator(); + break; + case Min: + this.aggregator = new MinAggregator(); + break; + case Sum: + this.aggregator = new SumAggregator(); + break; + default: + throw new IllegalStateException("Unexpected value: " + aggregateOperator.toString()); + } + } + + @SuppressWarnings("unchecked") + @Override + public Flux> drainAsync(int maxPageSize) { + + return this.component.drainAsync(maxPageSize) + .collectList() + .map( superList -> { + + double requestCharge = 0; + List aggregateResults = new ArrayList(); + HashMap headers = new HashMap(); + + for(FeedResponse page : superList) { + + if (page.results().size() == 0) { + headers.put(HttpConstants.HttpHeaders.REQUEST_CHARGE, Double.toString(requestCharge)); + FeedResponse frp = BridgeInternal.createFeedResponse(aggregateResults, headers); + return (FeedResponse) frp; + } + + Document doc = ((Document)page.results().get(0)); + requestCharge += page.requestCharge(); + QueryItem values = new QueryItem(doc.toJson()); + this.aggregator.aggregate(values.getItem()); + for(String key : BridgeInternal.queryMetricsFromFeedResponse(page).keySet()) { + if (queryMetricsMap.containsKey(key)) { + QueryMetrics qm = BridgeInternal.queryMetricsFromFeedResponse(page).get(key); + queryMetricsMap.get(key).add(qm); + } else { + queryMetricsMap.put(key, BridgeInternal.queryMetricsFromFeedResponse(page).get(key)); + } + } + } + + if (this.aggregator.getResult() == null || !this.aggregator.getResult().equals(Undefined.Value())) { + Document aggregateDocument = new Document(); + BridgeInternal.setProperty(aggregateDocument, Constants.Properties.AGGREGATE, this.aggregator.getResult()); + aggregateResults.add(aggregateDocument); + } + + headers.put(HttpConstants.HttpHeaders.REQUEST_CHARGE, Double.toString(requestCharge)); + FeedResponse frp = BridgeInternal.createFeedResponse(aggregateResults, headers); + if(!queryMetricsMap.isEmpty()) { + for(String key: queryMetricsMap.keySet()) { + BridgeInternal.putQueryMetricsIntoMap(frp, key, queryMetricsMap.get(key)); + } + } + return (FeedResponse) frp; + }).flux(); + } + + public static Flux> createAsync( + Function>> createSourceComponentFunction, + Collection aggregates, + String continuationToken) { + + return createSourceComponentFunction + .apply(continuationToken) + .map( component -> { return new AggregateDocumentQueryExecutionContext(component, aggregates);}); + } + + public IDocumentQueryExecutionComponent getComponent() { + return this.component; + } + +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/CompositeContinuationToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/CompositeContinuationToken.java new file mode 100644 index 0000000000000..c7c8f64d2b0d9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/CompositeContinuationToken.java @@ -0,0 +1,120 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.routing.Range; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public final class CompositeContinuationToken extends JsonSerializable { + private static final String TokenPropertyName = "token"; + private static final String RangePropertyName = "range"; + private static final Logger logger = LoggerFactory.getLogger(CompositeContinuationToken.class); + + public CompositeContinuationToken(String token, Range range) { + // token is allowed to be null + if (range == null) { + throw new IllegalArgumentException("range must not be null."); + } + + this.setToken(token); + this.setRange(range); + } + + private CompositeContinuationToken(String serializedCompositeContinuationToken) { + super(serializedCompositeContinuationToken); + } + + public static boolean tryParse(String serializedCompositeContinuationToken, + ValueHolder outCompositeContinuationToken) { + boolean parsed; + try { + CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken( + serializedCompositeContinuationToken); + compositeContinuationToken.getToken(); + + Range range = compositeContinuationToken.getRange(); + if (range == null) { + throw new IllegalArgumentException("range must not be null."); + } + + range.getMax(); + range.getMin(); + range.isEmpty(); + range.isMaxInclusive(); + range.isMinInclusive(); + range.isSingleValue(); + + outCompositeContinuationToken.v = compositeContinuationToken; + parsed = true; + } catch (Exception ex) { + logger.debug( + "Received exception {} when trying to parse: {}", + ex.getMessage(), + serializedCompositeContinuationToken); + parsed = false; + outCompositeContinuationToken.v = null; + } + + return parsed; + } + + /** + * @return the token + */ + public String getToken() { + return super.getString(TokenPropertyName); + } + + /** + * @return the range + */ + public Range getRange() { + return new Range(super.getString(RangePropertyName)); + } + + /** + * @param token + * the token to set + */ + private void setToken(String token) { + BridgeInternal.setProperty(this, TokenPropertyName, token); + } + + /** + * @param range + * the range to set + */ + private void setRange(Range range) { + /* TODO: Don't stringify the range */ + BridgeInternal.setProperty(this, RangePropertyName, range.toString()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DefaultDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DefaultDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..f2f18806e2e08 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DefaultDocumentQueryExecutionContext.java @@ -0,0 +1,267 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.BackoffRetryUtility; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.InvalidPartitionExceptionRetryPolicy; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.PartitionKeyRangeGoneRetryPolicy; +import com.azure.data.cosmos.internal.PathsHelper; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.caches.IPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.query.metrics.ClientSideMetrics; +import com.azure.data.cosmos.internal.query.metrics.FetchExecutionRangeAccumulator; +import com.azure.data.cosmos.internal.query.metrics.SchedulingStopwatch; +import com.azure.data.cosmos.internal.query.metrics.SchedulingTimeSpan; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import com.azure.data.cosmos.internal.routing.Range; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static com.azure.data.cosmos.CommonsBridgeInternal.partitionKeyRangeIdInternal; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class DefaultDocumentQueryExecutionContext extends DocumentQueryExecutionContextBase { + + private boolean isContinuationExpected; + private volatile int retries = -1; + + private final SchedulingStopwatch fetchSchedulingMetrics; + private final FetchExecutionRangeAccumulator fetchExecutionRangeAccumulator; + private static final String DEFAULT_PARTITION_KEY_RANGE_ID = "0"; + + public DefaultDocumentQueryExecutionContext(IDocumentQueryClient client, ResourceType resourceTypeEnum, + Class resourceType, SqlQuerySpec query, FeedOptions feedOptions, String resourceLink, + UUID correlatedActivityId, boolean isContinuationExpected) { + + super(client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + false, + correlatedActivityId); + + this.isContinuationExpected = isContinuationExpected; + this.fetchSchedulingMetrics = new SchedulingStopwatch(); + this.fetchSchedulingMetrics.ready(); + this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(DEFAULT_PARTITION_KEY_RANGE_ID); + } + + protected PartitionKeyInternal getPartitionKeyInternal() { + return this.feedOptions.partitionKey() == null ? null : feedOptions.partitionKey().getInternalPartitionKey(); + } + + @Override + public Flux> executeAsync() { + + if (feedOptions == null) { + feedOptions = new FeedOptions(); + } + + FeedOptions newFeedOptions = new FeedOptions(feedOptions); + + // We can not go to backend with the composite continuation token, + // but we still need the gateway for the query plan. + // The workaround is to try and parse the continuation token as a composite continuation token. + // If it is, then we send the query to the gateway with max degree of parallelism to force getting back the query plan + + String originalContinuation = newFeedOptions.requestContinuation(); + + if (isClientSideContinuationToken(originalContinuation)) { + // At this point we know we want back a query plan + newFeedOptions.requestContinuation(null); + newFeedOptions.maxDegreeOfParallelism(Integer.MAX_VALUE); + } + + int maxPageSize = newFeedOptions.maxItemCount() != null ? newFeedOptions.maxItemCount() : Constants.Properties.DEFAULT_MAX_PAGE_SIZE; + + BiFunction createRequestFunc = (continuationToken, pageSize) -> this.createRequestAsync(continuationToken, pageSize); + + // TODO: clean up if we want to use single vs observable. + Function>> executeFunc = executeInternalAsyncFunc(); + + return Paginator + .getPaginatedQueryResultAsObservable(newFeedOptions, createRequestFunc, executeFunc, resourceType, maxPageSize); + } + + public Mono> getTargetPartitionKeyRanges(String resourceId, List> queryRanges) { + // TODO: FIXME this needs to be revisited + + Range r = new Range<>("", "FF", true, false); + return client.getPartitionKeyRangeCache().tryGetOverlappingRangesAsync(resourceId, r, false, null); + } + + protected Function>> executeInternalAsyncFunc() { + RxCollectionCache collectionCache = this.client.getCollectionCache(); + IPartitionKeyRangeCache partitionKeyRangeCache = this.client.getPartitionKeyRangeCache(); + IDocumentClientRetryPolicy retryPolicyInstance = this.client.getResetSessionTokenRetryPolicy().getRequestPolicy(); + + retryPolicyInstance = new InvalidPartitionExceptionRetryPolicy(collectionCache, retryPolicyInstance, resourceLink, feedOptions); + if (super.resourceTypeEnum.isPartitioned()) { + retryPolicyInstance = new PartitionKeyRangeGoneRetryPolicy( + collectionCache, + partitionKeyRangeCache, + PathsHelper.getCollectionPath(super.resourceLink), + retryPolicyInstance, + feedOptions); + } + + final IDocumentClientRetryPolicy finalRetryPolicyInstance = retryPolicyInstance; + + return req -> { + finalRetryPolicyInstance.onBeforeSendRequest(req); + this.fetchExecutionRangeAccumulator.beginFetchRange(); + this.fetchSchedulingMetrics.start(); + return BackoffRetryUtility.executeRetry(() -> { + ++this.retries; + return executeRequestAsync(req); + }, finalRetryPolicyInstance).flux() + .map(tFeedResponse -> { + this.fetchSchedulingMetrics.stop(); + this.fetchExecutionRangeAccumulator.endFetchRange(tFeedResponse.activityId(), + tFeedResponse.results().size(), + this.retries); + ImmutablePair schedulingTimeSpanMap = + new ImmutablePair<>(DEFAULT_PARTITION_KEY_RANGE_ID, this.fetchSchedulingMetrics.getElapsedTime()); + if (!StringUtils.isEmpty(tFeedResponse.responseHeaders().get(HttpConstants.HttpHeaders.QUERY_METRICS))) { + QueryMetrics qm = + BridgeInternal.createQueryMetricsFromDelimitedStringAndClientSideMetrics(tFeedResponse.responseHeaders() + .get(HttpConstants.HttpHeaders.QUERY_METRICS), + new ClientSideMetrics(this.retries, + tFeedResponse.requestCharge(), + this.fetchExecutionRangeAccumulator.getExecutionRanges(), + Arrays.asList(schedulingTimeSpanMap)), + tFeedResponse.activityId()); + BridgeInternal.putQueryMetricsIntoMap(tFeedResponse, DEFAULT_PARTITION_KEY_RANGE_ID, qm); + } + return tFeedResponse; + }); + }; + } + + private Mono> executeOnceAsync(IDocumentClientRetryPolicy retryPolicyInstance, String continuationToken) { + // Don't reuse request, as the rest of client SDK doesn't reuse requests between retries. + // The code leaves some temporary garbage in request (in RequestContext etc.), + // which shold be erased during retries. + + RxDocumentServiceRequest request = this.createRequestAsync(continuationToken, this.feedOptions.maxItemCount()); + if (retryPolicyInstance != null) { + retryPolicyInstance.onBeforeSendRequest(request); + } + + if (!Strings.isNullOrEmpty(request.getHeaders().get(HttpConstants.HttpHeaders.PARTITION_KEY)) + || !request.getResourceType().isPartitioned()) { + return this.executeRequestAsync(request); + } + + + // TODO: remove this as partition key range id is not relevant + // TODO; has to be rx async + //CollectionCache collectionCache = this.client.getCollectionCache(); + + // TODO: has to be rx async + //DocumentCollection collection = + // collectionCache.resolveCollection(request); + + // TODO: this code is not relevant because partition key range id should not be exposed + // if (!Strings.isNullOrEmpty(super.getPartitionKeyId())) + // { + // request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, base.PartitionKeyRangeId)); + // return await this.ExecuteRequestAsync(request); + // } + + request.UseGatewayMode = true; + return this.executeRequestAsync(request); + } + + public RxDocumentServiceRequest createRequestAsync(String continuationToken, Integer maxPageSize) { + + // TODO this should be async + Map requestHeaders = this.createCommonHeadersAsync( + this.getFeedOptions(continuationToken, maxPageSize)); + + // TODO: add support for simple continuation for single partition query + //requestHeaders.put(keyHttpConstants.HttpHeaders.IsContinuationExpected, isContinuationExpected.ToString()) + + RxDocumentServiceRequest request = this.createDocumentServiceRequest( + requestHeaders, + this.query, + this.getPartitionKeyInternal()); + + if (!StringUtils.isEmpty(partitionKeyRangeIdInternal(feedOptions))) { + request.routeTo(new PartitionKeyRangeIdentity(partitionKeyRangeIdInternal(feedOptions))); + } + + return request; + } + + private static boolean isClientSideContinuationToken(String continuationToken) { + if (continuationToken != null) { + ValueHolder outCompositeContinuationToken = new ValueHolder(); + if (CompositeContinuationToken.tryParse(continuationToken, outCompositeContinuationToken)) { + return true; + } + + ValueHolder outOrderByContinuationToken = new ValueHolder(); + if (OrderByContinuationToken.tryParse(continuationToken, outOrderByContinuationToken)) { + return true; + } + + ValueHolder outTakeContinuationToken = new ValueHolder(); + if (TakeContinuationToken.tryParse(continuationToken, outTakeContinuationToken)) { + return true; + } + } + + return false; + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentProducer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentProducer.java new file mode 100644 index 0000000000000..e3cc355c71255 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentProducer.java @@ -0,0 +1,271 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.ObservableHelper; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.QueryMetricsConstants; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.query.metrics.ClientSideMetrics; +import com.azure.data.cosmos.internal.query.metrics.FetchExecutionRangeAccumulator; +import com.azure.data.cosmos.internal.query.metrics.SchedulingStopwatch; +import com.azure.data.cosmos.internal.query.metrics.SchedulingTimeSpan; +import com.azure.data.cosmos.internal.routing.Range; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +class DocumentProducer { + private static final Logger logger = LoggerFactory.getLogger(DocumentProducer.class); + private int retries; + + class DocumentProducerFeedResponse { + FeedResponse pageResult; + PartitionKeyRange sourcePartitionKeyRange; + + DocumentProducerFeedResponse(FeedResponse pageResult) { + this.pageResult = pageResult; + this.sourcePartitionKeyRange = DocumentProducer.this.targetRange; + populatePartitionedQueryMetrics(); + } + + DocumentProducerFeedResponse(FeedResponse pageResult, PartitionKeyRange pkr) { + this.pageResult = pageResult; + this.sourcePartitionKeyRange = pkr; + populatePartitionedQueryMetrics(); + } + + void populatePartitionedQueryMetrics() { + String queryMetricsDelimitedString = pageResult.responseHeaders().get(HttpConstants.HttpHeaders.QUERY_METRICS); + if (!StringUtils.isEmpty(queryMetricsDelimitedString)) { + queryMetricsDelimitedString += String.format(";%s=%.2f", QueryMetricsConstants.RequestCharge, pageResult.requestCharge()); + ImmutablePair schedulingTimeSpanMap = + new ImmutablePair<>(targetRange.id(), fetchSchedulingMetrics.getElapsedTime()); + + QueryMetrics qm =BridgeInternal.createQueryMetricsFromDelimitedStringAndClientSideMetrics(queryMetricsDelimitedString, + new ClientSideMetrics(retries, + pageResult.requestCharge(), + fetchExecutionRangeAccumulator.getExecutionRanges(), + Arrays.asList(schedulingTimeSpanMap) + ), pageResult.activityId()); + BridgeInternal.putQueryMetricsIntoMap(pageResult, targetRange.id(), qm); + } + } + } + + protected final IDocumentQueryClient client; + protected final String collectionRid; + protected final FeedOptions feedOptions; + protected final Class resourceType; + protected final PartitionKeyRange targetRange; + protected final String collectionLink; + protected final TriFunction createRequestFunc; + protected final Function>> executeRequestFuncWithRetries; + protected final Callable createRetryPolicyFunc; + protected final int pageSize; + protected final UUID correlatedActivityId; + public int top; + private volatile String lastResponseContinuationToken; + private final SchedulingStopwatch fetchSchedulingMetrics; + private SchedulingStopwatch moveNextSchedulingMetrics; + private final FetchExecutionRangeAccumulator fetchExecutionRangeAccumulator; + + public DocumentProducer( + IDocumentQueryClient client, + String collectionResourceId, + FeedOptions feedOptions, + TriFunction createRequestFunc, + Function>> executeRequestFunc, + PartitionKeyRange targetRange, + String collectionLink, + Callable createRetryPolicyFunc, + Class resourceType , + UUID correlatedActivityId, + int initialPageSize, // = -1, + String initialContinuationToken, + int top) { + + this.client = client; + this.collectionRid = collectionResourceId; + + this.createRequestFunc = createRequestFunc; + + this.fetchSchedulingMetrics = new SchedulingStopwatch(); + this.fetchSchedulingMetrics.ready(); + this.fetchExecutionRangeAccumulator = new FetchExecutionRangeAccumulator(targetRange.id()); + + this.executeRequestFuncWithRetries = request -> { + retries = -1; + this.fetchSchedulingMetrics.start(); + this.fetchExecutionRangeAccumulator.beginFetchRange(); + IDocumentClientRetryPolicy retryPolicy = null; + if (createRetryPolicyFunc != null) { + try { + retryPolicy = createRetryPolicyFunc.call(); + } catch (Exception e) { + return Flux.error(e); + } + retryPolicy.onBeforeSendRequest(request); + } + return ObservableHelper.inlineIfPossibleAsObs( + () -> { + ++retries; + return executeRequestFunc.apply(request); + }, retryPolicy); + }; + + this.correlatedActivityId = correlatedActivityId; + + this.feedOptions = feedOptions != null ? feedOptions : new FeedOptions(); + this.feedOptions.requestContinuation(initialContinuationToken); + this.lastResponseContinuationToken = initialContinuationToken; + this.resourceType = resourceType; + this.targetRange = targetRange; + this.collectionLink = collectionLink; + this.createRetryPolicyFunc = createRetryPolicyFunc; + this.pageSize = initialPageSize; + this.top = top; + } + + public Flux produceAsync() { + BiFunction sourcePartitionCreateRequestFunc = + (token, maxItemCount) -> createRequestFunc.apply(targetRange, token, maxItemCount); + Flux> obs = Paginator + .getPaginatedQueryResultAsObservable( + feedOptions.requestContinuation(), + sourcePartitionCreateRequestFunc, + executeRequestFuncWithRetries, + resourceType, + top, + pageSize) + .map(rsp -> { + lastResponseContinuationToken = rsp.continuationToken(); + this.fetchExecutionRangeAccumulator.endFetchRange(rsp.activityId(), + rsp.results().size(), + this.retries); + this.fetchSchedulingMetrics.stop(); + return rsp;}); + + return splitProof(obs.map(DocumentProducerFeedResponse::new)); + } + + private Flux splitProof(Flux sourceFeedResponseObservable) { + return sourceFeedResponseObservable.onErrorResume( t -> { + CosmosClientException dce = Utils.as(t, CosmosClientException.class); + if (dce == null || !isSplit(dce)) { + logger.error("Unexpected failure", t); + return Flux.error(t); + } + + // we are dealing with Split + logger.info("DocumentProducer handling a partition split in [{}], detail:[{}]", targetRange, dce); + Mono> replacementRangesObs = getReplacementRanges(targetRange.toRange()); + + // Since new DocumentProducers are instantiated for the new replacement ranges, if for the new + // replacement partitions split happens the corresponding DocumentProducer can recursively handle splits. + // so this is resilient to split on splits. + Flux> replacementProducers = replacementRangesObs.flux().flatMap( + partitionKeyRanges -> { + if (logger.isDebugEnabled()) { + logger.info("Cross Partition Query Execution detected partition [{}] split into [{}] partitions," + + " last continuation token is [{}].", + targetRange.toJson(), + partitionKeyRanges.stream() + .map(JsonSerializable::toJson).collect(Collectors.joining(", ")), + lastResponseContinuationToken); + } + return Flux.fromIterable(createReplacingDocumentProducersOnSplit(partitionKeyRanges)); + }); + + return produceOnSplit(replacementProducers); + }); + } + + protected Flux produceOnSplit(Flux> replacingDocumentProducers) { + return replacingDocumentProducers.flatMap(DocumentProducer::produceAsync, 1); + } + + private List> createReplacingDocumentProducersOnSplit(List partitionKeyRanges) { + + List> replacingDocumentProducers = new ArrayList<>(partitionKeyRanges.size()); + for(PartitionKeyRange pkr: partitionKeyRanges) { + replacingDocumentProducers.add(createChildDocumentProducerOnSplit(pkr, lastResponseContinuationToken)); + } + return replacingDocumentProducers; + } + + protected DocumentProducer createChildDocumentProducerOnSplit( + PartitionKeyRange targetRange, + String initialContinuationToken) { + + return new DocumentProducer( + client, + collectionRid, + feedOptions, + createRequestFunc, + executeRequestFuncWithRetries, + targetRange, + collectionLink, + null, + resourceType , + correlatedActivityId, + pageSize, + initialContinuationToken, + top); + } + + private Mono> getReplacementRanges(Range range) { + return client.getPartitionKeyRangeCache().tryGetOverlappingRangesAsync(collectionRid, range, true, feedOptions.properties()); + } + + private boolean isSplit(CosmosClientException e) { + return Exceptions.isPartitionSplit(e); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextBase.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextBase.java new file mode 100644 index 0000000000000..61cb796dde8f5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextBase.java @@ -0,0 +1,293 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ReplicatedResourceClientUtils; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RuntimeConstants.MediaTypes; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public abstract class DocumentQueryExecutionContextBase +implements IDocumentQueryExecutionContext { + + protected ResourceType resourceTypeEnum; + protected String resourceLink; + protected IDocumentQueryClient client; + protected Class resourceType; + protected FeedOptions feedOptions; + protected SqlQuerySpec query; + protected UUID correlatedActivityId; + protected boolean shouldExecuteQueryRequest; + + protected DocumentQueryExecutionContextBase(IDocumentQueryClient client, ResourceType resourceTypeEnum, + Class resourceType, SqlQuerySpec query, FeedOptions feedOptions, String resourceLink, + boolean getLazyFeedResponse, UUID correlatedActivityId) { + + // TODO: validate args are not null: client and feedOption should not be null + this.client = client; + this.resourceTypeEnum = resourceTypeEnum; + this.resourceType = resourceType; + this.query = query; + this.shouldExecuteQueryRequest = (query != null); + this.feedOptions = feedOptions; + this.resourceLink = resourceLink; + // this.getLazyFeedResponse = getLazyFeedResponse; + this.correlatedActivityId = correlatedActivityId; + } + + @Override + abstract public Flux> executeAsync(); + + public RxDocumentServiceRequest createDocumentServiceRequest(Map requestHeaders, + SqlQuerySpec querySpec, + PartitionKeyInternal partitionKey) { + + RxDocumentServiceRequest request = querySpec != null + ? this.createQueryDocumentServiceRequest(requestHeaders, querySpec) + : this.createReadFeedDocumentServiceRequest(requestHeaders); + + this.populatePartitionKeyInfo(request, partitionKey); + + return request; + } + + protected RxDocumentServiceRequest createDocumentServiceRequest(Map requestHeaders, + SqlQuerySpec querySpec, + PartitionKeyRange targetRange, + String collectionRid) { + RxDocumentServiceRequest request = querySpec != null + ? this.createQueryDocumentServiceRequest(requestHeaders, querySpec) + : this.createReadFeedDocumentServiceRequest(requestHeaders); + + this.populatePartitionKeyRangeInfo(request, targetRange, collectionRid); + + return request; + } + + public Mono> executeRequestAsync(RxDocumentServiceRequest request) { + return (this.shouldExecuteQueryRequest ? this.executeQueryRequestAsync(request) + : this.executeReadFeedRequestAsync(request)); + } + + public Mono> executeQueryRequestAsync(RxDocumentServiceRequest request) { + return this.getFeedResponse(this.executeQueryRequestInternalAsync(request)); + } + + public Mono> executeReadFeedRequestAsync(RxDocumentServiceRequest request) { + return this.getFeedResponse(this.client.readFeedAsync(request)); + } + + protected Mono> getFeedResponse(Mono response) { + return response.map(resp -> BridgeInternal.toFeedResponsePage(resp, resourceType)); + } + + public FeedOptions getFeedOptions(String continuationToken, Integer maxPageSize) { + FeedOptions options = new FeedOptions(this.feedOptions); + options.requestContinuation(continuationToken); + options.maxItemCount(maxPageSize); + return options; + } + + private Mono executeQueryRequestInternalAsync(RxDocumentServiceRequest request) { + return this.client.executeQueryAsync(request); + } + + public Map createCommonHeadersAsync(FeedOptions feedOptions) { + Map requestHeaders = new HashMap<>(); + + ConsistencyLevel defaultConsistencyLevel = this.client.getDefaultConsistencyLevelAsync(); + ConsistencyLevel desiredConsistencyLevel = this.client.getDesiredConsistencyLevelAsync(); + if (!Strings.isNullOrEmpty(feedOptions.sessionToken()) + && !ReplicatedResourceClientUtils.isReadingFromMaster(this.resourceTypeEnum, OperationType.ReadFeed)) { + if (defaultConsistencyLevel == ConsistencyLevel.SESSION + || (desiredConsistencyLevel == ConsistencyLevel.SESSION)) { + // Query across partitions is not supported today. Master resources (for e.g., + // database) + // can span across partitions, whereas server resources (viz: collection, + // document and attachment) + // don't span across partitions. Hence, session token returned by one partition + // should not be used + // when quering resources from another partition. + // Since master resources can span across partitions, don't send session token + // to the backend. + // As master resources are sync replicated, we should always get consistent + // query result for master resources, + // irrespective of the chosen replica. + // For server resources, which don't span partitions, specify the session token + // for correct replica to be chosen for servicing the query result. + requestHeaders.put(HttpConstants.HttpHeaders.SESSION_TOKEN, feedOptions.sessionToken()); + } + } + + requestHeaders.put(HttpConstants.HttpHeaders.CONTINUATION, feedOptions.requestContinuation()); + requestHeaders.put(HttpConstants.HttpHeaders.IS_QUERY, Strings.toString(true)); + + // Flow the pageSize only when we are not doing client eval + if (feedOptions.maxItemCount() != null && feedOptions.maxItemCount() > 0) { + requestHeaders.put(HttpConstants.HttpHeaders.PAGE_SIZE, Strings.toString(feedOptions.maxItemCount())); + } + + if (feedOptions.enableCrossPartitionQuery() != null) { + + requestHeaders.put(HttpConstants.HttpHeaders.ENABLE_CROSS_PARTITION_QUERY, + Strings.toString(feedOptions.enableCrossPartitionQuery())); + } + + if (feedOptions.maxDegreeOfParallelism() != 0) { + requestHeaders.put(HttpConstants.HttpHeaders.PARALLELIZE_CROSS_PARTITION_QUERY, Strings.toString(true)); + } + + if (this.feedOptions.enableCrossPartitionQuery() != null) { + requestHeaders.put(HttpConstants.HttpHeaders.ENABLE_SCAN_IN_QUERY, + Strings.toString(this.feedOptions.enableCrossPartitionQuery())); + } + + if (this.feedOptions.responseContinuationTokenLimitInKb() > 0) { + requestHeaders.put(HttpConstants.HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB, + Strings.toString(feedOptions.responseContinuationTokenLimitInKb())); + } + + if (desiredConsistencyLevel != null) { + requestHeaders.put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, desiredConsistencyLevel.toString()); + } + + if(feedOptions.populateQueryMetrics()){ + requestHeaders.put(HttpConstants.HttpHeaders.POPULATE_QUERY_METRICS, String.valueOf(feedOptions.populateQueryMetrics())); + } + + return requestHeaders; + } + + private void populatePartitionKeyInfo(RxDocumentServiceRequest request, PartitionKeyInternal partitionKey) { + if (request == null) { + throw new NullPointerException("request"); + } + + if (this.resourceTypeEnum.isPartitioned()) { + if (partitionKey != null) { + request.getHeaders().put(HttpConstants.HttpHeaders.PARTITION_KEY, partitionKey.toJson()); + } + } + } + + public void populatePartitionKeyRangeInfo(RxDocumentServiceRequest request, PartitionKeyRange range, + String collectionRid) { + if (request == null) { + throw new NullPointerException("request"); + } + + if (range == null) { + throw new NullPointerException("range"); + } + + if (this.resourceTypeEnum.isPartitioned()) { + request.routeTo(new PartitionKeyRangeIdentity(collectionRid, range.id())); + } + } + + private RxDocumentServiceRequest createQueryDocumentServiceRequest(Map requestHeaders, + SqlQuerySpec querySpec) { + RxDocumentServiceRequest executeQueryRequest; + + String queryText; + switch (this.client.getQueryCompatibilityMode()) { + case SqlQuery: + SqlParameterList params = querySpec.parameters(); + Utils.checkStateOrThrow(params != null && params.size() > 0, "query.parameters", + "Unsupported argument in query compatibility mode '%s'", + this.client.getQueryCompatibilityMode().toString()); + + executeQueryRequest = RxDocumentServiceRequest.create(OperationType.SqlQuery, this.resourceTypeEnum, + this.resourceLink, + // AuthorizationTokenType.PrimaryMasterKey, + requestHeaders); + + executeQueryRequest.getHeaders().put(HttpConstants.HttpHeaders.CONTENT_TYPE, MediaTypes.JSON); + queryText = querySpec.queryText(); + break; + + case Default: + case Query: + default: + executeQueryRequest = RxDocumentServiceRequest.create(OperationType.Query, this.resourceTypeEnum, + this.resourceLink, + // AuthorizationTokenType.PrimaryMasterKey, + requestHeaders); + + executeQueryRequest.getHeaders().put(HttpConstants.HttpHeaders.CONTENT_TYPE, MediaTypes.QUERY_JSON); + queryText = querySpec.toJson(); + break; + } + + try { + executeQueryRequest.setContentBytes(queryText.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + // TODO: exception should be handled differently + e.printStackTrace(); + } + + return executeQueryRequest; + } + + private RxDocumentServiceRequest createReadFeedDocumentServiceRequest(Map requestHeaders) { + if (this.resourceTypeEnum == ResourceType.Database || this.resourceTypeEnum == ResourceType.Offer) { + return RxDocumentServiceRequest.create(OperationType.ReadFeed, null, this.resourceTypeEnum, + // TODO: we may want to add a constructor to RxDocumentRequest supporting authorization type similar to .net + // AuthorizationTokenType.PrimaryMasterKey, + requestHeaders); + } else { + return RxDocumentServiceRequest.create(OperationType.ReadFeed, this.resourceTypeEnum, this.resourceLink, + // TODO: we may want to add a constructor to RxDocumentRequest supporting authorization type similar to .net + // AuthorizationTokenType.PrimaryMasterKey, + requestHeaders); + } + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextFactory.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextFactory.java new file mode 100644 index 0000000000000..bef8a6b7fdc31 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/DocumentQueryExecutionContextFactory.java @@ -0,0 +1,185 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.UUID; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class DocumentQueryExecutionContextFactory { + + private final static int PageSizeFactorForTop = 5; + + private static Mono resolveCollection(IDocumentQueryClient client, SqlQuerySpec query, + ResourceType resourceTypeEnum, String resourceLink) { + + RxCollectionCache collectionCache = client.getCollectionCache(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create( + OperationType.Query, + resourceTypeEnum, + resourceLink, null + // TODO AuthorizationTokenType.INVALID) + ); //this request doesnt actually go to server + return collectionCache.resolveCollectionAsync(request); + } + + public static Flux> createDocumentQueryExecutionContextAsync( + IDocumentQueryClient client, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + boolean isContinuationExpected, + UUID correlatedActivityId) { + + // return proxy + Flux collectionObs = Flux.empty(); + + if (resourceTypeEnum.isCollectionChild()) { + collectionObs = resolveCollection(client, query, resourceTypeEnum, resourceLink).flux(); + } + + // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext + // which will be used to send the query to GATEWAY and on getting 400(bad request) with 1004(cross parition query not servable), we initialize it with + // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from GATEWAY). + + Flux> proxyQueryExecutionContext = + collectionObs.flatMap(collection -> { + if (feedOptions != null && feedOptions.partitionKey() != null && feedOptions.partitionKey().equals(PartitionKey.None)) { + feedOptions.partitionKey(BridgeInternal.getPartitionKey(BridgeInternal.getNonePartitionKey(collection.getPartitionKey()))); + } + return ProxyDocumentQueryExecutionContext.createAsync( + client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + collection, + isContinuationExpected, + correlatedActivityId); + }).switchIfEmpty(ProxyDocumentQueryExecutionContext.createAsync( + client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + null, + isContinuationExpected, + correlatedActivityId)); + + return proxyQueryExecutionContext; + } + + public static Flux> createSpecializedDocumentQueryExecutionContextAsync( + IDocumentQueryClient client, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + boolean isContinuationExpected, + PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, + List targetRanges, + String collectionRid, + UUID correlatedActivityId) { + + int initialPageSize = Utils.getValueOrDefault(feedOptions.maxItemCount(), ParallelQueryConfig.ClientInternalPageSize); + + BadRequestException validationError = Utils.checkRequestOrReturnException + (initialPageSize > 0, "MaxItemCount", "INVALID MaxItemCount %s", initialPageSize); + if (validationError != null) { + return Flux.error(validationError); + } + + QueryInfo queryInfo = partitionedQueryExecutionInfo.getQueryInfo(); + + boolean getLazyFeedResponse = queryInfo.hasTop(); + + // We need to compute the optimal initial page size for order-by queries + if (queryInfo.hasOrderBy()) { + int top; + if (queryInfo.hasTop() && (top = partitionedQueryExecutionInfo.getQueryInfo().getTop()) > 0) { + int pageSizeWithTop = Math.min( + (int)Math.ceil(top / (double)targetRanges.size()) * PageSizeFactorForTop, + top); + + if (initialPageSize > 0) { + initialPageSize = Math.min(pageSizeWithTop, initialPageSize); + } + else { + initialPageSize = pageSizeWithTop; + } + } + // TODO: do not support continuation in string format right now + // else if (isContinuationExpected) + // { + // if (initialPageSize < 0) + // { + // initialPageSize = (int)Math.Max(feedOptions.MaxBufferedItemCount, ParallelQueryConfig.GetConfig().DefaultMaximumBufferSize); + // } + // + // initialPageSize = Math.Min( + // (int)Math.Ceiling(initialPageSize / (double)targetRanges.Count) * PageSizeFactorForTop, + // initialPageSize); + // } + } + + return PipelinedDocumentQueryExecutionContext.createAsync( + client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + collectionRid, + partitionedQueryExecutionInfo, + targetRanges, + initialPageSize, + isContinuationExpected, + getLazyFeedResponse, + correlatedActivityId); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ExceptionHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ExceptionHelper.java new file mode 100644 index 0000000000000..b34c251fc7643 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ExceptionHelper.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import java.util.concurrent.ExecutionException; + +class ExceptionHelper { + + private ExceptionHelper() {} + + public static Throwable unwrap(Throwable e) { + if (e.getCause() == null) { + return e; + } + if (e instanceof IllegalStateException || e instanceof ExecutionException) { + return unwrap(e.getCause()); + } + return e; + } + + public static Throwable unwrapIllegalStateException(Exception e) { + if (e instanceof IllegalStateException && e.getCause() != null) { + return e.getCause(); + } + return e; + } + + public static Throwable unwrapExecutionException(Exception e) { + if (e instanceof RuntimeException && e.getCause() != null) { + return e.getCause(); + } + return e; + } + + public static RuntimeException toRuntimeException(Throwable e) { + if (e instanceof RuntimeException) { + return (RuntimeException) e; + } + throw new IllegalStateException(e); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Fetcher.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Fetcher.java new file mode 100644 index 0000000000000..73ccbd5b52066 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Fetcher.java @@ -0,0 +1,121 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + +import java.util.function.BiFunction; +import java.util.function.Function; + +class Fetcher { + private final static Logger logger = LoggerFactory.getLogger(Fetcher.class); + + private final BiFunction createRequestFunc; + private final Function>> executeFunc; + private final boolean isChangeFeed; + + private volatile boolean shouldFetchMore; + private volatile int maxItemCount; + private volatile int top; + private volatile String continuationToken; + + public Fetcher(BiFunction createRequestFunc, + Function>> executeFunc, + String continuationToken, + boolean isChangeFeed, + int top, + int maxItemCount) { + + this.createRequestFunc = createRequestFunc; + this.executeFunc = executeFunc; + this.isChangeFeed = isChangeFeed; + + this.continuationToken = continuationToken; + this.top = top; + if (top == -1) { + this.maxItemCount = maxItemCount; + } else { + // it is a top query, we should not retrieve more than requested top. + this.maxItemCount = Math.min(maxItemCount, top); + } + this.shouldFetchMore = true; + } + + public boolean shouldFetchMore() { + return shouldFetchMore; + } + + public Flux> nextPage() { + RxDocumentServiceRequest request = createRequest(); + return nextPage(request); + } + + private void updateState(FeedResponse response) { + continuationToken = response.continuationToken(); + if (top != -1) { + top -= response.results().size(); + if (top < 0) { + // this shouldn't happen + // this means backend retrieved more items than requested + logger.warn("Azure Cosmos DB BackEnd Service returned more than requested {} items", maxItemCount); + top = 0; + } + maxItemCount = Math.min(maxItemCount, top); + } + + shouldFetchMore = shouldFetchMore && + // if token is null or top == 0 then done + (!StringUtils.isEmpty(continuationToken) && (top != 0)) && + // if change feed query and no changes then done + (!isChangeFeed || !BridgeInternal.noChanges(response)); + + logger.debug("Fetcher state updated: " + + "isChangeFeed = {}, continuation token = {}, max item count = {}, should fetch more = {}", + isChangeFeed, continuationToken, maxItemCount, shouldFetchMore); + } + + private RxDocumentServiceRequest createRequest() { + if (!shouldFetchMore) { + // this should never happen + logger.error("invalid state, trying to fetch more after completion"); + throw new IllegalStateException("INVALID state, trying to fetch more after completion"); + } + + return createRequestFunc.apply(continuationToken, maxItemCount); + } + + private Flux> nextPage(RxDocumentServiceRequest request) { + return executeFunc.apply(request).map(rsp -> { + updateState(rsp); + return rsp; + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryClient.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryClient.java new file mode 100644 index 0000000000000..6bd7f74abcece --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryClient.java @@ -0,0 +1,95 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.IRetryPolicyFactory; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; +import com.azure.data.cosmos.internal.caches.IPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import reactor.core.publisher.Mono; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IDocumentQueryClient { + + /** + * TODO: this should be async returning observable + * @return + */ + RxCollectionCache getCollectionCache(); + + /** + * TODO: this should be async returning observable + * @return + */ + IPartitionKeyRangeCache getPartitionKeyRangeCache(); + + /** + * @return + */ + IRetryPolicyFactory getResetSessionTokenRetryPolicy(); + + /** + * TODO: this should be async returning observable + * @return + */ + ConsistencyLevel getDefaultConsistencyLevelAsync(); + + /** + * TODO: this should be async returning observable + * @return + */ + ConsistencyLevel getDesiredConsistencyLevelAsync(); + + Mono executeQueryAsync(RxDocumentServiceRequest request); + + QueryCompatibilityMode getQueryCompatibilityMode(); + + ///

    + /// A client query compatibility mode when making query request. + /// Can be used to force a specific query request format. + /// + enum QueryCompatibilityMode { + /// + /// DEFAULT (latest) query format. + /// + Default, + + /// + /// Query (application/query+json). + /// DEFAULT. + /// + Query, + + /// + /// SqlQuery (application/sql). + /// + SqlQuery + } + + Mono readFeedAsync(RxDocumentServiceRequest request); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionComponent.java new file mode 100644 index 0000000000000..4825b6931de0b --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionComponent.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import reactor.core.publisher.Flux; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IDocumentQueryExecutionComponent { + + Flux> drainAsync(int maxPageSize); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..9134daf10b657 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/IDocumentQueryExecutionContext.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import reactor.core.publisher.Flux; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public interface IDocumentQueryExecutionContext { + + Flux> executeAsync(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemComparator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemComparator.java new file mode 100644 index 0000000000000..843e367d6906e --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemComparator.java @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import java.util.Comparator; + +public final class ItemComparator implements Comparator { + private ItemComparator() { + } + + private static class SingletonHelper { + private static final ItemComparator INSTANCE = new ItemComparator(); + } + + public static ItemComparator getInstance() { + return SingletonHelper.INSTANCE; + } + + @Override + public int compare(Object obj1, Object obj2) { + ItemType type1 = ItemTypeHelper.getOrderByItemType(obj1); + ItemType type2 = ItemTypeHelper.getOrderByItemType(obj2); + + int cmp = Integer.compare(type1.getVal(), type2.getVal()); + + if (cmp != 0) { + return cmp; + } + + switch (type1) { + case NoValue: + case Null: + return 0; + case Boolean: + return Boolean.compare((Boolean) obj1, (Boolean) obj2); + case Number: + return Double.compare(((Number) obj1).doubleValue(), ((Number) obj2).doubleValue()); + case String: + return ((String) obj1).compareTo((String) obj2); + default: + throw new ClassCastException(String.format("Unexpected type: %s", type1.toString())); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemType.java new file mode 100644 index 0000000000000..56b90491c7835 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemType.java @@ -0,0 +1,38 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +public enum ItemType { + NoValue(0x0), Null(0x1), Boolean(0x2), Number(0x4), String(0x5); + + private final int val; + + ItemType(int val) { + this.val = val; + } + + public int getVal() { + return this.val; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemTypeHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemTypeHelper.java new file mode 100644 index 0000000000000..b43d8cf0fdfab --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ItemTypeHelper.java @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.internal.Undefined; + +public final class ItemTypeHelper { + public static ItemType getOrderByItemType(Object obj) { + if (obj == null) { + return ItemType.Null; + } + + if (obj instanceof Undefined) { + return ItemType.NoValue; + } + + if (obj instanceof Boolean) { + return ItemType.Boolean; + } + + if (obj instanceof Number) { + return ItemType.Number; + } + + if (obj instanceof String) { + return ItemType.String; + } + + throw new IllegalArgumentException(String.format("Unexpected type: %s", obj.getClass().toString())); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByContinuationToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByContinuationToken.java new file mode 100644 index 0000000000000..64993e10cece8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByContinuationToken.java @@ -0,0 +1,153 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public final class OrderByContinuationToken extends JsonSerializable { + private static final String CompositeContinuationTokenPropertyName = "compositeToken"; + private static final String OrderByItemsPropetryName = "orderByItems"; + private static final String RidPropertyName = "rid"; + private static final String InclusivePropertyName = "inclusive"; + private static final Logger logger = LoggerFactory.getLogger(OrderByContinuationToken.class); + + public OrderByContinuationToken(CompositeContinuationToken compositeContinuationToken, QueryItem[] orderByItems, + String rid, boolean inclusive) { + if (compositeContinuationToken == null) { + throw new IllegalArgumentException("CompositeContinuationToken must not be null."); + } + + if (orderByItems == null) { + throw new IllegalArgumentException("orderByItems must not be null."); + } + + if (orderByItems.length == 0) { + throw new IllegalArgumentException("orderByItems must not be empty."); + } + + if (rid == null) { + throw new IllegalArgumentException("rid must not be null."); + } + + this.setCompositeContinuationToken(compositeContinuationToken); + this.setOrderByItems(orderByItems); + this.setRid(rid); + this.setInclusive(inclusive); + } + + private OrderByContinuationToken(String serializedOrderByContinuationToken) { + super(serializedOrderByContinuationToken); + } + + public static boolean tryParse(String serializedOrderByContinuationToken, + ValueHolder outOrderByContinuationToken) { + boolean parsed; + try { + OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( + serializedOrderByContinuationToken); + CompositeContinuationToken compositeContinuationToken = orderByContinuationToken + .getCompositeContinuationToken(); + if (compositeContinuationToken == null) { + throw new IllegalArgumentException("compositeContinuationToken must not be null."); + } + + orderByContinuationToken.getOrderByItems(); + orderByContinuationToken.getRid(); + orderByContinuationToken.getInclusive(); + + outOrderByContinuationToken.v = orderByContinuationToken; + parsed = true; + } catch (Exception ex) { + logger.debug( + "Received exception {} when trying to parse: {}", + ex.getMessage(), + serializedOrderByContinuationToken); + parsed = false; + outOrderByContinuationToken.v = null; + } + + return parsed; + } + + public CompositeContinuationToken getCompositeContinuationToken() { + ValueHolder outCompositeContinuationToken = new ValueHolder(); + boolean succeeded = CompositeContinuationToken.tryParse(super.getString(CompositeContinuationTokenPropertyName), + outCompositeContinuationToken); + if (!succeeded) { + throw new IllegalArgumentException("Continuation Token was not able to be parsed"); + } + + return outCompositeContinuationToken.v; + } + + public QueryItem[] getOrderByItems() { + List queryItems = new ArrayList(); + ArrayNode arrayNode = (ArrayNode) super.get(OrderByItemsPropetryName); + for (JsonNode jsonNode : arrayNode) { + QueryItem queryItem = new QueryItem(jsonNode.toString()); + queryItems.add(queryItem); + } + + QueryItem[] queryItemsArray = new QueryItem[queryItems.size()]; + + return queryItems.toArray(queryItemsArray); + } + + public String getRid() { + return super.getString(RidPropertyName); + } + + public boolean getInclusive() { + return super.getBoolean(InclusivePropertyName); + } + + private void setCompositeContinuationToken(CompositeContinuationToken compositeContinuationToken) { + BridgeInternal.setProperty(this, CompositeContinuationTokenPropertyName, compositeContinuationToken.toJson()); + } + + private void setOrderByItems(QueryItem[] orderByItems) { + BridgeInternal.setProperty(this, OrderByItemsPropetryName, orderByItems); + } + + private void setRid(String rid) { + BridgeInternal.setProperty(this, RidPropertyName, rid); + } + + private void setInclusive(boolean inclusive) { + BridgeInternal.setProperty(this, InclusivePropertyName, inclusive); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentProducer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentProducer.java new file mode 100644 index 0000000000000..d5b4cec4e74bd --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentProducer.java @@ -0,0 +1,113 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderByRowResult; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderbyRowComparer; +import reactor.core.publisher.Flux; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.function.Function; + +class OrderByDocumentProducer extends DocumentProducer { + private final OrderbyRowComparer consumeComparer; + private final Map targetRangeToOrderByContinuationTokenMap; + + OrderByDocumentProducer( + OrderbyRowComparer consumeComparer, + IDocumentQueryClient client, + String collectionResourceId, + FeedOptions feedOptions, + TriFunction createRequestFunc, + Function>> executeRequestFunc, + PartitionKeyRange targetRange, + String collectionLink, + Callable createRetryPolicyFunc, + Class resourceType, + UUID correlatedActivityId, + int initialPageSize, + String initialContinuationToken, + int top, + Map targetRangeToOrderByContinuationTokenMap) { + super(client, collectionResourceId, feedOptions, createRequestFunc, executeRequestFunc, targetRange, collectionLink, + createRetryPolicyFunc, resourceType, correlatedActivityId, initialPageSize, initialContinuationToken, top); + this.consumeComparer = consumeComparer; + this.targetRangeToOrderByContinuationTokenMap = targetRangeToOrderByContinuationTokenMap; + } + + protected Flux produceOnSplit(Flux> replacementProducers) { + return replacementProducers.collectList().flux().flatMap(documentProducers -> { + RequestChargeTracker tracker = new RequestChargeTracker(); + Map queryMetricsMap = new HashMap<>(); + return OrderByUtils.orderedMerge(resourceType, consumeComparer, tracker, documentProducers, queryMetricsMap, + targetRangeToOrderByContinuationTokenMap) + .map(orderByQueryResult -> resultPageFrom(tracker, orderByQueryResult)); + }); + } + + @SuppressWarnings("unchecked") + private DocumentProducerFeedResponse resultPageFrom(RequestChargeTracker tracker, OrderByRowResult row) { + double requestCharge = tracker.getAndResetCharge(); + Map headers = Utils.immutableMapOf(HttpConstants.HttpHeaders.REQUEST_CHARGE, String.valueOf(requestCharge)); + FeedResponse fr = BridgeInternal.createFeedResponse(Collections.singletonList((T) row), headers); + return new DocumentProducerFeedResponse(fr, row.getSourcePartitionKeyRange()); + } + + protected DocumentProducer createChildDocumentProducerOnSplit( + PartitionKeyRange targetRange, + String initialContinuationToken) { + + return new OrderByDocumentProducer<>( + consumeComparer, + client, + collectionRid, + feedOptions, + createRequestFunc, + executeRequestFuncWithRetries, + targetRange, + collectionLink, + createRetryPolicyFunc, + resourceType , + correlatedActivityId, + pageSize, + initialContinuationToken, + top, + this.targetRangeToOrderByContinuationTokenMap); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..30afa3602176a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByDocumentQueryExecutionContext.java @@ -0,0 +1,642 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderByRowResult; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderbyRowComparer; +import com.azure.data.cosmos.internal.routing.Range; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.tuple.ImmutablePair; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class OrderByDocumentQueryExecutionContext + extends ParallelDocumentQueryExecutionContextBase { + private final String FormatPlaceHolder = "{documentdb-formattableorderbyquery-filter}"; + private final String True = "true"; + private final String collectionRid; + private final OrderbyRowComparer consumeComparer; + private final RequestChargeTracker tracker; + private final ConcurrentMap queryMetricMap; + private Flux> orderByObservable; + private final Map targetRangeToOrderByContinuationTokenMap; + + private OrderByDocumentQueryExecutionContext( + IDocumentQueryClient client, + List partitionKeyRanges, + ResourceType resourceTypeEnum, + Class klass, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + String rewrittenQuery, + boolean isContinuationExpected, + boolean getLazyFeedResponse, + OrderbyRowComparer consumeComparer, + String collectionRid, + UUID correlatedActivityId) { + super(client, partitionKeyRanges, resourceTypeEnum, klass, query, feedOptions, resourceLink, rewrittenQuery, + isContinuationExpected, getLazyFeedResponse, correlatedActivityId); + this.collectionRid = collectionRid; + this.consumeComparer = consumeComparer; + this.tracker = new RequestChargeTracker(); + this.queryMetricMap = new ConcurrentHashMap<>(); + targetRangeToOrderByContinuationTokenMap = new HashMap<>(); + } + + public static Flux> createAsync( + IDocumentQueryClient client, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec expression, + FeedOptions feedOptions, + String resourceLink, + String collectionRid, + PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, + List partitionKeyRanges, + int initialPageSize, + boolean isContinuationExpected, + boolean getLazyFeedResponse, + UUID correlatedActivityId) { + + OrderByDocumentQueryExecutionContext context = new OrderByDocumentQueryExecutionContext(client, + partitionKeyRanges, + resourceTypeEnum, + resourceType, + expression, + feedOptions, + resourceLink, + partitionedQueryExecutionInfo.getQueryInfo().getRewrittenQuery(), + isContinuationExpected, + getLazyFeedResponse, + new OrderbyRowComparer(partitionedQueryExecutionInfo.getQueryInfo().getOrderBy()), + collectionRid, + correlatedActivityId); + + try { + context.initialize(partitionKeyRanges, + partitionedQueryExecutionInfo.getQueryInfo().getOrderBy(), + partitionedQueryExecutionInfo.getQueryInfo().getOrderByExpressions(), + initialPageSize, + feedOptions.requestContinuation()); + + return Flux.just(context); + } catch (CosmosClientException dce) { + return Flux.error(dce); + } + } + + private void initialize( + List partitionKeyRanges, + List sortOrders, + Collection orderByExpressions, + int initialPageSize, + String continuationToken) throws CosmosClientException { + if (continuationToken == null) { + // First iteration so use null continuation tokens and "true" filters + Map partitionKeyRangeToContinuationToken = new HashMap(); + for (PartitionKeyRange partitionKeyRange : partitionKeyRanges) { + partitionKeyRangeToContinuationToken.put(partitionKeyRange, + null); + } + + super.initialize(collectionRid, + partitionKeyRangeToContinuationToken, + initialPageSize, + new SqlQuerySpec(querySpec.queryText().replace(FormatPlaceHolder, + True), + querySpec.parameters())); + } else { + // Check to see if order by continuation token is a valid JSON. + OrderByContinuationToken orderByContinuationToken; + ValueHolder outOrderByContinuationToken = new ValueHolder(); + if (!OrderByContinuationToken.tryParse(continuationToken, + outOrderByContinuationToken)) { + String message = String.format("INVALID JSON in continuation token %s for OrderBy~Context", + continuationToken); + throw BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + message); + } + + orderByContinuationToken = outOrderByContinuationToken.v; + + CompositeContinuationToken compositeContinuationToken = orderByContinuationToken + .getCompositeContinuationToken(); + // Check to see if the ranges inside are valid + if (compositeContinuationToken.getRange().isEmpty()) { + String message = String.format("INVALID RANGE in the continuation token %s for OrderBy~Context.", + continuationToken); + throw BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + message); + } + + // At this point the token is valid. + ImmutablePair targetIndexAndFilters = this.GetFiltersForPartitions( + orderByContinuationToken, + partitionKeyRanges, + sortOrders, + orderByExpressions); + + int targetIndex = targetIndexAndFilters.left; + targetRangeToOrderByContinuationTokenMap.put(String.valueOf(targetIndex), orderByContinuationToken); + FormattedFilterInfo formattedFilterInfo = targetIndexAndFilters.right; + + // Left + String filterForRangesLeftOfTheTargetRange = formattedFilterInfo.getFilterForRangesLeftOfTheTargetRange(); + this.initializeRangeWithContinuationTokenAndFilter(partitionKeyRanges, + /* startInclusive */ 0, + /* endExclusive */ targetIndex, + /* continuationToken */ null, + filterForRangesLeftOfTheTargetRange, + initialPageSize); + + // Target + String filterForTargetRange = formattedFilterInfo.getFilterForTargetRange(); + this.initializeRangeWithContinuationTokenAndFilter(partitionKeyRanges, + /* startInclusive */ targetIndex, + /* endExclusive */ targetIndex + 1, + null, + filterForTargetRange, + initialPageSize); + + // Right + String filterForRangesRightOfTheTargetRange = formattedFilterInfo.getFilterForRangesRightOfTheTargetRange(); + this.initializeRangeWithContinuationTokenAndFilter(partitionKeyRanges, + /* startInclusive */ targetIndex + 1, + /* endExclusive */ partitionKeyRanges.size(), + /* continuationToken */ null, + filterForRangesRightOfTheTargetRange, + initialPageSize); + } + + orderByObservable = OrderByUtils.orderedMerge(resourceType, + consumeComparer, + tracker, + documentProducers, + queryMetricMap, + targetRangeToOrderByContinuationTokenMap); + } + + private void initializeRangeWithContinuationTokenAndFilter( + List partitionKeyRanges, + int startInclusive, + int endExclusive, + String continuationToken, + String filter, + int initialPageSize) { + Map partitionKeyRangeToContinuationToken = new HashMap(); + for (int i = startInclusive; i < endExclusive; i++) { + PartitionKeyRange partitionKeyRange = partitionKeyRanges.get(i); + partitionKeyRangeToContinuationToken.put(partitionKeyRange, + continuationToken); + } + + super.initialize(collectionRid, + partitionKeyRangeToContinuationToken, + initialPageSize, + new SqlQuerySpec(querySpec.queryText().replace(FormatPlaceHolder, + filter), + querySpec.parameters())); + } + + private ImmutablePair GetFiltersForPartitions( + OrderByContinuationToken orderByContinuationToken, + List partitionKeyRanges, + List sortOrders, + Collection orderByExpressions) throws CosmosClientException { + // Find the partition key range we left off on + int startIndex = this.FindTargetRangeAndExtractContinuationTokens(partitionKeyRanges, + orderByContinuationToken.getCompositeContinuationToken().getRange()); + + // Get the filters. + FormattedFilterInfo formattedFilterInfo = this.GetFormattedFilters(orderByExpressions, + orderByContinuationToken.getOrderByItems(), + sortOrders, + orderByContinuationToken.getInclusive()); + + return new ImmutablePair(startIndex, + formattedFilterInfo); + } + + private OrderByDocumentQueryExecutionContext.FormattedFilterInfo GetFormattedFilters( + Collection orderByExpressionCollection, + QueryItem[] orderByItems, + Collection sortOrderCollection, + boolean inclusive) { + // Convert to arrays + SortOrder[] sortOrders = new SortOrder[sortOrderCollection.size()]; + sortOrderCollection.toArray(sortOrders); + + String[] expressions = new String[orderByExpressionCollection.size()]; + orderByExpressionCollection.toArray(expressions); + + // Validate the inputs + if (expressions.length != sortOrders.length) { + throw new IllegalArgumentException("expressions.size() != sortOrders.size()"); + } + + if (expressions.length != orderByItems.length) { + throw new IllegalArgumentException("expressions.size() != orderByItems.length"); + } + + // When we run cross partition queries, + // we only serialize the continuation token for the partition that we left off + // on. + // The only problem is that when we resume the order by query, + // we don't have continuation tokens for all other partitions. + // The saving grace is that the data has a composite sort order(query sort + // order, partition key range id) + // so we can generate range filters which in turn the backend will turn into rid + // based continuation tokens, + // which is enough to get the streams of data flowing from all partitions. + // The details of how this is done is described below: + + int numOrderByItems = expressions.length; + boolean isSingleOrderBy = numOrderByItems == 1; + StringBuilder left = new StringBuilder(); + StringBuilder target = new StringBuilder(); + StringBuilder right = new StringBuilder(); + + if (isSingleOrderBy) { + // For a single order by query we resume the continuations in this manner + // Suppose the query is SELECT* FROM c ORDER BY c.string ASC + // And we left off on partition N with the value "B" + // Then + // ALL the partitions to the left will have finished reading "B" + // Partition N is still reading "B" + // ALL the partitions to the right have let to read a "B + // Therefore the filters should be + // > "B" , >= "B", and >= "B" respectively + // Repeat the same logic for DESC and you will get + // < "B", <= "B", and <= "B" respectively + // The general rule becomes + // For ASC + // > for partitions to the left + // >= for the partition we left off on + // >= for the partitions to the right + // For DESC + // < for partitions to the left + // <= for the partition we left off on + // <= for the partitions to the right + String expression = expressions[0]; + SortOrder sortOrder = sortOrders[0]; + QueryItem orderByItem = orderByItems[0]; + Object rawItem = orderByItem.getItem(); + String orderByItemToString; + if (rawItem instanceof String) { + orderByItemToString = "\"" + rawItem.toString().replaceAll("\"", + "\\\"") + "\""; + } else { + orderByItemToString = rawItem.toString(); + } + + left.append(String.format("%s %s %s", + expression, + (sortOrder == SortOrder.Descending ? "<" : ">"), + orderByItemToString)); + + if (inclusive) { + target.append(String.format("%s %s %s", + expression, + (sortOrder == SortOrder.Descending ? "<=" : ">="), + orderByItemToString)); + } else { + target.append(String.format("%s %s %s", + expression, + (sortOrder == SortOrder.Descending ? "<" : ">"), + orderByItemToString)); + } + + right.append(String.format("%s %s %s", + expression, + (sortOrder == SortOrder.Descending ? "<=" : ">="), + orderByItemToString)); + } else { + // This code path needs to be implemented, but it's error prone and needs + // testing. + // You can port the implementation from the .net SDK and it should work if + // ported right. + throw new NotImplementedException( + "Resuming a multi order by query from a continuation token is not supported yet."); + } + + return new FormattedFilterInfo(left.toString(), + target.toString(), + right.toString()); + } + + protected OrderByDocumentProducer createDocumentProducer( + String collectionRid, + PartitionKeyRange targetRange, + String continuationToken, + int initialPageSize, + FeedOptions feedOptions, + SqlQuerySpec querySpecForInit, + Map commonRequestHeaders, + TriFunction createRequestFunc, + Function>> executeFunc, + Callable createRetryPolicyFunc) { + return new OrderByDocumentProducer(consumeComparer, + client, + collectionRid, + feedOptions, + createRequestFunc, + executeFunc, + targetRange, + collectionRid, + () -> client.getResetSessionTokenRetryPolicy().getRequestPolicy(), + resourceType, + correlatedActivityId, + initialPageSize, + continuationToken, + top, + this.targetRangeToOrderByContinuationTokenMap); + } + + private static class ItemToPageTransformer + implements Function>, Flux>> { + private final static int DEFAULT_PAGE_SIZE = 100; + private final RequestChargeTracker tracker; + private final int maxPageSize; + private final ConcurrentMap queryMetricMap; + private final Function, String> orderByContinuationTokenCallback; + private volatile FeedResponse> previousPage; + + public ItemToPageTransformer( + RequestChargeTracker tracker, + int maxPageSize, + ConcurrentMap queryMetricsMap, + Function, String> orderByContinuationTokenCallback) { + this.tracker = tracker; + this.maxPageSize = maxPageSize > 0 ? maxPageSize : DEFAULT_PAGE_SIZE; + this.queryMetricMap = queryMetricsMap; + this.orderByContinuationTokenCallback = orderByContinuationTokenCallback; + this.previousPage = null; + } + + private static Map headerResponse( + double requestCharge) { + return Utils.immutableMapOf(HttpConstants.HttpHeaders.REQUEST_CHARGE, + String.valueOf(requestCharge)); + } + + private FeedResponse> addOrderByContinuationToken( + FeedResponse> page, + String orderByContinuationToken) { + Map headers = new HashMap<>(page.responseHeaders()); + headers.put(HttpConstants.HttpHeaders.CONTINUATION, + orderByContinuationToken); + return BridgeInternal.createFeedResponseWithQueryMetrics(page.results(), + headers, + BridgeInternal.queryMetricsFromFeedResponse(page)); + } + + @Override + public Flux> apply(Flux> source) { + return source + // .windows: creates an observable of observable where inner observable + // emits max maxPageSize elements + .window(maxPageSize).map(Flux::collectList) + // flattens the observable>>> to + // Observable>> + .flatMap(resultListObs -> resultListObs, + 1) + // translates Observable>> to + // Observable>>> + .map(orderByRowResults -> { + // construct a page from result with request charge + FeedResponse> feedResponse = BridgeInternal.createFeedResponse( + orderByRowResults, + headerResponse(tracker.getAndResetCharge())); + if (!queryMetricMap.isEmpty()) { + for (String key : queryMetricMap.keySet()) { + BridgeInternal.putQueryMetricsIntoMap(feedResponse, + key, + queryMetricMap.get(key)); + } + } + return feedResponse; + }) + // Emit an empty page so the downstream observables know when there are no more + // results. + .concatWith(Flux.defer(() -> { + return Flux.just(BridgeInternal.createFeedResponse(Utils.immutableListOf(), + null)); + })) + // CREATE pairs from the stream to allow the observables downstream to "peek" + // 1, 2, 3, null -> (null, 1), (1, 2), (2, 3), (3, null) + .map(orderByRowResults -> { + ImmutablePair>, FeedResponse>> previousCurrent = new ImmutablePair>, FeedResponse>>( + this.previousPage, + orderByRowResults); + this.previousPage = orderByRowResults; + return previousCurrent; + }) + // remove the (null, 1) + .skip(1) + // Add the continuation token based on the current and next page. + .map(currentNext -> { + FeedResponse> current = currentNext.left; + FeedResponse> next = currentNext.right; + + FeedResponse> page; + if (next.results().size() == 0) { + // No more pages no send current page with null continuation token + page = current; + page = this.addOrderByContinuationToken(page, + null); + } else { + // Give the first page but use the first value in the next page to generate the + // continuation token + page = current; + List> results = next.results(); + OrderByRowResult firstElementInNextPage = results.get(0); + String orderByContinuationToken = this.orderByContinuationTokenCallback + .apply(firstElementInNextPage); + page = this.addOrderByContinuationToken(page, + orderByContinuationToken); + } + + return page; + }).map(feedOfOrderByRowResults -> { + // FeedResponse> to FeedResponse + List unwrappedResults = new ArrayList(); + for (OrderByRowResult orderByRowResult : feedOfOrderByRowResults.results()) { + unwrappedResults.add(orderByRowResult.getPayload()); + } + + return BridgeInternal.createFeedResponseWithQueryMetrics(unwrappedResults, + feedOfOrderByRowResults.responseHeaders(), + BridgeInternal.queryMetricsFromFeedResponse(feedOfOrderByRowResults)); + }).switchIfEmpty(Flux.defer(() -> { + // create an empty page if there is no result + return Flux.just(BridgeInternal.createFeedResponse(Utils.immutableListOf(), + headerResponse(tracker.getAndResetCharge()))); + })); + } + } + + @Override + public Flux> drainAsync( + int maxPageSize) { + //// In order to maintain the continuation token for the user we must drain with + //// a few constraints + //// 1) We always drain from the partition, which has the highest priority item + //// first + //// 2) If multiple partitions have the same priority item then we drain from + //// the left most first + //// otherwise we would need to keep track of how many of each item we drained + //// from each partition + //// (just like parallel queries). + //// Visually that look the following case where we have three partitions that + //// are numbered and store letters. + //// For teaching purposes I have made each item a tuple of the following form: + //// + //// So that duplicates across partitions are distinct, but duplicates within + //// partitions are indistinguishable. + //// |-------| |-------| |-------| + //// | | | | | | + //// | | | | | | + //// | | | | | | + //// | | | | | | + //// | | | | | | + //// | | | | | | + //// | | | | | | + //// |-------| |-------| |-------| + //// Now the correct drain order in this case is: + //// ,,,,,,,,,,, + //// ,,,,,,,,, + //// In more mathematical terms + //// 1) always comes before where x < z + //// 2) always come before where j < k + return this.orderByObservable.compose(new ItemToPageTransformer(tracker, + maxPageSize, + this.queryMetricMap, + this::getContinuationToken)); + } + + @Override + public Flux> executeAsync() { + return drainAsync(feedOptions.maxItemCount()); + } + + private String getContinuationToken( + OrderByRowResult orderByRowResult) { + // rid + String rid = orderByRowResult.resourceId(); + + // CompositeContinuationToken + String backendContinuationToken = orderByRowResult.getSourceBackendContinuationToken(); + Range range = orderByRowResult.getSourcePartitionKeyRange().toRange(); + + boolean inclusive = true; + CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken(backendContinuationToken, + range); + + // OrderByItems + QueryItem[] orderByItems = new QueryItem[orderByRowResult.getOrderByItems().size()]; + orderByRowResult.getOrderByItems().toArray(orderByItems); + + return new OrderByContinuationToken(compositeContinuationToken, + orderByItems, + rid, + inclusive).toJson(); + } + + private final class FormattedFilterInfo { + private final String filterForRangesLeftOfTheTargetRange; + private final String filterForTargetRange; + private final String filterForRangesRightOfTheTargetRange; + + public FormattedFilterInfo( + String filterForRangesLeftOfTheTargetRange, + String filterForTargetRange, + String filterForRangesRightOfTheTargetRange) { + if (filterForRangesLeftOfTheTargetRange == null) { + throw new IllegalArgumentException("filterForRangesLeftOfTheTargetRange must not be null."); + } + + if (filterForTargetRange == null) { + throw new IllegalArgumentException("filterForTargetRange must not be null."); + } + + if (filterForRangesRightOfTheTargetRange == null) { + throw new IllegalArgumentException("filterForRangesRightOfTheTargetRange must not be null."); + } + + this.filterForRangesLeftOfTheTargetRange = filterForRangesLeftOfTheTargetRange; + this.filterForTargetRange = filterForTargetRange; + this.filterForRangesRightOfTheTargetRange = filterForRangesRightOfTheTargetRange; + } + + /** + * @return the filterForRangesLeftOfTheTargetRange + */ + public String getFilterForRangesLeftOfTheTargetRange() { + return filterForRangesLeftOfTheTargetRange; + } + + /** + * @return the filterForTargetRange + */ + public String getFilterForTargetRange() { + return filterForTargetRange; + } + + /** + * @return the filterForRangesRightOfTheTargetRange + */ + public String getFilterForRangesRightOfTheTargetRange() { + return filterForRangesRightOfTheTargetRange; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByUtils.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByUtils.java new file mode 100644 index 0000000000000..2837ac580b817 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/OrderByUtils.java @@ -0,0 +1,166 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.ResourceId; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderByRowResult; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderbyRowComparer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.apache.commons.lang3.tuple.Pair; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +class OrderByUtils { + + public static Flux> orderedMerge(Class klass, + OrderbyRowComparer consumeComparer, + RequestChargeTracker tracker, + List> documentProducers, + Map queryMetricsMap, + Map targetRangeToOrderByContinuationTokenMap) { + Flux>[] fluxes = documentProducers + .subList(0, documentProducers.size()) + .stream() + .map(producer -> + toOrderByQueryResultObservable(klass, producer, tracker, queryMetricsMap, targetRangeToOrderByContinuationTokenMap, consumeComparer.getSortOrders())) + .toArray(Flux[]::new); + return Flux.mergeOrdered(consumeComparer, fluxes); + } + + private static Flux> toOrderByQueryResultObservable(Class klass, + DocumentProducer producer, + RequestChargeTracker tracker, + Map queryMetricsMap, + Map targetRangeToOrderByContinuationTokenMap, + List sortOrders) { + return producer + .produceAsync() + .compose(new OrderByUtils.PageToItemTransformer(klass, tracker, queryMetricsMap, targetRangeToOrderByContinuationTokenMap, sortOrders)); + } + + private static class PageToItemTransformer implements Function.DocumentProducerFeedResponse>, Flux>> { + private final RequestChargeTracker tracker; + private final Class klass; + private final Map queryMetricsMap; + private final Map targetRangeToOrderByContinuationTokenMap; + private final List sortOrders; + + public PageToItemTransformer(Class klass, RequestChargeTracker tracker, Map queryMetricsMap, + Map targetRangeToOrderByContinuationTokenMap, List sortOrders) { + this.klass = klass; + this.tracker = tracker; + this.queryMetricsMap = queryMetricsMap; + this.targetRangeToOrderByContinuationTokenMap = targetRangeToOrderByContinuationTokenMap; + this.sortOrders = sortOrders; + } + + @Override + public Flux> apply(Flux.DocumentProducerFeedResponse> source) { + return source.flatMap(documentProducerFeedResponse -> { + for (String key : BridgeInternal.queryMetricsFromFeedResponse(documentProducerFeedResponse.pageResult).keySet()) { + if (queryMetricsMap.containsKey(key)) { + QueryMetrics qm = BridgeInternal.queryMetricsFromFeedResponse(documentProducerFeedResponse.pageResult).get(key); + queryMetricsMap.get(key).add(qm); + } else { + queryMetricsMap.put(key, BridgeInternal.queryMetricsFromFeedResponse(documentProducerFeedResponse.pageResult).get(key)); + } + } + List results = documentProducerFeedResponse.pageResult.results(); + OrderByContinuationToken orderByContinuationToken = targetRangeToOrderByContinuationTokenMap.get(documentProducerFeedResponse.sourcePartitionKeyRange.id()); + if (orderByContinuationToken != null) { + Pair booleanResourceIdPair = ResourceId.tryParse(orderByContinuationToken.getRid()); + if (!booleanResourceIdPair.getLeft()) { + return Flux.error(new BadRequestException(String.format("INVALID Rid in the continuation token %s for OrderBy~Context.", + orderByContinuationToken.getCompositeContinuationToken().getToken()))); + } + ResourceId continuationTokenRid = booleanResourceIdPair.getRight(); + results = results.stream() + .filter(tOrderByRowResult -> { + // When we resume a query on a partition there is a possibility that we only read a partial page from the backend + // meaning that will we repeat some documents if we didn't do anything about it. + // The solution is to filter all the documents that come before in the sort order, since we have already emitted them to the client. + // The key is to seek until we get an order by value that matches the order by value we left off on. + // Once we do that we need to seek to the correct _rid within the term, + // since there might be many documents with the same order by value we left off on. + List queryItems = new ArrayList(); + ArrayNode arrayNode = (ArrayNode) tOrderByRowResult.get("orderByItems"); + for (JsonNode jsonNode : arrayNode) { + QueryItem queryItem = new QueryItem(jsonNode.toString()); + queryItems.add(queryItem); + } + + // Check if its the same orderby item from the token + long cmp = 0; + for (int i = 0; i < sortOrders.size(); i++) { + cmp = ItemComparator.getInstance().compare(orderByContinuationToken.getOrderByItems()[i].getItem(), + queryItems.get(i).getItem()); + if (cmp != 0) { + cmp = sortOrders.get(i).equals(SortOrder.Descending) ? -cmp : cmp; + break; + } + } + + if (cmp == 0) { + // Once the item matches the order by items from the continuation tokens + // We still need to remove all the documents that have a lower rid in the rid sort order. + // If there is a tie in the sort order the documents should be in _rid order in the same direction as the first order by field. + // So if it's ORDER BY c.age ASC, c.name DESC the _rids are ASC + // If ti's ORDER BY c.age DESC, c.name DESC the _rids are DESC + cmp = (continuationTokenRid.getDocument() - ResourceId.tryParse(tOrderByRowResult.resourceId()).getRight().getDocument()); + + if (sortOrders.iterator().next().equals(SortOrder.Descending)) { + cmp = -cmp; + } + return (cmp <= 0); + } + return true; + + }) + .collect(Collectors.toList()); + + } + + tracker.addCharge(documentProducerFeedResponse.pageResult.requestCharge()); + Flux x = Flux.fromIterable(results); + + return x.map(r -> new OrderByRowResult( + klass, + r.toJson(), + documentProducerFeedResponse.sourcePartitionKeyRange, + documentProducerFeedResponse.pageResult.continuationToken())); + }, 1); + } + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Paginator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Paginator.java new file mode 100644 index 0000000000000..4780965387d37 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/Paginator.java @@ -0,0 +1,94 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; + +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class Paginator { + + private final static Logger logger = LoggerFactory.getLogger(Paginator.class); + + public static Flux> getPaginatedChangeFeedQueryResultAsObservable( + ChangeFeedOptions feedOptions, BiFunction createRequestFunc, + Function>> executeFunc, Class resourceType, + int maxPageSize) { + return getPaginatedQueryResultAsObservable(feedOptions.requestContinuation(), createRequestFunc, executeFunc, resourceType, + -1, maxPageSize, true); + } + + public static Flux> getPaginatedQueryResultAsObservable( + FeedOptions feedOptions, + BiFunction createRequestFunc, + Function>> executeFunc, Class resourceType, + int maxPageSize) { + return getPaginatedQueryResultAsObservable(feedOptions.requestContinuation(), createRequestFunc, executeFunc, resourceType, + -1, maxPageSize); + } + + public static Flux> getPaginatedQueryResultAsObservable( + String continuationToken, + BiFunction createRequestFunc, + Function>> executeFunc, Class resourceType, + int top, int maxPageSize) { + return getPaginatedQueryResultAsObservable(continuationToken, createRequestFunc, executeFunc, resourceType, + top, maxPageSize, false); + } + + private static Flux> getPaginatedQueryResultAsObservable( + String continuationToken, + BiFunction createRequestFunc, + Function>> executeFunc, Class resourceType, + int top, int maxPageSize, boolean isChangeFeed) { + + return Flux.defer(() -> { + Flux>> generate = Flux.generate(() -> + new Fetcher<>(createRequestFunc, executeFunc, continuationToken, isChangeFeed, top, maxPageSize), + (tFetcher, sink) -> { + if (tFetcher.shouldFetchMore()) { + Flux> nextPage = tFetcher.nextPage(); + sink.next(nextPage); + } else { + logger.debug("No more results"); + sink.complete(); + } + return tFetcher; + }); + + return generate.flatMapSequential(feedResponseFlux -> feedResponseFlux, 1); + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..61b9354ea8fb3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContext.java @@ -0,0 +1,360 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.RequestChargeTracker; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import org.apache.commons.lang3.tuple.ImmutablePair; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.stream.Collectors; +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class ParallelDocumentQueryExecutionContext + extends ParallelDocumentQueryExecutionContextBase { + + private ParallelDocumentQueryExecutionContext( + IDocumentQueryClient client, + List partitionKeyRanges, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + String rewrittenQuery, + String collectionRid, + boolean isContinuationExpected, + boolean getLazyFeedResponse, + UUID correlatedActivityId) { + super(client, partitionKeyRanges, resourceTypeEnum, resourceType, query, feedOptions, resourceLink, + rewrittenQuery, isContinuationExpected, getLazyFeedResponse, correlatedActivityId); + } + + public static Flux> createAsync( + IDocumentQueryClient client, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + String collectionRid, + PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, + List targetRanges, + int initialPageSize, + boolean isContinuationExpected, + boolean getLazyFeedResponse, + UUID correlatedActivityId) { + + ParallelDocumentQueryExecutionContext context = new ParallelDocumentQueryExecutionContext(client, + targetRanges, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + partitionedQueryExecutionInfo.getQueryInfo().getRewrittenQuery(), + collectionRid, + isContinuationExpected, + getLazyFeedResponse, + correlatedActivityId); + + try { + context.initialize(collectionRid, + targetRanges, + initialPageSize, + feedOptions.requestContinuation()); + return Flux.just(context); + } catch (CosmosClientException dce) { + return Flux.error(dce); + } + } + + private void initialize( + String collectionRid, + List targetRanges, + int initialPageSize, + String continuationToken) throws CosmosClientException { + // Generate the corresponding continuation token map. + Map partitionKeyRangeToContinuationTokenMap = new HashMap(); + if (continuationToken == null) { + // If the user does not give a continuation token, + // then just start the query from the first partition. + for (PartitionKeyRange targetRange : targetRanges) { + partitionKeyRangeToContinuationTokenMap.put(targetRange, + null); + } + } else { + // Figure out which partitions to resume from: + + // If a continuation token is given then we need to figure out partition key + // range it maps to + // in order to filter the partition key ranges. + // For example if suppliedCompositeContinuationToken.RANGE.Min == + // partition3.RANGE.Min, + // then we know that partitions 0, 1, 2 are fully drained. + + // Check to see if composite continuation token is a valid JSON. + ValueHolder outCompositeContinuationToken = new ValueHolder(); + if (!CompositeContinuationToken.tryParse(continuationToken, + outCompositeContinuationToken)) { + String message = String.format("INVALID JSON in continuation token %s for Parallel~Context", + continuationToken); + throw BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + message); + } + + CompositeContinuationToken compositeContinuationToken = outCompositeContinuationToken.v; + + // Get the right hand side of the query ranges: + List filteredPartitionKeyRanges = this.getPartitionKeyRangesForContinuation( + compositeContinuationToken, + targetRanges); + + // The first partition is the one we left off on and have a backend continuation + // token for. + partitionKeyRangeToContinuationTokenMap.put(filteredPartitionKeyRanges.get(0), + compositeContinuationToken.getToken()); + + // The remaining partitions we have yet to touch / have null continuation tokens + for (int i = 1; i < filteredPartitionKeyRanges.size(); i++) { + partitionKeyRangeToContinuationTokenMap.put(filteredPartitionKeyRanges.get(i), + null); + } + } + + super.initialize(collectionRid, + partitionKeyRangeToContinuationTokenMap, + initialPageSize, + this.querySpec); + } + + private List getPartitionKeyRangesForContinuation( + CompositeContinuationToken compositeContinuationToken, + List partitionKeyRanges) throws CosmosClientException { + // Find the partition key range we left off on + int startIndex = this.FindTargetRangeAndExtractContinuationTokens(partitionKeyRanges, + compositeContinuationToken.getRange()); + + List rightHandSideRanges = new ArrayList(); + for (int i = startIndex; i < partitionKeyRanges.size(); i++) { + rightHandSideRanges.add(partitionKeyRanges.get(i)); + } + + return rightHandSideRanges; + } + + private static class EmptyPagesFilterTransformer + implements Function.DocumentProducerFeedResponse>, Flux>> { + private final RequestChargeTracker tracker; + private DocumentProducer.DocumentProducerFeedResponse previousPage; + + public EmptyPagesFilterTransformer( + RequestChargeTracker tracker) { + + if (tracker == null) { + throw new IllegalArgumentException("Request Charge Tracker must not be null."); + } + + this.tracker = tracker; + this.previousPage = null; + } + + private DocumentProducer.DocumentProducerFeedResponse plusCharge( + DocumentProducer.DocumentProducerFeedResponse documentProducerFeedResponse, + double charge) { + FeedResponse page = documentProducerFeedResponse.pageResult; + Map headers = new HashMap<>(page.responseHeaders()); + double pageCharge = page.requestCharge(); + pageCharge += charge; + headers.put(HttpConstants.HttpHeaders.REQUEST_CHARGE, + String.valueOf(pageCharge)); + FeedResponse newPage = BridgeInternal.createFeedResponseWithQueryMetrics(page.results(), + headers, + BridgeInternal.queryMetricsFromFeedResponse(page)); + documentProducerFeedResponse.pageResult = newPage; + return documentProducerFeedResponse; + } + + private DocumentProducer.DocumentProducerFeedResponse addCompositeContinuationToken( + DocumentProducer.DocumentProducerFeedResponse documentProducerFeedResponse, + String compositeContinuationToken) { + FeedResponse page = documentProducerFeedResponse.pageResult; + Map headers = new HashMap<>(page.responseHeaders()); + headers.put(HttpConstants.HttpHeaders.CONTINUATION, + compositeContinuationToken); + FeedResponse newPage = BridgeInternal.createFeedResponseWithQueryMetrics(page.results(), + headers, + BridgeInternal.queryMetricsFromFeedResponse(page)); + documentProducerFeedResponse.pageResult = newPage; + return documentProducerFeedResponse; + } + + private static Map headerResponse( + double requestCharge) { + return Utils.immutableMapOf(HttpConstants.HttpHeaders.REQUEST_CHARGE, + String.valueOf(requestCharge)); + } + + @Override + public Flux> apply(Flux.DocumentProducerFeedResponse> source) { + // Emit an empty page so the downstream observables know when there are no more + // results. + return source.filter(documentProducerFeedResponse -> { + if (documentProducerFeedResponse.pageResult.results().isEmpty()) { + // filter empty pages and accumulate charge + tracker.addCharge(documentProducerFeedResponse.pageResult.requestCharge()); + return false; + } + return true; + }).map(documentProducerFeedResponse -> { + // Add the request charge + double charge = tracker.getAndResetCharge(); + if (charge > 0) { + return new ValueHolder<>(plusCharge(documentProducerFeedResponse, + charge)); + } else { + return new ValueHolder<>(documentProducerFeedResponse); + } + }).concatWith(Flux.just(new ValueHolder<>(null))).map(heldValue -> { + DocumentProducer.DocumentProducerFeedResponse documentProducerFeedResponse = heldValue.v; + // CREATE pairs from the stream to allow the observables downstream to "peek" + // 1, 2, 3, null -> (null, 1), (1, 2), (2, 3), (3, null) + ImmutablePair.DocumentProducerFeedResponse, DocumentProducer.DocumentProducerFeedResponse> previousCurrent = new ImmutablePair<>( + this.previousPage, + documentProducerFeedResponse); + this.previousPage = documentProducerFeedResponse; + return previousCurrent; + }).skip(1).map(currentNext -> { + // remove the (null, 1) + // Add the continuation token based on the current and next page. + DocumentProducer.DocumentProducerFeedResponse current = currentNext.left; + DocumentProducer.DocumentProducerFeedResponse next = currentNext.right; + + String compositeContinuationToken; + String backendContinuationToken = current.pageResult.continuationToken(); + if (backendContinuationToken == null) { + // We just finished reading the last document from a partition + if (next == null) { + // It was the last partition and we are done + compositeContinuationToken = null; + } else { + // It wasn't the last partition, so we need to give the next range, but with a + // null continuation + CompositeContinuationToken compositeContinuationTokenDom = new CompositeContinuationToken(null, + next.sourcePartitionKeyRange.toRange()); + compositeContinuationToken = compositeContinuationTokenDom.toJson(); + } + } else { + // We are in the middle of reading a partition, + // so give back this partition with a backend continuation token + CompositeContinuationToken compositeContinuationTokenDom = new CompositeContinuationToken( + backendContinuationToken, + current.sourcePartitionKeyRange.toRange()); + compositeContinuationToken = compositeContinuationTokenDom.toJson(); + } + + DocumentProducer.DocumentProducerFeedResponse page; + page = current; + page = this.addCompositeContinuationToken(page, + compositeContinuationToken); + + return page; + }).map(documentProducerFeedResponse -> { + // Unwrap the documentProducerFeedResponse and get back the feedResponse + return documentProducerFeedResponse.pageResult; + }).switchIfEmpty(Flux.defer(() -> { + // create an empty page if there is no result + return Flux.just(BridgeInternal.createFeedResponse(Utils.immutableListOf(), + headerResponse(tracker.getAndResetCharge()))); + })); + } + } + + @Override + public Flux> drainAsync( + int maxPageSize) { + List.DocumentProducerFeedResponse>> obs = this.documentProducers + // Get the stream. + .stream() + // Start from the left most partition first. + .sorted(Comparator.comparing(dp -> dp.targetRange.getMinInclusive())) + // For each partition get it's stream of results. + .map(DocumentProducer::produceAsync) + // Merge results from all partitions. + .collect(Collectors.toList()); + return Flux.concat(obs).compose(new EmptyPagesFilterTransformer<>(new RequestChargeTracker())); + } + + @Override + public Flux> executeAsync() { + return this.drainAsync(feedOptions.maxItemCount()); + } + + protected DocumentProducer createDocumentProducer( + String collectionRid, + PartitionKeyRange targetRange, + String initialContinuationToken, + int initialPageSize, + FeedOptions feedOptions, + SqlQuerySpec querySpecForInit, + Map commonRequestHeaders, + TriFunction createRequestFunc, + Function>> executeFunc, + Callable createRetryPolicyFunc) { + return new DocumentProducer(client, + collectionRid, + feedOptions, + createRequestFunc, + executeFunc, + targetRange, + collectionRid, + () -> client.getResetSessionTokenRetryPolicy().getRequestPolicy(), + resourceType, + correlatedActivityId, + initialPageSize, + initialContinuationToken, + top); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContextBase.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContextBase.java new file mode 100644 index 0000000000000..52625723d24c2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelDocumentQueryExecutionContextBase.java @@ -0,0 +1,157 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IDocumentClientRetryPolicy; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.routing.Range; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public abstract class ParallelDocumentQueryExecutionContextBase + extends DocumentQueryExecutionContextBase implements IDocumentQueryExecutionComponent { + + protected final List> documentProducers; + protected final List partitionKeyRanges; + protected final SqlQuerySpec querySpec; + protected int pageSize; + protected int top = -1; + + protected ParallelDocumentQueryExecutionContextBase(IDocumentQueryClient client, + List partitionKeyRanges, ResourceType resourceTypeEnum, Class resourceType, + SqlQuerySpec query, FeedOptions feedOptions, String resourceLink, String rewrittenQuery, + boolean isContinuationExpected, boolean getLazyFeedResponse, UUID correlatedActivityId) { + super(client, resourceTypeEnum, resourceType, query, feedOptions, resourceLink, getLazyFeedResponse, + correlatedActivityId); + + documentProducers = new ArrayList<>(); + + this.partitionKeyRanges = partitionKeyRanges; + + if (!Strings.isNullOrEmpty(rewrittenQuery)) { + this.querySpec = new SqlQuerySpec(rewrittenQuery, super.query.parameters()); + } else { + this.querySpec = super.query; + } + } + + protected void initialize(String collectionRid, + Map partitionKeyRangeToContinuationTokenMap, int initialPageSize, + SqlQuerySpec querySpecForInit) { + this.pageSize = initialPageSize; + Map commonRequestHeaders = createCommonHeadersAsync(this.getFeedOptions(null, null)); + + for (PartitionKeyRange targetRange : partitionKeyRangeToContinuationTokenMap.keySet()) { + TriFunction createRequestFunc = (partitionKeyRange, + continuationToken, pageSize) -> { + Map headers = new HashMap<>(commonRequestHeaders); + headers.put(HttpConstants.HttpHeaders.CONTINUATION, continuationToken); + headers.put(HttpConstants.HttpHeaders.PAGE_SIZE, Strings.toString(pageSize)); + return this.createDocumentServiceRequest(headers, querySpecForInit, partitionKeyRange, collectionRid); + }; + + Function>> executeFunc = (request) -> { + return this.executeRequestAsync(request).flux(); + }; + + DocumentProducer dp = createDocumentProducer(collectionRid, targetRange, + partitionKeyRangeToContinuationTokenMap.get(targetRange), initialPageSize, feedOptions, + querySpecForInit, commonRequestHeaders, createRequestFunc, executeFunc, + () -> client.getResetSessionTokenRetryPolicy().getRequestPolicy()); + + documentProducers.add(dp); + } + } + + protected int FindTargetRangeAndExtractContinuationTokens( + List partitionKeyRanges, Range range) throws CosmosClientException { + if (partitionKeyRanges == null) { + throw new IllegalArgumentException("partitionKeyRanges can not be null."); + } + + if (partitionKeyRanges.size() < 1) { + throw new IllegalArgumentException("partitionKeyRanges must have atleast one element."); + } + + for (PartitionKeyRange partitionKeyRange : partitionKeyRanges) { + if (partitionKeyRange == null) { + throw new IllegalArgumentException("partitionKeyRanges can not have null elements."); + } + } + + // Find the minimum index. + PartitionKeyRange needle = new PartitionKeyRange(/* id */ null, range.getMin(), range.getMax()); + int minIndex; + for (minIndex = 0; minIndex < partitionKeyRanges.size(); minIndex++) { + if (needle.getMinInclusive().equals(partitionKeyRanges.get(minIndex).getMinInclusive())) { + break; + } + } + + if (minIndex == partitionKeyRanges.size()) { + throw BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + String.format("Could not find partition key range for continuation token: {0}", needle)); + } + + return minIndex; + } + + abstract protected DocumentProducer createDocumentProducer(String collectionRid, PartitionKeyRange targetRange, + String initialContinuationToken, int initialPageSize, FeedOptions feedOptions, SqlQuerySpec querySpecForInit, + Map commonRequestHeaders, + TriFunction createRequestFunc, + Function>> executeFunc, + Callable createRetryPolicyFunc); + + @Override + abstract public Flux> drainAsync(int maxPageSize); + + public void setTop(int newTop) { + this.top = newTop; + + for (DocumentProducer producer : this.documentProducers) { + producer.top = newTop; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelQueryConfig.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelQueryConfig.java new file mode 100644 index 0000000000000..6544f64583e84 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ParallelQueryConfig.java @@ -0,0 +1,33 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class ParallelQueryConfig { + + public static final int ClientInternalPageSize = 100; + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfo.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfo.java new file mode 100644 index 0000000000000..cdf64044c4140 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfo.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.routing.Range; + +import java.util.List; + +/** + * Used internally to encapsulates execution information for a query in the Azure Cosmos DB database service. + */ +public final class PartitionedQueryExecutionInfo extends JsonSerializable { + @SuppressWarnings("unchecked") + private static final Class> QUERY_RANGES_CLASS = (Class>) Range + .getEmptyRange((String) null).getClass(); + + private QueryInfo queryInfo; + private List> queryRanges; + + PartitionedQueryExecutionInfo(QueryInfo queryInfo, List> queryRanges) { + this.queryInfo = queryInfo; + this.queryRanges = queryRanges; + + BridgeInternal.setProperty(this, + PartitionedQueryExecutionInfoInternal.PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, + Constants.PartitionedQueryExecutionInfo.VERSION_1); + } + + public PartitionedQueryExecutionInfo(String jsonString) { + super(jsonString); + } + + public int getVersion() { + return super.getInt(PartitionedQueryExecutionInfoInternal.PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY); + } + + public QueryInfo getQueryInfo() { + return this.queryInfo != null ? this.queryInfo + : (this.queryInfo = super.getObject( + PartitionedQueryExecutionInfoInternal.QUERY_INFO_PROPERTY, QueryInfo.class)); + } + + public List> getQueryRanges() { + return this.queryRanges != null ? this.queryRanges + : (this.queryRanges = super.getList( + PartitionedQueryExecutionInfoInternal.QUERY_RANGES_PROPERTY, QUERY_RANGES_CLASS)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfoInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfoInternal.java new file mode 100644 index 0000000000000..64b0061044c8d --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PartitionedQueryExecutionInfoInternal.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Constants; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.Range; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.util.List; + +public final class PartitionedQueryExecutionInfoInternal extends JsonSerializable { + static final String QUERY_INFO_PROPERTY = "queryInfo"; + static final String QUERY_RANGES_PROPERTY = "queryRanges"; + static final String PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY = "partitionedQueryExecutionInfoVersion"; + + @SuppressWarnings("unchecked") + private static final Class> QUERY_RANGE_CLASS = (Class>) Range + .getEmptyRange((PartitionKeyInternal) null).getClass(); + + private QueryInfo queryInfo; + private List> queryRanges; + + public PartitionedQueryExecutionInfoInternal() { + BridgeInternal.setProperty(this, PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY, Constants.PartitionedQueryExecutionInfo.VERSION_1); + } + + public PartitionedQueryExecutionInfoInternal(String jsonString) { + super(jsonString); + } + + public int getVersion() { + return super.getInt(PARTITIONED_QUERY_EXECUTION_INFO_VERSION_PROPERTY); + } + + public QueryInfo getQueryInfo() { + return this.queryInfo != null ? this.queryInfo + : (this.queryInfo = super.getObject(QUERY_INFO_PROPERTY, QueryInfo.class)); + } + + public void setQueryInfo(QueryInfo queryInfo) { + this.queryInfo = queryInfo; + } + + public List> getQueryRanges() { + return this.queryRanges != null ? this.queryRanges + : (this.queryRanges = super.getList(QUERY_RANGES_PROPERTY, QUERY_RANGE_CLASS)); + } + + public void setQueryRanges(List> queryRanges) { + this.queryRanges = queryRanges; + } + + public String toJson() { + try { + return Utils.getSimpleObjectMapper().writeValueAsString(this); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Unable to serialize partition query execution info internal."); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PipelinedDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PipelinedDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..606d95618af60 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/PipelinedDocumentQueryExecutionContext.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.Utils; +import reactor.core.publisher.Flux; + +import java.util.List; +import java.util.UUID; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public class PipelinedDocumentQueryExecutionContext implements IDocumentQueryExecutionContext { + + private IDocumentQueryExecutionComponent component; + private int actualPageSize; + private UUID correlatedActivityId; + + private PipelinedDocumentQueryExecutionContext(IDocumentQueryExecutionComponent component, int actualPageSize, + UUID correlatedActivityId) { + this.component = component; + this.actualPageSize = actualPageSize; + this.correlatedActivityId = correlatedActivityId; + + // this.executeNextSchedulingMetrics = new SchedulingStopwatch(); + // this.executeNextSchedulingMetrics.Ready(); + + // DefaultTrace.TraceVerbose(string.Format( + // CultureInfo.InvariantCulture, + // "{0} Pipelined~Context, actual page size: {1}", + // DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture), + // this.actualPageSize)); + } + + public static Flux> createAsync( + IDocumentQueryClient client, ResourceType resourceTypeEnum, Class resourceType, SqlQuerySpec expression, + FeedOptions feedOptions, String resourceLink, String collectionRid, + PartitionedQueryExecutionInfo partitionedQueryExecutionInfo, List targetRanges, + int initialPageSize, boolean isContinuationExpected, boolean getLazyFeedResponse, + UUID correlatedActivityId) { + // Use nested callback pattern to unwrap the continuation token at each level. + Function>> createBaseComponentFunction; + + QueryInfo queryInfo = partitionedQueryExecutionInfo.getQueryInfo(); + + if (queryInfo.hasOrderBy()) { + createBaseComponentFunction = (continuationToken) -> { + FeedOptions orderByFeedOptions = new FeedOptions(feedOptions); + orderByFeedOptions.requestContinuation(continuationToken); + return OrderByDocumentQueryExecutionContext.createAsync(client, resourceTypeEnum, resourceType, + expression, orderByFeedOptions, resourceLink, collectionRid, partitionedQueryExecutionInfo, + targetRanges, initialPageSize, isContinuationExpected, getLazyFeedResponse, + correlatedActivityId); + }; + } else { + createBaseComponentFunction = (continuationToken) -> { + FeedOptions parallelFeedOptions = new FeedOptions(feedOptions); + parallelFeedOptions.requestContinuation(continuationToken); + return ParallelDocumentQueryExecutionContext.createAsync(client, resourceTypeEnum, resourceType, + expression, parallelFeedOptions, resourceLink, collectionRid, partitionedQueryExecutionInfo, + targetRanges, initialPageSize, isContinuationExpected, getLazyFeedResponse, + correlatedActivityId); + }; + } + + Function>> createAggregateComponentFunction; + if (queryInfo.hasAggregates()) { + createAggregateComponentFunction = (continuationToken) -> { + return AggregateDocumentQueryExecutionContext.createAsync(createBaseComponentFunction, + queryInfo.getAggregates(), continuationToken); + }; + } else { + createAggregateComponentFunction = createBaseComponentFunction; + } + + Function>> createTopComponentFunction; + if (queryInfo.hasTop()) { + createTopComponentFunction = (continuationToken) -> { + return TopDocumentQueryExecutionContext.createAsync(createAggregateComponentFunction, + queryInfo.getTop(), continuationToken); + }; + } else { + createTopComponentFunction = createAggregateComponentFunction; + } + + int actualPageSize = Utils.getValueOrDefault(feedOptions.maxItemCount(), + ParallelQueryConfig.ClientInternalPageSize); + + if (actualPageSize == -1) { + actualPageSize = Integer.MAX_VALUE; + } + + int pageSize = Math.min(actualPageSize, Utils.getValueOrDefault(queryInfo.getTop(), (actualPageSize))); + return createTopComponentFunction.apply(feedOptions.requestContinuation()) + .map(c -> new PipelinedDocumentQueryExecutionContext<>(c, pageSize, correlatedActivityId)); + } + + @Override + public Flux> executeAsync() { + // TODO Auto-generated method stub + + // TODO add more code here + return this.component.drainAsync(actualPageSize); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ProxyDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ProxyDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..a3980bea91665 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/ProxyDocumentQueryExecutionContext.java @@ -0,0 +1,186 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.Exceptions; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.lang.invoke.MethodHandles; +import java.util.List; +import java.util.UUID; +import java.util.function.Function; + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + * + * This class is used as a proxy to wrap the + * DefaultDocumentQueryExecutionContext which is needed for sending the query to + * GATEWAY first and then uses PipelinedDocumentQueryExecutionContext after it + * gets the necessary info. + */ +public class ProxyDocumentQueryExecutionContext implements IDocumentQueryExecutionContext { + + private IDocumentQueryExecutionContext innerExecutionContext; + private IDocumentQueryClient client; + private ResourceType resourceTypeEnum; + private Class resourceType; + private FeedOptions feedOptions; + private SqlQuerySpec query; + private String resourceLink; + private DocumentCollection collection; + private UUID correlatedActivityId; + private boolean isContinuationExpected; + private final static Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + public ProxyDocumentQueryExecutionContext( + IDocumentQueryExecutionContext innerExecutionContext, + IDocumentQueryClient client, + ResourceType resourceTypeEnum, + Class resourceType, + SqlQuerySpec query, + FeedOptions feedOptions, + String resourceLink, + DocumentCollection collection, + boolean isContinuationExpected, + UUID correlatedActivityId) { + this.innerExecutionContext = innerExecutionContext; + + this.client = client; + this.resourceTypeEnum = resourceTypeEnum; + this.resourceType = resourceType; + this.query = query; + this.feedOptions = feedOptions; + this.resourceLink = resourceLink; + + this.collection = collection; + this.isContinuationExpected = isContinuationExpected; + this.correlatedActivityId = correlatedActivityId; + } + + @Override + public Flux> executeAsync() { + + Function>> func = t -> { + + logger.debug("Received non result message from gateway", t); + if (!(t instanceof Exception)) { + logger.error("Unexpected failure", t); + return Flux.error(t); + } + + if (!isCrossPartitionQuery((Exception) t)) { + // If this is not a cross partition query then propagate error + logger.debug("Failure from gateway", t); + return Flux.error(t); + } + + logger.debug("Setting up query pipeline using the query plan received form gateway"); + + // cross partition query construct pipeline + + CosmosClientException dce = (CosmosClientException) t; + + PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = new + PartitionedQueryExecutionInfo(dce.error().getPartitionedQueryExecutionInfo()); + + logger.debug("Query Plan from gateway {}", partitionedQueryExecutionInfo); + + DefaultDocumentQueryExecutionContext queryExecutionContext = + (DefaultDocumentQueryExecutionContext) this.innerExecutionContext; + + Mono> partitionKeyRanges = queryExecutionContext.getTargetPartitionKeyRanges(collection.resourceId(), + partitionedQueryExecutionInfo.getQueryRanges()); + + Flux> exContext = partitionKeyRanges.flux() + .flatMap(pkranges -> DocumentQueryExecutionContextFactory.createSpecializedDocumentQueryExecutionContextAsync( + this.client, + this.resourceTypeEnum, + this.resourceType, + this.query, + this.feedOptions, + this.resourceLink, + isContinuationExpected, + partitionedQueryExecutionInfo, + pkranges, + this.collection.resourceId(), + this.correlatedActivityId)); + + return exContext.flatMap(IDocumentQueryExecutionContext::executeAsync); + }; + + return this.innerExecutionContext.executeAsync().onErrorResume(func); + } + + private boolean isCrossPartitionQuery(Exception exception) { + + CosmosClientException clientException = Utils.as(exception, CosmosClientException.class); + + if (clientException == null) { + return false; + } + + return (Exceptions.isStatusCode(clientException, HttpConstants.StatusCodes.BADREQUEST) && + Exceptions.isSubStatusCode(clientException, HttpConstants.SubStatusCodes.CROSS_PARTITION_QUERY_NOT_SERVABLE)); + } + + public static Flux> createAsync(IDocumentQueryClient client, + ResourceType resourceTypeEnum, Class resourceType, SqlQuerySpec query, FeedOptions feedOptions, + String resourceLink, DocumentCollection collection, boolean isContinuationExpected, + UUID correlatedActivityId) { + + IDocumentQueryExecutionContext innerExecutionContext = + new DefaultDocumentQueryExecutionContext( + client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + correlatedActivityId, + isContinuationExpected); + + return Flux.just(new ProxyDocumentQueryExecutionContext(innerExecutionContext, client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + collection, + isContinuationExpected, + correlatedActivityId)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryInfo.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryInfo.java new file mode 100644 index 0000000000000..8c4d6e1cd3c77 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryInfo.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.query.aggregation.AggregateOperator; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collection; +import java.util.List; + +/** + * Used internally to encapsulates a query's information in the Azure Cosmos DB database service. + */ +public final class QueryInfo extends JsonSerializable { + private Integer top; + private List orderBy; + private Collection aggregates; + private Collection orderByExpressions; + private String rewrittenQuery; + + public QueryInfo() { } + + public QueryInfo(String jsonString) { + super(jsonString); + } + + public Integer getTop() { + return this.top != null ? this.top : (this.top = super.getInt("top")); + } + + public List getOrderBy() { + return this.orderBy != null ? this.orderBy : (this.orderBy = super.getList("orderBy", SortOrder.class)); + } + + public String getRewrittenQuery() { + return this.rewrittenQuery != null ? this.rewrittenQuery + : (this.rewrittenQuery = super.getString("rewrittenQuery")); + } + + public boolean hasTop() { + return this.getTop() != null; + } + + public boolean hasOrderBy() { + Collection orderBy = this.getOrderBy(); + return orderBy != null && orderBy.size() > 0; + } + + public boolean hasRewrittenQuery() { + return !StringUtils.isEmpty(this.getRewrittenQuery()); + } + + public boolean hasAggregates() { + Collection aggregates = this.getAggregates(); + return aggregates != null && aggregates.size() > 0; + } + + public Collection getAggregates() { + return this.aggregates != null + ? this.aggregates + : (this.aggregates = super.getCollection("aggregates", AggregateOperator.class)); + } + + public Collection getOrderByExpressions() { + return this.orderByExpressions != null + ? this.orderByExpressions + : (this.orderByExpressions = super.getCollection("orderByExpressions", String.class)); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryItem.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryItem.java new file mode 100644 index 0000000000000..ff447462358be --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/QueryItem.java @@ -0,0 +1,48 @@ + +/** + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Undefined; + +/** + * Used internally for query in the Azure Cosmos DB database service. + */ +public final class QueryItem extends JsonSerializable { + private Object item; + + public QueryItem(String jsonString) { + super(jsonString); + } + + public Object getItem() { + if (this.item == null) { + Object rawItem = super.get("item"); + this.item = super.has("item") ? rawItem : Undefined.Value(); + } + + return this.item; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/SortOrder.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/SortOrder.java new file mode 100644 index 0000000000000..cbd6fccb8e613 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/SortOrder.java @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +/** + * Sort order in the Azure Cosmos DB database service. + */ +public enum SortOrder { + Ascending, Descending, +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TakeContinuationToken.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TakeContinuationToken.java new file mode 100644 index 0000000000000..37562f903246a --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TakeContinuationToken.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * While this class is public, but it is not part of our published public APIs. + * This is meant to be internally used only by our sdk. + */ +public final class TakeContinuationToken extends JsonSerializable { + private static final String LimitPropertyName = "limit"; + private static final String SourceTokenPropetryName = "sourceToken"; + private static final Logger logger = LoggerFactory.getLogger(TakeContinuationToken.class); + + public TakeContinuationToken(int takeCount, String sourceToken) { + if (takeCount < 0) { + throw new IllegalArgumentException("takeCount must be a non negative number."); + } + + // sourceToken is allowed to be null. + this.setTakeCount(takeCount); + this.setSourceToken(sourceToken); + } + + private TakeContinuationToken(String serializedTakeContinuationToken) { + super(serializedTakeContinuationToken); + } + + public static boolean tryParse(String serializedTakeContinuationToken, + ValueHolder outTakeContinuationToken) { + boolean parsed; + try { + TakeContinuationToken takeContinuationToken = new TakeContinuationToken(serializedTakeContinuationToken); + takeContinuationToken.getSourceToken(); + takeContinuationToken.getTakeCount(); + outTakeContinuationToken.v = takeContinuationToken; + parsed = true; + } catch (Exception ex) { + logger.debug( + "Received exception {} when trying to parse: {}", + ex.getMessage(), + serializedTakeContinuationToken); + parsed = false; + outTakeContinuationToken.v = null; + } + + return parsed; + } + + public int getTakeCount() { + return super.getInt(LimitPropertyName); + } + + public String getSourceToken() { + return super.getString(SourceTokenPropetryName); + } + + private void setTakeCount(int takeCount) { + BridgeInternal.setProperty(this, LimitPropertyName, takeCount); + } + + private void setSourceToken(String sourceToken) { + BridgeInternal.setProperty(this, SourceTokenPropetryName, sourceToken); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TopDocumentQueryExecutionContext.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TopDocumentQueryExecutionContext.java new file mode 100644 index 0000000000000..661b132cf5a90 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TopDocumentQueryExecutionContext.java @@ -0,0 +1,148 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import reactor.core.publisher.Flux; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +public class TopDocumentQueryExecutionContext implements IDocumentQueryExecutionComponent { + + private final IDocumentQueryExecutionComponent component; + private final int top; + + public TopDocumentQueryExecutionContext(IDocumentQueryExecutionComponent component, int top) { + this.component = component; + this.top = top; + } + + public static Flux> createAsync( + Function>> createSourceComponentFunction, + int topCount, String topContinuationToken) { + TakeContinuationToken takeContinuationToken; + + if (topContinuationToken == null) { + takeContinuationToken = new TakeContinuationToken(topCount, null); + } else { + ValueHolder outTakeContinuationToken = new ValueHolder(); + if (!TakeContinuationToken.tryParse(topContinuationToken, outTakeContinuationToken)) { + String message = String.format("INVALID JSON in continuation token %s for Top~Context", + topContinuationToken); + CosmosClientException dce = BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, + message); + return Flux.error(dce); + } + + takeContinuationToken = outTakeContinuationToken.v; + } + + if (takeContinuationToken.getTakeCount() > topCount) { + String message = String.format( + "top count in continuation token: %d can not be greater than the top count in the query: %d.", + takeContinuationToken.getTakeCount(), topCount); + CosmosClientException dce = BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, message); + return Flux.error(dce); + } + + return createSourceComponentFunction + .apply(takeContinuationToken.getSourceToken()) + .map(component -> new TopDocumentQueryExecutionContext<>(component, takeContinuationToken.getTakeCount())); + } + + @Override + public Flux> drainAsync(int maxPageSize) { + ParallelDocumentQueryExecutionContextBase context; + + if (this.component instanceof AggregateDocumentQueryExecutionContext) { + context = (ParallelDocumentQueryExecutionContextBase) ((AggregateDocumentQueryExecutionContext) this.component) + .getComponent(); + } else { + context = (ParallelDocumentQueryExecutionContextBase) this.component; + } + + context.setTop(this.top); + + return this.component.drainAsync(maxPageSize).takeUntil(new Predicate>() { + + private volatile int fetchedItems = 0; + + @Override + public boolean test(FeedResponse frp) { + + fetchedItems += frp.results().size(); + + // take until we have at least top many elements fetched + return fetchedItems >= top; + } + }).map(new Function, FeedResponse>() { + + private volatile int collectedItems = 0; + private volatile boolean lastPage = false; + + @Override + public FeedResponse apply(FeedResponse t) { + + if (collectedItems + t.results().size() <= top) { + collectedItems += t.results().size(); + + Map headers = new HashMap<>(t.responseHeaders()); + if (top != collectedItems) { + // Add Take Continuation Token + String sourceContinuationToken = t.continuationToken(); + TakeContinuationToken takeContinuationToken = new TakeContinuationToken(top - collectedItems, + sourceContinuationToken); + headers.put(HttpConstants.HttpHeaders.CONTINUATION, takeContinuationToken.toJson()); + } else { + // Null out the continuation token + headers.put(HttpConstants.HttpHeaders.CONTINUATION, null); + } + + return BridgeInternal.createFeedResponseWithQueryMetrics(t.results(), headers, + BridgeInternal.queryMetricsFromFeedResponse(t)); + } else { + assert lastPage == false; + lastPage = true; + int lastPageSize = top - collectedItems; + collectedItems += lastPageSize; + + // Null out the continuation token + Map headers = new HashMap<>(t.responseHeaders()); + headers.put(HttpConstants.HttpHeaders.CONTINUATION, null); + + return BridgeInternal.createFeedResponseWithQueryMetrics(t.results().subList(0, lastPageSize), + headers, BridgeInternal.queryMetricsFromFeedResponse(t)); + } + } + }); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TriFunction.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TriFunction.java new file mode 100644 index 0000000000000..fc4772ad8e940 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/TriFunction.java @@ -0,0 +1,23 @@ +package com.azure.data.cosmos.internal.query; + +/** + * A functional interface (callback) that computes a value based on multiple input values. + * @param the first value type + * @param the second value type + * @param the third value type + * @param the result type + */ + +@FunctionalInterface +public interface TriFunction { + + /** + * Applies this function to the given arguments. + * + * @param t the first function argument + * @param u the second function argument + * @param v the third function argument + * @return the function result + */ + R apply(T t, U u, V v); +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AggregateOperator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AggregateOperator.java new file mode 100644 index 0000000000000..b84421411f04c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AggregateOperator.java @@ -0,0 +1,32 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +public enum AggregateOperator { + Average, + Count, + Max, + Min, + Sum +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/Aggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/Aggregator.java new file mode 100644 index 0000000000000..82a6301bc8d3c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/Aggregator.java @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +public interface Aggregator { + void aggregate(Object item); + + Object getResult(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AverageAggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AverageAggregator.java new file mode 100644 index 0000000000000..d64ba353914c5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/AverageAggregator.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.Utils; + +import java.io.IOException; + +public class AverageAggregator implements Aggregator { + private AverageInfo averageInfo; + + public AverageAggregator() { + this.averageInfo = new AverageInfo(); + } + + @Override + public void aggregate(Object item) { + AverageInfo averageInfo; + try { + averageInfo = Utils.getSimpleObjectMapper().readValue(item.toString(), AverageInfo.class); + } catch (IOException e) { + throw new IllegalStateException("Failed to deserialize aggregate result"); + } + this.averageInfo.add(averageInfo); + } + + @Override + public Object getResult() { + return this.averageInfo.getAverage(); + } + + private static class AverageInfo { + public Double sum; + public long count; + + public void add(AverageInfo other) { + if (other == null) { + throw new IllegalArgumentException("other"); + } + if (other.sum == null) { + return; + } + if (this.sum == null) { + this.sum = 0.0; + } + + this.sum += other.sum; + this.count += other.count; + } + + Object getAverage() { + if (this.sum == null || this.count <= 0) { + return Undefined.Value(); + } + return this.sum / this.count; + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/CountAggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/CountAggregator.java new file mode 100644 index 0000000000000..bb18db582ed57 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/CountAggregator.java @@ -0,0 +1,39 @@ + +/** + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +public class CountAggregator implements Aggregator { + private long value; + + @Override + public void aggregate(Object item) { + value += Long.parseLong(item.toString()); + } + + @Override + public Object getResult() { + return value; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MaxAggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MaxAggregator.java new file mode 100644 index 0000000000000..ea59e3b4538e6 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MaxAggregator.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.query.ItemComparator; + +public class MaxAggregator implements Aggregator { + private Object value; + + public MaxAggregator() { + this.value = Undefined.Value(); + } + + @Override + public void aggregate(Object item) { + if (Undefined.Value().equals(this.value)) { + this.value = item; + } else if (ItemComparator.getInstance().compare(item, this.value) > 0) { + this.value = item; + } + + } + + @Override + public Object getResult() { + return this.value; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MinAggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MinAggregator.java new file mode 100644 index 0000000000000..981e55a957b89 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/MinAggregator.java @@ -0,0 +1,49 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.query.ItemComparator; + +public class MinAggregator implements Aggregator { + private Object value; + + public MinAggregator() { + this.value = Undefined.Value(); + } + + @Override + public void aggregate(Object item) { + if (Undefined.Value().equals(this.value)) { + this.value = item; + } else if (ItemComparator.getInstance().compare(item, this.value) < 0) { + this.value = item; + } + } + + @Override + public Object getResult() { + return this.value; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/SumAggregator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/SumAggregator.java new file mode 100644 index 0000000000000..0d238dc9a0c00 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/aggregation/SumAggregator.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.aggregation; + +import com.azure.data.cosmos.internal.Undefined; + +public class SumAggregator implements Aggregator { + private Double sum; + + @Override + public void aggregate(Object item) { + if (Undefined.Value().equals(item)) { + return; + } + + if (this.sum == null) { + this.sum = 0.0; + } + this.sum += ((Number) item).doubleValue(); + } + + @Override + public Object getResult() { + if (this.sum == null) { + return Undefined.Value(); + } + return this.sum; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/ClientSideMetrics.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/ClientSideMetrics.java new file mode 100644 index 0000000000000..f29d1c001a0ba --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/ClientSideMetrics.java @@ -0,0 +1,143 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +/** + * Client side QueryMetrics + */ +public class ClientSideMetrics { + + public static final ClientSideMetrics ZERO = new ClientSideMetrics( + 0, /* retries*/ + 0, /* requestCharge */ + new ArrayList<>(), /* fetchExecutionRanges */ + new ArrayList<>()); /* partitionSchedulingTimeSpans */ + + private final long retries; + private final double requestCharge; + private final List fetchExecutionRanges; + private final List> partitionSchedulingTimeSpans; + + /** + * Constructor + * + * @param retries The number of retries required to execute the query. + * @param requestCharge The request charge incurred from executing the query. + * @param executionRanges The fetch execution ranges from executing the query. + * @param schedulingTimeSpans The partition scheduling timespans from the query. + */ + public ClientSideMetrics(int retries, double requestCharge, List executionRanges, + List> schedulingTimeSpans) { + if (executionRanges == null || executionRanges.contains(null)) { + throw new NullPointerException("executionRanges"); + } + if (schedulingTimeSpans == null || schedulingTimeSpans.contains(null)) { + throw new NullPointerException("schedulingTimeSpans"); + } + if (retries < 0) { + throw new IllegalArgumentException("retries must not be negative"); + } + if (requestCharge < 0) { + throw new IllegalArgumentException("requestCharge must not be negative"); + } + + this.retries = retries; + this.requestCharge = requestCharge; + this.fetchExecutionRanges = executionRanges; + this.partitionSchedulingTimeSpans = schedulingTimeSpans; + } + + /** + * Gets number of retries in the Azure Cosmos database service + * + * @return the retries + */ + public long getRetries() { + return retries; + } + + /** + * Gets the request charge for this continuation of the query. + * + * @return the requestCharge + */ + public double getRequestCharge() { + return requestCharge; + } + + /** + * create ClientSideMetrics from collection + * + * @param clientSideMetricsCollection + * @return + */ + public static ClientSideMetrics createFromCollection(Collection clientSideMetricsCollection) { + if (clientSideMetricsCollection == null) { + throw new NullPointerException("clientSideMetricsCollection"); + } + + int retries = 0; + double requestCharge = 0; + List fetchExecutionRanges = new ArrayList<>(); + List> partitionSchedulingTimeSpans = new ArrayList<>(); + + for (ClientSideMetrics clientSideQueryMetrics : clientSideMetricsCollection) { + retries += clientSideQueryMetrics.retries; + requestCharge += clientSideQueryMetrics.requestCharge; + fetchExecutionRanges.addAll(clientSideQueryMetrics.fetchExecutionRanges); + partitionSchedulingTimeSpans.addAll(clientSideQueryMetrics.partitionSchedulingTimeSpans); + } + + return new ClientSideMetrics(retries, requestCharge, fetchExecutionRanges, partitionSchedulingTimeSpans); + } + + static double getOrDefault(HashMap metrics, String key) { + Double doubleReference = metrics.get(key); + return doubleReference == null ? 0 : doubleReference; + } + + /** + * Gets the Fetch Execution Ranges for this continuation of the query. + * + * @return the Fetch Execution Ranges for this continuation of the query + */ + public List getFetchExecutionRanges() { + return fetchExecutionRanges; + } + + /** + * Gets the Partition Scheduling TimeSpans for this query. + * + * @return the List of Partition Scheduling TimeSpans for this query + */ + public List> getPartitionSchedulingTimeSpans() { + return partitionSchedulingTimeSpans; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRange.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRange.java new file mode 100644 index 0000000000000..b0cfc0a2d1bac --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRange.java @@ -0,0 +1,110 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +import java.time.Instant; + +/** + * Stores information about fetch execution + */ +public class FetchExecutionRange { + private final Instant startTime; + private final Instant endTime; + private final String partitionId; + private final long numberOfDocuments; + private final long retryCount; + private final String activityId; + + /** + * Constructor + * + * @param activityId The activityId of the fetch + * @param startTime The start time of the fetch + * @param endTime The end time of the fetch + * @param partitionId The partitionkeyrangeid from which you are fetching for + * @param numberOfDocuments The number of documents that were fetched in the particular execution range + * @param retryCount The number of times we retried for this fetch execution range + */ + FetchExecutionRange(String activityId, Instant startTime, Instant endTime, String partitionId, long numberOfDocuments, long retryCount) { + this.activityId = activityId; + this.startTime = startTime; + this.endTime = endTime; + this.partitionId = partitionId; + this.numberOfDocuments = numberOfDocuments; + this.retryCount = retryCount; + } + + /** + * Gets the start time of the fetch. + * + * @return the start time of the fetch. + */ + public Instant getStartTime() { + return startTime; + } + + /** + * Gets the end time of the fetch. + * + * @return the end time of the fetch. + */ + public Instant getEndTime() { + return endTime; + } + + /** + * Gets the partition id that was fetched from. + * + * @return the partition id that was fetched from. + */ + public String getPartitionId() { + return partitionId; + } + + /** + * Gets the number of documents that where fetched in the particular execution range. + * + * @return the number of documents that where fetched in the particular execution range. + */ + public long getNumberOfDocuments() { + return numberOfDocuments; + } + + /** + * Gets the number of times we retried for this fetch execution range. + * + * @return the number of times we retried for this fetch execution range. + */ + public long getRetryCount() { + return retryCount; + } + + /** + * Gets the activityId of the fetch. + * + * @return the activityId of the fetch. + */ + public String getActivityId() { + return activityId; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRangeAccumulator.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRangeAccumulator.java new file mode 100644 index 0000000000000..3f86b0d01aef4 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/FetchExecutionRangeAccumulator.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +import org.apache.commons.lang3.time.StopWatch; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Accumlator that acts as a builder of FetchExecutionRanges + */ +public class FetchExecutionRangeAccumulator { + private final String partitionKeyRangeId; + private final Instant constructionTime; + private final StopWatch stopwatch; + private List fetchExecutionRanges; + private Instant startTime; + private Instant endTime; + private boolean isFetching; + + public FetchExecutionRangeAccumulator(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + this.constructionTime = Instant.now(); + // This stopwatch is always running and is only used to calculate deltas that are synchronized with the construction time. + this.stopwatch = new StopWatch(); + stopwatch.start(); + this.fetchExecutionRanges = new ArrayList(); + } + + /** + * Gets the FetchExecutionRanges and resets the accumulator. + * + * @return the SchedulingMetricsResult. + */ + public List getExecutionRanges() { + List returnValue = this.fetchExecutionRanges; + this.fetchExecutionRanges = new ArrayList<>(); + return returnValue; + } + + /** + * Updates the most recent start time internally. + */ + public void beginFetchRange() { + if (!this.isFetching) { + // Calculating the start time as the construction time and the stopwatch as a delta. + this.startTime = this.constructionTime.plus(Duration.ofMillis(this.stopwatch.getTime(TimeUnit.MILLISECONDS))); + this.isFetching = true; + } + } + + /** + * Updates the most recent end time internally and constructs a new FetchExecutionRange + * + * @param numberOfDocuments The number of documents that were fetched for this range. + * @param retryCount The number of times we retried for this fetch execution range. + */ + public void endFetchRange(String activityId, long numberOfDocuments, long retryCount) { + if (this.isFetching) { + // Calculating the end time as the construction time and the stopwatch as a delta. + this.endTime = this.constructionTime.plus(Duration.ofMillis(this.stopwatch.getTime(TimeUnit.MILLISECONDS))); + FetchExecutionRange fetchExecutionRange = new FetchExecutionRange( + activityId, + this.startTime, + this.endTime, + this.partitionKeyRangeId, + numberOfDocuments, + retryCount); + this.fetchExecutionRanges.add(fetchExecutionRange); + this.isFetching = false; + } + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsTextWriter.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsTextWriter.java new file mode 100644 index 0000000000000..171edf56b41d9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsTextWriter.java @@ -0,0 +1,600 @@ +package com.azure.data.cosmos.internal.query.metrics; + +import org.apache.commons.lang3.StringUtils; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +public class QueryMetricsTextWriter extends QueryMetricsWriter { + + private final StringBuilder stringBuilder; + + // QueryMetrics + private static final String ActivityIds = "Activity Ids"; + private static final String RetrievedDocumentCount = "Retrieved Document Count"; + private static final String RetrievedDocumentSize = "Retrieved Document Size"; + private static final String OutputDocumentCount = "Output Document Count"; + private static final String OutputDocumentSize = "Output Document Size"; + private static final String IndexUtilizationText = "Index Utilization"; + private static final String TotalQueryExecutionTime = "Total Query Execution Time"; + + // QueryPreparationTimes + private static final String QueryPreparationTimes = "Query Preparation Times"; + private static final String QueryCompileTime = "Query Compilation Time"; + private static final String LogicalPlanBuildTime = "Logical Plan Build Time"; + private static final String PhysicalPlanBuildTime = "Physical Plan Build Time"; + private static final String QueryOptimizationTime = "Query Optimization Time"; + + // QueryTimes + private static final String QueryEngineTimes = "Query Engine Times"; + private static final String IndexLookupTime = "Index Lookup Time"; + private static final String DocumentLoadTime = "Document Load Time"; + private static final String DocumentWriteTime = "Document Write Time"; + + // RuntimeExecutionTimes + private static final String RuntimeExecutionTimes = "Runtime Execution Times"; + private static final String TotalExecutionTime = "Query Engine Execution Time"; + private static final String SystemFunctionExecuteTime = "System Function Execution Time"; + private static final String UserDefinedFunctionExecutionTime = "User-defined Function Execution Time"; + + // ClientSideQueryMetrics + private static final String ClientSideQueryMetrics = "Client Side Metrics"; + private static final String Retries = "Retry Count"; + private static final String RequestCharge = "Request Charge"; + private static final String FetchExecutionRanges = "Partition Execution Timeline"; + private static final String SchedulingMetrics = "Scheduling Metrics"; + + // Constants for Partition Execution Timeline Table + private static final String StartTimeHeader = "Start Time (UTC)"; + private static final String EndTimeHeader = "End Time (UTC)"; + private static final String DurationHeader = "Duration (ms)"; + private static final String PartitionKeyRangeIdHeader = "Partition Id"; + private static final String NumberOfDocumentsHeader = "NUMBER of Documents"; + private static final String RetryCountHeader = "Retry Count"; + private static final String ActivityIdHeader = "Activity Id"; + + // Constants for Scheduling Metrics Table + private static final String PartitionIdHeader = "Partition Id"; + private static final String ResponseTimeHeader = "Response Time (ms)"; + private static final String RunTimeHeader = "Run Time (ms)"; + private static final String WaitTimeHeader = "Wait Time (ms)"; + private static final String TurnaroundTimeHeader = "Turnaround Time (ms)"; + private static final String NumberOfPreemptionHeader = "NUMBER of Preemptions"; + + // Static for Partition Execution Timeline Table + // private static int MaxDateTimeStringLength = LocalDateTime.MAX.toString().length(); + private static final int MaxDateTimeStringLength = 16; + private static final int StartTimeHeaderLength = Math.max(MaxDateTimeStringLength, StartTimeHeader.length()); + private static final int EndTimeHeaderLength = Math.max(MaxDateTimeStringLength, EndTimeHeader.length()); + private static final int DurationHeaderLength = DurationHeader.length(); + private static final int PartitionKeyRangeIdHeaderLength = PartitionKeyRangeIdHeader.length(); + private static final int NumberOfDocumentsHeaderLength = NumberOfDocumentsHeader.length(); + private static final int RetryCountHeaderLength = RetryCountHeader.length(); + private static final int ActivityIdHeaderLength = UUID.randomUUID().toString().length(); + + private static TextTable.Column[] PartitionExecutionTimelineColumns = new TextTable.Column[] + { + new TextTable.Column(PartitionKeyRangeIdHeader, PartitionKeyRangeIdHeaderLength), + new TextTable.Column(ActivityIdHeader, ActivityIdHeaderLength), + new TextTable.Column(StartTimeHeader, StartTimeHeaderLength), + new TextTable.Column(EndTimeHeader, EndTimeHeaderLength), + new TextTable.Column(DurationHeader, DurationHeaderLength), + new TextTable.Column(NumberOfDocumentsHeader, NumberOfDocumentsHeaderLength), + new TextTable.Column(RetryCountHeader, RetryCountHeaderLength), + }; + + private static TextTable PartitionExecutionTimelineTable = new TextTable(Arrays.asList(PartitionExecutionTimelineColumns)); + + // Static for Scheduling Metrics Table + //private static readonly int MaxTimeSpanStringLength = Math.Max(TimeSpan.MaxValue.TotalMilliseconds.ToString + // ("G17").Length, TurnaroundTimeHeader.Length); + private static final int PartitionIdHeaderLength = PartitionIdHeader.length(); + private static final int ResponseTimeHeaderLength = ResponseTimeHeader.length(); + private static final int RunTimeHeaderLength = RunTimeHeader.length(); + private static final int WaitTimeHeaderLength = WaitTimeHeader.length(); + private static final int TurnaroundTimeHeaderLength = TurnaroundTimeHeader.length(); + private static final int NumberOfPreemptionHeaderLength = NumberOfPreemptionHeader.length(); + + private static TextTable.Column[] SchedulingMetricsColumns = new TextTable.Column[] + { + new TextTable.Column(PartitionIdHeader, PartitionIdHeaderLength), + new TextTable.Column(ResponseTimeHeader, ResponseTimeHeaderLength), + new TextTable.Column(RunTimeHeader, RunTimeHeaderLength), + new TextTable.Column(WaitTimeHeader, WaitTimeHeaderLength), + new TextTable.Column(TurnaroundTimeHeader, TurnaroundTimeHeaderLength), + new TextTable.Column(NumberOfPreemptionHeader, NumberOfPreemptionHeaderLength), + }; + + private static TextTable SchedulingMetricsTable = new TextTable(Arrays.asList(SchedulingMetricsColumns)); + + // FetchExecutionRange state + private String lastFetchPartitionId; + private String lastActivityId; + private Instant lastStartTime; + private Instant lastEndTime; + private long lastFetchDocumentCount; + private long lastFetchRetryCount; + + // PartitionSchedulingTimeSpan state + private String lastSchedulingPartitionId; + private long lastResponseTime; + private long lastRunTime; + private long lastWaitTime; + private long lastTurnaroundTime; + private long lastNumberOfPreemptions; + + static DateTimeFormatter formatter = + DateTimeFormatter.ofPattern("HH:mm:ss:SSSS").withZone(ZoneOffset.UTC); + + public QueryMetricsTextWriter(StringBuilder stringBuilder) { + assert stringBuilder != null; + this.stringBuilder = stringBuilder; + } + + @Override + protected void writeBeforeQueryMetrics() { + // Do Nothing + } + + @Override + protected void writeRetrievedDocumentCount(long retrievedDocumentCount) { + QueryMetricsTextWriter.appendCountToStringBuilder(stringBuilder, + QueryMetricsTextWriter.RetrievedDocumentCount, retrievedDocumentCount, 0); + } + + @Override + protected void writeRetrievedDocumentSize(long retrievedDocumentSize) { + QueryMetricsTextWriter.appendBytesToStringBuilder(stringBuilder, QueryMetricsTextWriter.RetrievedDocumentSize + , retrievedDocumentSize, 0); + } + + @Override + protected void writeOutputDocumentCount(long outputDocumentCount) { + QueryMetricsTextWriter.appendCountToStringBuilder(stringBuilder, QueryMetricsTextWriter.OutputDocumentCount, + outputDocumentCount, 0); + } + + @Override + protected void writeOutputDocumentSize(long outputDocumentSize) { + QueryMetricsTextWriter.appendBytesToStringBuilder(stringBuilder, QueryMetricsTextWriter.OutputDocumentSize, + outputDocumentSize, 0); + } + + @Override + protected void writeIndexHitRatio(double indexHitRatio) { + QueryMetricsTextWriter.appendPercentageToStringBuilder(stringBuilder, QueryMetricsTextWriter.IndexUtilizationText + , indexHitRatio, 0); + } + + @Override + protected void writeTotalQueryExecutionTime(Duration totalQueryExecutionTime) { + QueryMetricsTextWriter.appendNanosecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.TotalQueryExecutionTime, durationToMilliseconds(totalQueryExecutionTime), 0); + } + + @Override + protected void writeBeforeQueryPreparationTimes() { + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, + QueryMetricsTextWriter.QueryPreparationTimes, 1); + } + + @Override + protected void writeQueryCompilationTime(Duration queryCompilationTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.QueryCompileTime, durationToMilliseconds(queryCompilationTime), 2); + } + + @Override + protected void writeLogicalPlanBuildTime(Duration logicalPlanBuildTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.LogicalPlanBuildTime, durationToMilliseconds(logicalPlanBuildTime), 2); + } + + @Override + protected void writePhysicalPlanBuildTime(Duration physicalPlanBuildTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.PhysicalPlanBuildTime, durationToMilliseconds(physicalPlanBuildTime), 2); + } + + @Override + protected void writeQueryOptimizationTime(Duration queryOptimizationTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.QueryOptimizationTime, durationToMilliseconds(queryOptimizationTime), 2); + } + + @Override + protected void writeAfterQueryPreparationTimes() { + // Do Nothing + } + + @Override + protected void writeIndexLookupTime(Duration indexLookupTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.IndexLookupTime, durationToMilliseconds(indexLookupTime), 1); + } + + @Override + protected void writeDocumentLoadTime(Duration documentLoadTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.DocumentLoadTime, durationToMilliseconds(documentLoadTime), 1); + } + + @Override + protected void writeVMExecutionTime(Duration vMExecutionTime) { + // Do Nothing + } + + @Override + protected void writeBeforeRuntimeExecutionTimes() { + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, + QueryMetricsTextWriter.RuntimeExecutionTimes, 1); + } + + @Override + protected void writeQueryEngineExecutionTime(Duration queryEngineExecutionTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.QueryEngineTimes, durationToMilliseconds(queryEngineExecutionTime), 2); + } + + @Override + protected void writeSystemFunctionExecutionTime(Duration systemFunctionExecutionTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.SystemFunctionExecuteTime, durationToMilliseconds(systemFunctionExecutionTime) + , 2); + } + + @Override + protected void writeUserDefinedFunctionExecutionTime(Duration userDefinedFunctionExecutionTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.UserDefinedFunctionExecutionTime, + durationToMilliseconds(userDefinedFunctionExecutionTime), 2); + } + + @Override + protected void writeAfterRuntimeExecutionTimes() { + // Do Nothing + } + + @Override + protected void writeDocumentWriteTime(Duration documentWriteTime) { + QueryMetricsTextWriter.appendMillisecondsToStringBuilder(stringBuilder, + QueryMetricsTextWriter.DocumentWriteTime, durationToMilliseconds(documentWriteTime), 1); + } + + @Override + protected void writeBeforeClientSideMetrics() { + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, + QueryMetricsTextWriter.ClientSideQueryMetrics, 0); + } + + @Override + protected void writeRetries(long retries) { + QueryMetricsTextWriter.appendCountToStringBuilder(stringBuilder, QueryMetricsTextWriter.Retries, retries, 1); + } + + @Override + protected void writeRequestCharge(double requestCharge) { + QueryMetricsTextWriter.appendRUToStringBuilder(stringBuilder, QueryMetricsTextWriter.RequestCharge, + requestCharge, 1); + } + + @Override + protected void writeBeforePartitionExecutionTimeline() { + QueryMetricsTextWriter.appendNewlineToStringBuilder(stringBuilder); + + // Building the table for fetch execution ranges + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, QueryMetricsTextWriter.FetchExecutionRanges + , 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, PartitionExecutionTimelineTable.getTopLine(), 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, PartitionExecutionTimelineTable.getHeader(), 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, PartitionExecutionTimelineTable.getMiddleLine(), 1); + } + + @Override + protected void writeBeforeFetchExecutionRange() { + // Do Nothing + } + + @Override + protected void writeFetchPartitionKeyRangeId(String partitionId) { + this.lastFetchPartitionId = partitionId; + } + + @Override + protected void writeActivityId(String activityId) { + this.lastActivityId = activityId; + } + + @Override + protected void writeStartTime(Instant startTime) { + this.lastStartTime = startTime; + } + + @Override + protected void writeEndTime(Instant endTime) { + this.lastEndTime = endTime; + } + + @Override + protected void writeFetchDocumentCount(long numberOfDocuments) { + this.lastFetchDocumentCount = numberOfDocuments; + } + + @Override + protected void writeFetchRetryCount(long retryCount) { + this.lastFetchRetryCount = retryCount; + } + + @Override + protected void writeAfterFetchExecutionRange() { + QueryMetricsTextWriter.appendHeaderToStringBuilder( + stringBuilder, + PartitionExecutionTimelineTable.getRow(Arrays.asList( + this.lastFetchPartitionId, + this.lastActivityId, + formatter.format(this.lastStartTime), + formatter.format(this.lastEndTime), + nanosToMilliSeconds(this.lastEndTime.minusNanos(lastStartTime.getNano()).getNano()), + this.lastFetchDocumentCount, + this.lastFetchRetryCount)), + 1); + } + + @Override + protected void writeAfterPartitionExecutionTimeline() { + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, PartitionExecutionTimelineTable.getBottomLine(), + 1); + } + + @Override + protected void writeBeforeSchedulingMetrics() { + QueryMetricsTextWriter.appendNewlineToStringBuilder(stringBuilder); + + // Building the table for scheduling metrics + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, QueryMetricsTextWriter.SchedulingMetrics, 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, SchedulingMetricsTable.getTopLine(), 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, SchedulingMetricsTable.getHeader(), 1); + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, SchedulingMetricsTable.getMiddleLine(), 1); + } + + @Override + protected void writeBeforePartitionSchedulingDuration() { + // Do Nothing + } + + @Override + protected void writePartitionSchedulingDurationId(String partitionId) { + this.lastSchedulingPartitionId = partitionId; + } + + @Override + protected void writeResponseTime(long responseTime) { + this.lastResponseTime = responseTime; + } + + @Override + protected void writeRunTime(long runTime) { + this.lastRunTime = runTime; + } + + @Override + protected void writeWaitTime(long waitTime) { + this.lastWaitTime = waitTime; + } + + @Override + protected void writeTurnaroundTime(long turnaroundTime) { + this.lastTurnaroundTime = turnaroundTime; + } + + @Override + protected void writeNumberOfPreemptions(long numPreemptions) { + this.lastNumberOfPreemptions = numPreemptions; + } + + @Override + protected void writeAfterPartitionSchedulingDuration() { + QueryMetricsTextWriter.appendHeaderToStringBuilder( + stringBuilder, + SchedulingMetricsTable.getRow(Arrays.asList( + this.lastSchedulingPartitionId, + this.lastResponseTime, + this.lastRunTime, + this.lastWaitTime, + this.lastTurnaroundTime, + this.lastNumberOfPreemptions)), + 1); + } + + @Override + protected void writeAfterSchedulingMetrics() { + QueryMetricsTextWriter.appendHeaderToStringBuilder(stringBuilder, SchedulingMetricsTable.getBottomLine(), 1); + } + + @Override + protected void writeAfterClientSideMetrics() { + // Do Nothing + } + + @Override + protected void writeAfterQueryMetrics() { + // Do Nothing + } + + // Util functions + private static final int NANOS_TO_MILLIS = 1000000; + + static HashMap parseDelimitedString(String delimitedString) { + if (delimitedString == null) { + throw new NullPointerException("delimitedString"); + } + + HashMap metrics = new HashMap<>(); + + final int key = 0; + final int value = 1; + String[] headerAttributes = StringUtils.split(delimitedString, ";"); + + for (String attribute : headerAttributes) { + String[] attributeKeyValue = StringUtils.split(attribute, "="); + + if (attributeKeyValue.length != 2) { + throw new NullPointerException("recieved a malformed delimited STRING"); + } + + String attributeKey = attributeKeyValue[key]; + double attributeValue = Double.parseDouble(attributeKeyValue[value]); + metrics.put(attributeKey, attributeValue); + } + + return metrics; + } + + static Duration durationFromMetrics(HashMap metrics, String key) { + // Just attempt to get the metrics + Double durationInMilliseconds = metrics.get(key); + if (durationInMilliseconds == null) { + return Duration.ZERO; + } + + long seconds = (long) (durationInMilliseconds / 1e3); + long nanoseconds = (long) ((durationInMilliseconds - (seconds * 1e3)) * 1e6); + + return Duration.ofSeconds(seconds, nanoseconds); + } + + static double durationToMilliseconds(Duration duration) { + double seconds = duration.getSeconds(); + double nano = duration.getNano(); + + return (seconds * 1e3) + (nano / 1e6); + } + + static Duration getDurationFromMetrics(HashMap metrics, String key) { + double timeSpanInMilliseconds; + Duration timeSpanFromMetrics; + timeSpanInMilliseconds = metrics.get(key); + timeSpanFromMetrics = doubleMillisecondsToDuration(timeSpanInMilliseconds); + return timeSpanFromMetrics; + } + + private static Duration doubleMillisecondsToDuration(double timeSpanInMilliseconds) { + long timeInNanoSeconds = (long) (timeSpanInMilliseconds * NANOS_TO_MILLIS); + return Duration.ofNanos(timeInNanoSeconds); + } + + private static void appendToStringBuilder(StringBuilder stringBuilder, String property, String value, + String units, int indentLevel) { + final String Indent = " "; + final String FormatString = "%-40s : %15s %-12s %s"; + + stringBuilder.append(String.format( + Locale.ROOT, + FormatString, + StringUtils.repeat(Indent, indentLevel) + property, + value, + units, + System.lineSeparator())); + } + + static void appendBytesToStringBuilder(StringBuilder stringBuilder, String property, long bytes, int indentLevel) { + final String BytesFormatString = "%d"; + final String BytesUnitString = "bytes"; + + appendToStringBuilder( + stringBuilder, + property, + String.format(BytesFormatString, bytes), + BytesUnitString, + indentLevel); + } + + static void appendMillisecondsToStringBuilder(StringBuilder stringBuilder, String property, double milliseconds, + int indentLevel) { + final String MillisecondsFormatString = "%f"; + final String MillisecondsUnitString = "milliseconds"; + + appendToStringBuilder(stringBuilder, property, String.format(MillisecondsFormatString, + milliseconds), MillisecondsUnitString, indentLevel); + } + + static void appendNanosecondsToStringBuilder(StringBuilder stringBuilder, String property, double nanoSeconds, + int indentLevel) { + final String MillisecondsFormatString = "%.2f"; + final String MillisecondsUnitString = "milliseconds"; + appendToStringBuilder(stringBuilder, property, String.format(MillisecondsFormatString, + nanosToMilliSeconds(nanoSeconds)), MillisecondsUnitString, indentLevel); + } + + static double nanosToMilliSeconds(double nanos) { + return nanos / NANOS_TO_MILLIS; + } + + static void appendHeaderToStringBuilder(StringBuilder stringBuilder, String headerTitle, int indentLevel) { + final String Indent = " "; + final String FormatString = "%s %s"; + stringBuilder.append(String.format( + Locale.ROOT, + FormatString, + String.join(StringUtils.repeat(Indent, indentLevel)) + headerTitle, + System.lineSeparator())); + } + + static void appendRUToStringBuilder(StringBuilder stringBuilder, String property, double requestCharge, + int indentLevel) { + final String RequestChargeFormatString = "%s"; + final String RequestChargeUnitString = "RUs"; + + appendToStringBuilder( + stringBuilder, + property, + String.format(Locale.ROOT, RequestChargeFormatString, requestCharge), + RequestChargeUnitString, + indentLevel); + } + + static void appendActivityIdsToStringBuilder(StringBuilder stringBuilder, String activityIdsLabel, + List activityIds, int indentLevel) { + final String Indent = " "; + stringBuilder.append(activityIdsLabel); + stringBuilder.append(System.lineSeparator()); + for (String activityId : activityIds) { + stringBuilder.append(Indent); + stringBuilder.append(activityId); + stringBuilder.append(System.lineSeparator()); + } + } + + static void appendPercentageToStringBuilder(StringBuilder stringBuilder, String property, double percentage, + int indentLevel) { + final String PercentageFormatString = "%.2f"; + final String PercentageUnitString = "%"; + + appendToStringBuilder(stringBuilder, property, String.format(PercentageFormatString, + percentage * 100), PercentageUnitString, indentLevel); + } + + static void appendCountToStringBuilder(StringBuilder stringBuilder, String property, long count, int indentLevel) { + final String CountFormatString = "%s"; + final String CountUnitString = ""; + + appendToStringBuilder( + stringBuilder, + property, + String.format(CountFormatString, count), + CountUnitString, + indentLevel); + } + + static void appendNewlineToStringBuilder(StringBuilder stringBuilder) { + appendHeaderToStringBuilder(stringBuilder, StringUtils.EMPTY, 0); + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsWriter.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsWriter.java new file mode 100644 index 0000000000000..d61094020e326 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/QueryMetricsWriter.java @@ -0,0 +1,225 @@ +package com.azure.data.cosmos.internal.query.metrics; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.QueryMetrics; +import com.azure.data.cosmos.internal.QueryPreparationTimes; +import com.azure.data.cosmos.internal.RuntimeExecutionTimes; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; + +abstract class QueryMetricsWriter { + + public void writeQueryMetrics(QueryMetrics queryMetrics) { + this.writeBeforeQueryMetrics(); + + // Top Level Properties + this.writeRetrievedDocumentCount(queryMetrics.getRetrievedDocumentCount()); + this.writeRetrievedDocumentSize(queryMetrics.getRetrievedDocumentSize()); + this.writeOutputDocumentCount(queryMetrics.getOutputDocumentCount()); + this.writeOutputDocumentSize(queryMetrics.getOutputDocumentSize()); + this.writeIndexHitRatio(queryMetrics.getIndexHitRatio()); + this.writeTotalQueryExecutionTime(queryMetrics.getTotalQueryExecutionTime()); + + // QueryPreparationTimes + this.writeQueryPreparationTimes(queryMetrics.getQueryPreparationTimes()); + + this.writeIndexLookupTime(queryMetrics.getIndexLookupTime()); + this.writeDocumentLoadTime(queryMetrics.getDocumentLoadTime()); + this.writeVMExecutionTime(queryMetrics.getVMExecutionTime()); + + // RuntimesExecutionTimes + this.writeRuntimesExecutionTimes(queryMetrics.getRuntimeExecutionTimes()); + + this.writeDocumentWriteTime(queryMetrics.getDocumentWriteTime()); + + // ClientSideMetrics + this.writeClientSideMetrics(BridgeInternal.getClientSideMetrics(queryMetrics)); + + this.writeAfterQueryMetrics(); + } + + protected abstract void writeBeforeQueryMetrics(); + + protected abstract void writeRetrievedDocumentCount(long retrievedDocumentCount); + + protected abstract void writeRetrievedDocumentSize(long retrievedDocumentSize); + + protected abstract void writeOutputDocumentCount(long outputDocumentCount); + + protected abstract void writeOutputDocumentSize(long outputDocumentSize); + + protected abstract void writeIndexHitRatio(double indexHitRatio); + + protected abstract void writeTotalQueryExecutionTime(Duration totalQueryExecutionTime); + + //QueryPreparationTimes + private void writeQueryPreparationTimes(QueryPreparationTimes queryPreparationTimes) { + this.writeBeforeQueryPreparationTimes(); + + this.writeQueryCompilationTime(queryPreparationTimes.getQueryCompilationTime()); + this.writeLogicalPlanBuildTime(queryPreparationTimes.getLogicalPlanBuildTime()); + this.writePhysicalPlanBuildTime(queryPreparationTimes.getPhysicalPlanBuildTime()); + this.writeQueryOptimizationTime(queryPreparationTimes.getQueryOptimizationTime()); + + this.writeAfterQueryPreparationTimes(); + } + + protected abstract void writeBeforeQueryPreparationTimes(); + + protected abstract void writeQueryCompilationTime(Duration queryCompilationTime); + + protected abstract void writeLogicalPlanBuildTime(Duration logicalPlanBuildTime); + + protected abstract void writePhysicalPlanBuildTime(Duration physicalPlanBuildTime); + + protected abstract void writeQueryOptimizationTime(Duration queryOptimizationTime); + + protected abstract void writeAfterQueryPreparationTimes(); + + protected abstract void writeIndexLookupTime(Duration indexLookupTime); + + protected abstract void writeDocumentLoadTime(Duration documentLoadTime); + + protected abstract void writeVMExecutionTime(Duration vMExecutionTime); + + // RuntimeExecutionTimes + private void writeRuntimesExecutionTimes(RuntimeExecutionTimes runtimeExecutionTimes) { + this.writeBeforeRuntimeExecutionTimes(); + + this.writeQueryEngineExecutionTime(runtimeExecutionTimes.getQueryEngineExecutionTime()); + this.writeSystemFunctionExecutionTime(runtimeExecutionTimes.getSystemFunctionExecutionTime()); + this.writeUserDefinedFunctionExecutionTime(runtimeExecutionTimes.getUserDefinedFunctionExecutionTime()); + + this.writeAfterRuntimeExecutionTimes(); + } + + + protected abstract void writeBeforeRuntimeExecutionTimes(); + + protected abstract void writeQueryEngineExecutionTime(Duration queryEngineExecutionTime); + + protected abstract void writeSystemFunctionExecutionTime(Duration systemFunctionExecutionTime); + + protected abstract void writeUserDefinedFunctionExecutionTime(Duration userDefinedFunctionExecutionTime); + + protected abstract void writeAfterRuntimeExecutionTimes(); + + protected abstract void writeDocumentWriteTime(Duration documentWriteTime); + + // ClientSideMetrics + private void writeClientSideMetrics(ClientSideMetrics clientSideMetrics) { + this.writeBeforeClientSideMetrics(); + + this.writeRetries(clientSideMetrics.getRetries()); + this.writeRequestCharge(clientSideMetrics.getRequestCharge()); + this.writePartitionExecutionTimeline(clientSideMetrics); + this.writeSchedulingMetrics(clientSideMetrics); + + this.writeAfterClientSideMetrics(); + } + + protected abstract void writeBeforeClientSideMetrics(); + + protected abstract void writeRetries(long retries); + + protected abstract void writeRequestCharge(double requestCharge); + + private void writePartitionExecutionTimeline(ClientSideMetrics clientSideMetrics) { + this.writeBeforePartitionExecutionTimeline(); + List fetchExecutionRanges = clientSideMetrics.getFetchExecutionRanges(); + fetchExecutionRanges.sort((f1, f2) -> f2.getStartTime().compareTo(f1.getStartTime())); + for (FetchExecutionRange fetchExecutionRange : clientSideMetrics.getFetchExecutionRanges()) { + this.writeFetchExecutionRange(fetchExecutionRange); + } + this.writeAfterPartitionExecutionTimeline(); + } + + protected abstract void writeBeforePartitionExecutionTimeline(); + + private void writeFetchExecutionRange(FetchExecutionRange fetchExecutionRange) { + this.writeBeforeFetchExecutionRange(); + + this.writeFetchPartitionKeyRangeId(fetchExecutionRange.getPartitionId()); + this.writeActivityId(fetchExecutionRange.getActivityId()); + this.writeStartTime(fetchExecutionRange.getStartTime()); + this.writeEndTime(fetchExecutionRange.getEndTime()); + this.writeFetchDocumentCount(fetchExecutionRange.getNumberOfDocuments()); + this.writeFetchRetryCount(fetchExecutionRange.getRetryCount()); + + this.writeAfterFetchExecutionRange(); + } + + protected abstract void writeBeforeFetchExecutionRange(); + + protected abstract void writeFetchPartitionKeyRangeId(String partitionId); + + protected abstract void writeActivityId(String activityId); + + protected abstract void writeStartTime(Instant startTime); + + protected abstract void writeEndTime(Instant endTime); + + protected abstract void writeFetchDocumentCount(long numberOfDocuments); + + protected abstract void writeFetchRetryCount(long retryCount); + + protected abstract void writeAfterFetchExecutionRange(); + + protected abstract void writeAfterPartitionExecutionTimeline(); + + private void writeSchedulingMetrics(ClientSideMetrics clientSideMetrics) { + this.writeBeforeSchedulingMetrics(); + List> partitionSchedulingTimeSpans = clientSideMetrics.getPartitionSchedulingTimeSpans(); + partitionSchedulingTimeSpans.sort((o1, o2) -> (int) (o2.right.getResponseTime() - o1.right.getResponseTime())); + for (ImmutablePair partitionSchedulingDuration : + partitionSchedulingTimeSpans) { + String partitionId = partitionSchedulingDuration.getLeft(); + SchedulingTimeSpan schedulingDuration = partitionSchedulingDuration.getRight(); + + this.writePartitionSchedulingDuration(partitionId, schedulingDuration); + } + + this.writeAfterSchedulingMetrics(); + } + + protected abstract void writeBeforeSchedulingMetrics(); + + private void writePartitionSchedulingDuration(String partitionId, SchedulingTimeSpan schedulingDuration) { + this.writeBeforePartitionSchedulingDuration(); + + this.writePartitionSchedulingDurationId(partitionId); + this.writeResponseTime(schedulingDuration.getResponseTime()); + this.writeRunTime(schedulingDuration.getRunTime()); + this.writeWaitTime(schedulingDuration.getWaitTime()); + this.writeTurnaroundTime(schedulingDuration.getTurnaroundTime()); + this.writeNumberOfPreemptions(schedulingDuration.getNumPreemptions()); + + this.writeAfterPartitionSchedulingDuration(); + } + + protected abstract void writeBeforePartitionSchedulingDuration(); + + protected abstract void writePartitionSchedulingDurationId(String partitionId); + + protected abstract void writeResponseTime(long responseTime); + + protected abstract void writeRunTime(long runTime); + + protected abstract void writeWaitTime(long waitTime); + + protected abstract void writeTurnaroundTime(long turnaroundTime); + + protected abstract void writeNumberOfPreemptions(long numPreemptions); + + protected abstract void writeAfterPartitionSchedulingDuration(); + + protected abstract void writeAfterSchedulingMetrics(); + + protected abstract void writeAfterClientSideMetrics(); + + protected abstract void writeAfterQueryMetrics(); + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingStopwatch.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingStopwatch.java new file mode 100644 index 0000000000000..64fbf2c103c99 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingStopwatch.java @@ -0,0 +1,90 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +import org.apache.commons.lang3.time.StopWatch; + +public class SchedulingStopwatch { + private StopWatch turnaroundTimeStopwatch; + private StopWatch responseTimeStopwatch; + private StopWatch runTimeStopwatch; + private long numPreemptions; + private boolean responded; + + public SchedulingStopwatch() { + this.turnaroundTimeStopwatch = new StopWatch(); + this.responseTimeStopwatch = new StopWatch(); + this.runTimeStopwatch = new StopWatch(); + } + + public SchedulingTimeSpan getElapsedTime() { + return new SchedulingTimeSpan(this.turnaroundTimeStopwatch.getTime(), this.responseTimeStopwatch.getTime(), + this.runTimeStopwatch.getTime(), + this.turnaroundTimeStopwatch.getTime() - this.runTimeStopwatch.getTime(), this.numPreemptions); + } + + /** + * Tells the SchedulingStopwatch know that the process is in a state where it is ready to be worked on, + * which in turn starts the stopwatch for for response time and turnaround time. + */ + public void ready() { + startStopWatch(this.turnaroundTimeStopwatch); + startStopWatch(this.responseTimeStopwatch); + } + + public void start() { + if (!this.runTimeStopwatch.isStarted()) { + if (!this.responded) { + // This is the first time the process got a response, so the response time stopwatch needs to stop. + this.responseTimeStopwatch.stop(); + this.responded = true; + } + this.runTimeStopwatch.reset(); + startStopWatch(this.runTimeStopwatch); + } + } + + public void stop() { + if (this.runTimeStopwatch.isStarted()) { + stopStopWatch(this.runTimeStopwatch); + this.numPreemptions++; + } + } + + public void terminate() { + stopStopWatch(this.turnaroundTimeStopwatch); + stopStopWatch(this.responseTimeStopwatch); + } + + private void startStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.start(); + } + } + + private void stopStopWatch(StopWatch stopwatch) { + synchronized (stopwatch) { + stopwatch.stop(); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingTimeSpan.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingTimeSpan.java new file mode 100644 index 0000000000000..0600e78daf637 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/SchedulingTimeSpan.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +public class SchedulingTimeSpan { + + /** + * The total time taken from when the process arrives to when it ended. + */ + private final long turnaroundTime; + + /** + * The total latency (time) taken from when the process arrived to when the CPU actually started working on it. + */ + private final long responseTime; + + /** + * The total time the process spent in the running state. + */ + private final long runTime; + + /** + * The total time that the process spent is on the ready or waiting state. + */ + private final long waitTime; + + /** + * NUMBER of times the process was preempted. + */ + private final long numPreemptions; + + public SchedulingTimeSpan(long turnaroundTime, long responseTime, long runTime, long waitTime, long numPreemptions) { + this.turnaroundTime = turnaroundTime; + this.responseTime = responseTime; + this.runTime = runTime; + this.waitTime = waitTime; + this.numPreemptions = numPreemptions; + } + + public long getTurnaroundTime() { + return turnaroundTime; + } + + public long getResponseTime() { + return responseTime; + } + + public long getRunTime() { + return runTime; + } + + public long getWaitTime() { + return waitTime; + } + + public long getNumPreemptions() { + return numPreemptions; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/TextTable.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/TextTable.java new file mode 100644 index 0000000000000..367384ad62bb8 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/metrics/TextTable.java @@ -0,0 +1,131 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query.metrics; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +class TextTable { + private static final char CellLeftTop = '┌'; + private static final char CellRightTop = '┐'; + private static final char CellLeftBottom = '└'; + private static final char CellRightBottom = '┘'; + private static final char CellHorizontalJointTop = '┬'; + private static final char CellHorizontalJointBottom = '┴'; + private static final char CellVerticalJointLeft = '├'; + private static final char CellTJoint = '┼'; + private static final char CellVerticalJointRight = '┤'; + private static final char CellHorizontalLine = '-'; + private static final char CellVerticalLine = '│'; + + private List columns; + + private String header; + private String topLine; + private String middleLine; + private String bottomLine; + + private String rowFormatString; + + /** + * Initializes a new instance of the TextTable class. + * + * @param columns The columns of the table + */ + public TextTable(List columns) { + this.columns = new ArrayList<>(columns); + + // Building the table header + String headerFormatString = TextTable.buildLineFormatString(columns); + this.header = String.format(headerFormatString, columns.stream().map(textTableColumn -> textTableColumn.columnName).toArray()); + + // building the different lines + this.topLine = TextTable.buildLine(CellLeftTop, CellRightTop, CellHorizontalJointTop, columns); + this.middleLine = TextTable.buildLine(CellVerticalJointLeft, CellVerticalJointRight, CellTJoint, columns); + this.bottomLine = TextTable.buildLine(CellLeftBottom, CellRightBottom, CellHorizontalJointBottom, columns); + + // building the row format string + this.rowFormatString = TextTable.buildLineFormatString(columns); + } + + public String getRow(List cells) { + if (cells.size() != this.columns.size()) { + throw new IllegalArgumentException("Cells in a row needs to have exactly 1 element per column"); + } + return String.format(this.rowFormatString, cells.toArray()); + } + + private static String buildLine(char firstChar, char lastChar, char seperator, List columns) { + StringBuilder lineStringBuilder = new StringBuilder(); + lineStringBuilder.append(firstChar); + for (Column column : columns.subList(0, columns.size() - 1)) { + lineStringBuilder.append(StringUtils.repeat(CellHorizontalLine, column.columnWidth)); + lineStringBuilder.append(seperator); + } + + lineStringBuilder.append(StringUtils.repeat(CellHorizontalLine, columns.get(columns.size() - 1).columnWidth)); + lineStringBuilder.append(lastChar); + + return lineStringBuilder.toString(); + } + + private static String buildLineFormatString(List columns) { + StringBuilder lineFormatStringBuilder = new StringBuilder(); + lineFormatStringBuilder.append(CellVerticalLine); + for (Column column : columns) { + lineFormatStringBuilder.append("%" + column.columnWidth + "s"); + lineFormatStringBuilder.append(CellVerticalLine); + } + + return lineFormatStringBuilder.toString(); + } + + + static class Column { + String columnName; + int columnWidth; + + public Column(String columnName, int columnWidth) { + this.columnName = columnName; + this.columnWidth = columnWidth; + } + } + + public String getHeader() { + return header; + } + + public String getTopLine() { + return topLine; + } + + public String getMiddleLine() { + return middleLine; + } + + public String getBottomLine() { + return bottomLine; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderByRowResult.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderByRowResult.java new file mode 100644 index 0000000000000..2427b16d25355 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderByRowResult.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.orderbyquery; + +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.query.QueryItem; + +import java.util.List; + +/** + * Represents the result of a query in the Azure Cosmos DB database service. + */ +public final class OrderByRowResult extends Document { + private final Class klass; + private volatile List orderByItems; + private volatile T payload; + private final PartitionKeyRange targetRange; + private final String backendContinuationToken; + + public OrderByRowResult( + Class klass, + String jsonString, + PartitionKeyRange targetRange, + String backendContinuationToken) { + super(jsonString); + this.klass = klass; + this.targetRange = targetRange; + this.backendContinuationToken = backendContinuationToken; + } + + public List getOrderByItems() { + return this.orderByItems != null ? this.orderByItems + : (this.orderByItems = super.getList("orderByItems", QueryItem.class)); + } + + public T getPayload() { + return this.payload != null ? this.payload : (this.payload = super.getObject("payload", klass)); + } + + public PartitionKeyRange getSourcePartitionKeyRange() { + return this.targetRange; + } + + public String getSourceBackendContinuationToken() { + return this.backendContinuationToken; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderbyRowComparer.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderbyRowComparer.java new file mode 100644 index 0000000000000..c205d04529834 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/query/orderbyquery/OrderbyRowComparer.java @@ -0,0 +1,116 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query.orderbyquery; + +import com.azure.data.cosmos.internal.query.ItemComparator; +import com.azure.data.cosmos.internal.query.ItemType; +import com.azure.data.cosmos.internal.query.ItemTypeHelper; +import com.azure.data.cosmos.internal.query.QueryItem; +import com.azure.data.cosmos.internal.query.SortOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +public final class OrderbyRowComparer implements Comparator> { + private static final Logger logger = LoggerFactory.getLogger(OrderbyRowComparer.class); + + private final List sortOrders; + private volatile List itemTypes; + + public OrderbyRowComparer(Collection sortOrders) { + this.sortOrders = new ArrayList<>(sortOrders); + } + + @Override + public int compare(OrderByRowResult r1, OrderByRowResult r2) { + try { + // comparing document (row) vs document (row) + List result1 = r1.getOrderByItems(); + List result2 = r2.getOrderByItems(); + + if (result1.size() != result2.size()) { + throw new IllegalStateException("OrderByItems cannot have different sizes."); + } + + if (result1.size() != this.sortOrders.size()) { + throw new IllegalStateException("OrderByItems cannot have a different size than sort orders."); + } + + if (this.itemTypes == null) { + synchronized (this) { + if (this.itemTypes == null) { + this.itemTypes = new ArrayList(result1.size()); + for (QueryItem item : result1) { + this.itemTypes.add(ItemTypeHelper.getOrderByItemType(item.getItem())); + } + } + } + } + + this.checkOrderByItemType(result1); + this.checkOrderByItemType(result2); + + for (int i = 0; i < result1.size(); ++i) { + int cmp = ItemComparator.getInstance().compare(result1.get(i).getItem(), result2.get(i).getItem()); + if (cmp != 0) { + switch (this.sortOrders.get(i)) { + case Ascending: + return cmp; + case Descending: + return -cmp; + } + } + } + + return r1.getSourcePartitionKeyRange().getMinInclusive().compareTo(r2.getSourcePartitionKeyRange().getMinInclusive()); + } catch (Exception e) { + // Due to a bug in rxjava-extras <= 0.8.0.15 dependency, + // if OrderbyRowComparer throws an unexpected exception, + // then the observable returned by Transformers.orderedMergeWith(.) will never emit a terminal event. + // rxjava-extras lib provided a quick fix on the bugreport: + // https://github.com/davidmoten/rxjava-extras/issues/30 (0.8.0.16) + // we are also capturing the exception stacktrace here + logger.error("Orderby Row comparision failed {}, {}", r1.toJson(), r2.toJson(), e); + throw e; + } + } + + private void checkOrderByItemType(List orderByItems) { + for (int i = 0; i < this.itemTypes.size(); ++i) { + ItemType type = ItemTypeHelper.getOrderByItemType(orderByItems.get(i).getItem()); + if (type != this.itemTypes.get(i)) { + throw new UnsupportedOperationException( + String.format("Expected %s, but got %s.", this.itemTypes.get(i).toString(), type.toString())); + } + } + } + + public List getSortOrders() { + return this.sortOrders; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/BoolPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/BoolPartitionKeyComponent.java new file mode 100644 index 0000000000000..053dea7c7eee2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/BoolPartitionKeyComponent.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class BoolPartitionKeyComponent implements IPartitionKeyComponent { + + private final boolean value; + + public BoolPartitionKeyComponent(boolean value) { + this.value = value; + } + + @Override + public int CompareTo(IPartitionKeyComponent other) { + BoolPartitionKeyComponent otherBool = Utils.as(other, BoolPartitionKeyComponent.class); + if (otherBool == null) { + throw new IllegalArgumentException("other"); + } + + return (int) Math.signum((this.value ? 1 : 0) - (otherBool.value ? 1 : 0)); + } + + @Override + public int GetTypeOrdinal() { + return this.value ? PartitionKeyComponentType.TRUE.type : PartitionKeyComponentType.FALSE.type; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + try { + writer.writeBoolean(this.value); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + try { + outputStream.write((byte) (this.value ? PartitionKeyComponentType.TRUE.type + : PartitionKeyComponentType.FALSE.type)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + try { + outputStream.write((byte) (this.value ? PartitionKeyComponentType.TRUE.type + : PartitionKeyComponentType.FALSE.type)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) (this.value ? PartitionKeyComponentType.TRUE.type + : PartitionKeyComponentType.FALSE.type)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CaseInsensitiveHashMap.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CaseInsensitiveHashMap.java new file mode 100644 index 0000000000000..dc000cd04c1ad --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CaseInsensitiveHashMap.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + + +// TODO: commons-collections lib has CaseInsensitiveHashMap we should switch to that. +// https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.2/org/apache/commons/collections/map/CaseInsensitiveMap.html +public class CaseInsensitiveHashMap extends HashMap { + + private static String safeToLower(String key) { + return key != null ? key.toLowerCase() : null; + } + + @Override + public V get(Object key) { + return super.get(safeToLower((String) key)); + } + + + @Override + public void putAll(Map m) { + super.putAll(m); + } + + @Override + public V put(String key, V value) { + return super.put(safeToLower(key), value); + } + + @Override + public V putIfAbsent(String key, V value) { + return super.putIfAbsent(safeToLower(key), value); + } + + @Override + public V compute(String key, BiFunction remappingFunction) { + return super.compute(safeToLower(key), remappingFunction); + } + + @Override + public V computeIfAbsent(String key, Function mappingFunction) { + return super.computeIfAbsent(safeToLower(key), mappingFunction); + } + + @Override + public V computeIfPresent(String key, BiFunction remappingFunction) { + return super.computeIfPresent(safeToLower(key), remappingFunction); + } + + @Override + public boolean containsKey(Object key) { + return super.containsKey(safeToLower((String) key)); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CollectionRoutingMap.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CollectionRoutingMap.java new file mode 100644 index 0000000000000..a180c1955aeaa --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/CollectionRoutingMap.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.util.Collection; +import java.util.List; + +/** + * Used internally in request routing in the Azure Cosmos DB database service. + */ +public interface CollectionRoutingMap { + List getOrderedPartitionKeyRanges(); + + PartitionKeyRange getRangeByEffectivePartitionKey(String effectivePartitionKeyValue); + + PartitionKeyRange getRangeByPartitionKeyRangeId(String partitionKeyRangeId); + + List getOverlappingRanges(Range range); + + List getOverlappingRanges(Collection> providedPartitionKeyRanges); + + PartitionKeyRange tryGetRangeByPartitionKeyRangeId(String partitionKeyRangeId); + + IServerIdentity tryGetInfoByPartitionKeyRangeId(String partitionKeyRangeId); + + boolean IsGone(String partitionKeyRangeId); + + String getCollectionUniqueId(); + + CollectionRoutingMap tryCombine(List> ranges); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IPartitionKeyComponent.java new file mode 100644 index 0000000000000..e65fade4fe831 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IPartitionKeyComponent.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.OutputStream; + +interface IPartitionKeyComponent { + int CompareTo(IPartitionKeyComponent other); + + int GetTypeOrdinal(); + + void JsonEncode(JsonGenerator writer); + + void WriteForHashing(OutputStream outputStream); + + void WriteForHashingV2(OutputStream binaryWriter); + + void WriteForBinaryEncoding(OutputStream binaryWriter); + + IPartitionKeyComponent Truncate(); +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IServerIdentity.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IServerIdentity.java new file mode 100644 index 0000000000000..2ebb41e349f17 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/IServerIdentity.java @@ -0,0 +1,27 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +public interface IServerIdentity { +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMap.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMap.java new file mode 100644 index 0000000000000..89d14550f1394 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMap.java @@ -0,0 +1,257 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +/** + * Used internally to cache partition key ranges of a collection in the Azure Cosmos DB database service. + */ +public class InMemoryCollectionRoutingMap implements CollectionRoutingMap { + private final Map> rangeById; + private final List orderedPartitionKeyRanges; + private final List> orderedRanges; + + private final Set goneRanges; + + private String collectionUniqueId; + + private InMemoryCollectionRoutingMap(Map> rangeById, + List orderedPartitionKeyRanges, + String collectionUniqueId) { + this.rangeById = rangeById; + this.orderedPartitionKeyRanges = orderedPartitionKeyRanges; + this.orderedRanges = orderedPartitionKeyRanges.stream().map( + range -> + new Range<>( + range.getMinInclusive(), + range.getMaxExclusive(), + true, + false)).collect(Collectors.toList()); + + this.collectionUniqueId = collectionUniqueId; + this.goneRanges = new HashSet<>(orderedPartitionKeyRanges.stream().flatMap(r -> CollectionUtils.emptyIfNull(r.getParents()).stream()).collect(Collectors.toSet())); + + } + + public static InMemoryCollectionRoutingMap tryCreateCompleteRoutingMap( + Iterable> ranges, String collectionUniqueId) { + + Map> rangeById = + new HashMap<>(); + + for (ImmutablePair range: ranges) { + rangeById.put(range.left.id(), range); + } + + List> sortedRanges = new ArrayList<>(rangeById.values()); + Collections.sort(sortedRanges, new MinPartitionKeyPairComparator()); + List orderedRanges = sortedRanges.stream().map(range -> range.left).collect(Collectors.toList()); + + if (!isCompleteSetOfRanges(orderedRanges)) { + return null; + } + + return new InMemoryCollectionRoutingMap(rangeById, orderedRanges, collectionUniqueId); + } + + private static boolean isCompleteSetOfRanges(List orderedRanges) { + boolean isComplete = false; + if (orderedRanges.size() > 0) { + PartitionKeyRange firstRange = orderedRanges.get(0); + PartitionKeyRange lastRange = orderedRanges.get(orderedRanges.size() - 1); + isComplete = firstRange.getMinInclusive() + .compareTo(PartitionKeyRange.MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY) == 0; + isComplete &= lastRange.getMaxExclusive() + .compareTo(PartitionKeyRange.MAXIMUM_EXCLUSIVE_EFFECTIVE_PARTITION_KEY) == 0; + + for (int i = 1; i < orderedRanges.size(); i++) { + PartitionKeyRange previousRange = orderedRanges.get(i - 1); + PartitionKeyRange currentRange = orderedRanges.get(i); + isComplete &= previousRange.getMaxExclusive().compareTo(currentRange.getMinInclusive()) == 0; + + if (!isComplete) { + if (previousRange.getMaxExclusive().compareTo(currentRange.getMinInclusive()) > 0) { + throw new IllegalStateException("Ranges overlap"); + } + + break; + } + } + } + + return isComplete; + } + + public String getCollectionUniqueId() { + return collectionUniqueId; + } + + @Override + public List getOrderedPartitionKeyRanges() { + return this.orderedPartitionKeyRanges; + } + + @Override + public PartitionKeyRange getRangeByEffectivePartitionKey(String effectivePartitionKeyValue) { + if (PartitionKeyRange.MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY.compareTo(effectivePartitionKeyValue) == 0) { + return this.orderedPartitionKeyRanges.get(0); + } + + if (PartitionKeyRange.MAXIMUM_EXCLUSIVE_EFFECTIVE_PARTITION_KEY.compareTo(effectivePartitionKeyValue) == 0) { + return null; + } + + int index = Collections.binarySearch(this.orderedRanges, Range.getPointRange(effectivePartitionKeyValue), + new Range.MinComparator()); + + if (index < 0) { + index = Math.max(0, -index - 2); + } + + return this.orderedPartitionKeyRanges.get(index); + } + + @Override + public PartitionKeyRange getRangeByPartitionKeyRangeId(String partitionKeyRangeId) { + ImmutablePair pair = this.rangeById.get(partitionKeyRangeId); + return pair == null ? null : pair.left; + } + + + @Override + public List getOverlappingRanges(Range range) { + return this.getOverlappingRanges(Collections.singletonList(range)); + } + + @Override + public List getOverlappingRanges(Collection> providedPartitionKeyRanges) { + if (providedPartitionKeyRanges == null) { + throw new IllegalArgumentException("providedPartitionKeyRanges"); + } + + Map partitionRanges = new TreeMap(); + + for (Range range : providedPartitionKeyRanges) { + int minIndex = Collections.binarySearch(this.orderedRanges, range, new Range.MinComparator()); + if (minIndex < 0) { + minIndex = Math.max(minIndex, -minIndex - 2); + } + + int maxIndex = Collections.binarySearch(this.orderedRanges, range, new Range.MaxComparator()); + if (maxIndex < 0) { + maxIndex = Math.min(this.orderedRanges.size() - 1, -maxIndex - 1); + } + + for (int i = minIndex; i <= maxIndex; ++i) { + if (Range.checkOverlapping(this.orderedRanges.get(i), range)) { + PartitionKeyRange partitionKeyRange = this.orderedPartitionKeyRanges.get(i); + partitionRanges.put(partitionKeyRange.getMinInclusive(), partitionKeyRange); + } + } + } + + return new ArrayList<>(partitionRanges.values()); + } + + + @Override + public PartitionKeyRange tryGetRangeByPartitionKeyRangeId(String partitionKeyRangeId) + { + Pair addresses; + addresses = this.rangeById.get(partitionKeyRangeId); + if (addresses != null) { + return addresses.getLeft(); + } + + return null; + } + + @Override + public IServerIdentity tryGetInfoByPartitionKeyRangeId(String partitionKeyRangeId) + { + Pair addresses; + addresses = this.rangeById.get(partitionKeyRangeId); + if (addresses != null) { + return addresses.getRight(); + } + + return null; + } + + @Override + public boolean IsGone(String partitionKeyRangeId) { + return this.goneRanges.contains(partitionKeyRangeId); + } + + private static class MinPartitionKeyPairComparator + implements Comparator> { + public int compare(ImmutablePair pair1, + ImmutablePair pair2) { + return pair1.left.getMinInclusive().compareTo(pair2.left.getMinInclusive()); + } + } + + + public CollectionRoutingMap tryCombine( + List> ranges) { + Set newGoneRanges = new HashSet<>(ranges.stream().flatMap(tuple -> CollectionUtils.emptyIfNull(tuple.getLeft().getParents()).stream()).collect(Collectors.toSet())); + newGoneRanges.addAll(this.goneRanges); + + Map> newRangeById = + this.rangeById.values().stream().filter(tuple -> !newGoneRanges.contains(tuple.left.id())).collect(Collectors. + toMap(tuple -> tuple.left.id(), tuple -> tuple)); + + for (ImmutablePair tuple : ranges.stream().filter(tuple -> !newGoneRanges.contains(tuple.getLeft().id())).collect(Collectors.toList())) { + newRangeById.put(tuple.getLeft().id(), tuple); + } + + List> sortedRanges = newRangeById.values().stream().collect(Collectors.toList()); + + Collections.sort(sortedRanges, new MinPartitionKeyPairComparator()); + + List newOrderedRanges = sortedRanges.stream().map(range -> range.left).collect(Collectors.toList()); + + if (!isCompleteSetOfRanges(newOrderedRanges)) { + return null; + } + + return new InMemoryCollectionRoutingMap(newRangeById, newOrderedRanges, this.getCollectionUniqueId()); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InfinityPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InfinityPartitionKeyComponent.java new file mode 100644 index 0000000000000..18d02d76c1f9c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/InfinityPartitionKeyComponent.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class InfinityPartitionKeyComponent implements IPartitionKeyComponent { + @Override + public int CompareTo(IPartitionKeyComponent other) { + InfinityPartitionKeyComponent otherInfinity = Utils.as(other, InfinityPartitionKeyComponent.class); + if (otherInfinity == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.INFINITY.type; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + throw new IllegalStateException(); + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + throw new IllegalStateException(); + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.INFINITY.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Int128.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Int128.java new file mode 100644 index 0000000000000..07cd07b6d877c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Int128.java @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + + +import java.math.BigInteger; + +public class Int128 { + + private final BigInteger value; + + private static final BigInteger MaxBigIntValue = + new BigInteger(new byte[] { + (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }); + + public static final Int128 MaxValue = new Int128( + new BigInteger(new byte[] { + (byte) 0x7F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + }) + ); + + private Int128(BigInteger value) { + this.value = value.remainder(MaxBigIntValue); + } + + public Int128(int n) { + this(BigInteger.valueOf(n)); + } + + public Int128(byte[] data) { + if (data.length != 16) { + throw new IllegalArgumentException("data"); + } + + this.value = new BigInteger(data); + + if (this.value.compareTo(MaxValue.value) > 0) { + throw new IllegalArgumentException(); + } + } + + public static Int128 multiply(Int128 left, Int128 right) { + return new Int128(left.value.multiply(right.value)); + } + + public static Int128 add(Int128 left, Int128 right) { + return new Int128(left.value.add(right.value)); + } + + public static Int128 subtract(Int128 left, Int128 right) { + return new Int128(left.value.subtract(right.value)); + } + + public static Int128 div (Int128 left, Int128 right) { + return new Int128(left.value.divide(right.value)); + } + + public static boolean gt(Int128 left, Int128 right) { + return left.value.compareTo(right.value) > 0; + } + + public static boolean lt(Int128 left, Int128 right) { + return left.value.compareTo(right.value) < 0; + } + + public byte[] bytes() { + byte[] bytes = this.value.toByteArray(); + if (bytes.length < 16) { + byte[] paddedBytes = new byte[16]; + System.arraycopy(bytes, 0, paddedBytes, 0, bytes.length); + return paddedBytes; + } + + return bytes; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationCache.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationCache.java new file mode 100644 index 0000000000000..78c2cf6d7ea72 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationCache.java @@ -0,0 +1,582 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.DatabaseAccountLocation; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.apache.commons.collections4.map.CaseInsensitiveMap; +import org.apache.commons.collections4.map.UnmodifiableMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.URL; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +/** + * Implements the abstraction to resolve target location for geo-replicated DatabaseAccount + * with multiple writable and readable locations. + */ +public class LocationCache { + private final static Logger logger = LoggerFactory.getLogger(LocationCache.class); + + private final boolean enableEndpointDiscovery; + private final URL defaultEndpoint; + private final boolean useMultipleWriteLocations; + private final Object lockObject; + private final Duration unavailableLocationsExpirationTime; + private final ConcurrentHashMap locationUnavailabilityInfoByEndpoint; + + private DatabaseAccountLocationsInfo locationInfo; + + private Instant lastCacheUpdateTimestamp; + private boolean enableMultipleWriteLocations; + + public LocationCache( + List preferredLocations, + URL defaultEndpoint, + boolean enableEndpointDiscovery, + boolean useMultipleWriteLocations, + Configs configs) { + this.locationInfo = new DatabaseAccountLocationsInfo(preferredLocations, defaultEndpoint); + this.defaultEndpoint = defaultEndpoint; + this.enableEndpointDiscovery = enableEndpointDiscovery; + this.useMultipleWriteLocations = useMultipleWriteLocations; + + this.lockObject = new Object(); + + + this.locationUnavailabilityInfoByEndpoint = new ConcurrentHashMap<>(); + + this.lastCacheUpdateTimestamp = Instant.MIN; + this.enableMultipleWriteLocations = false; + this.unavailableLocationsExpirationTime = Duration.ofSeconds(configs.getUnavailableLocationsExpirationTimeInSeconds()); + } + + /** + * Gets list of read endpoints ordered by + * + * 1. Preferred location + * 2. Endpoint availability + * @return + */ + public UnmodifiableList getReadEndpoints() { + if (this.locationUnavailabilityInfoByEndpoint.size() > 0 + && unavailableLocationsExpirationTimePassed()) { + this.updateLocationCache(); + } + + return this.locationInfo.readEndpoints; + } + + /** + * Gets list of write endpoints ordered by + * 1. Preferred location + * 2. Endpoint availability + * @return + */ + public UnmodifiableList getWriteEndpoints() { + if (this.locationUnavailabilityInfoByEndpoint.size() > 0 + && unavailableLocationsExpirationTimePassed()) { + this.updateLocationCache(); + } + + return this.locationInfo.writeEndpoints; + } + + /** + * Marks the current location unavailable for read + */ + public void markEndpointUnavailableForRead(URL endpoint) { + this.markEndpointUnavailable(endpoint, OperationType.Read); + } + + /** + * Marks the current location unavailable for write + */ + public void markEndpointUnavailableForWrite(URL endpoint) { + this.markEndpointUnavailable(endpoint, OperationType.Write); + } + + /** + * Invoked when {@link DatabaseAccount} is read + * @param databaseAccount READ DatabaseAccount + */ + public void onDatabaseAccountRead(DatabaseAccount databaseAccount) { + this.updateLocationCache( + databaseAccount.getWritableLocations(), + databaseAccount.getReadableLocations(), + null, + BridgeInternal.isEnableMultipleWriteLocations(databaseAccount)); + } + + void onLocationPreferenceChanged(UnmodifiableList preferredLocations) { + this.updateLocationCache( + null, null , preferredLocations, null); + } + + /** + * Resolves request to service endpoint. + * 1. If this is a write request + * (a) If UseMultipleWriteLocations = true + * (i) For document writes, resolve to most preferred and available write endpoint. + * Once the endpoint is marked unavailable, it is moved to the end of available write endpoint. Current request will + * be retried on next preferred available write endpoint. + * (ii) For all other resources, always resolve to first/second (regardless of preferred locations) + * write endpoint in {@link DatabaseAccount#getWritableLocations()}. + * Endpoint of first write location in {@link DatabaseAccount#getWritableLocations()} is the only endpoint that supports + * write operation on all resource types (except during that region's failover). + * Only during manual failover, client would retry write on second write location in {@link DatabaseAccount#getWritableLocations()}. + * (b) Else resolve the request to first write endpoint in {@link DatabaseAccount#getWritableLocations()} OR + * second write endpoint in {@link DatabaseAccount#getWritableLocations()} in case of manual failover of that location. + * 2. Else resolve the request to most preferred available read endpoint (automatic failover for read requests) + * @param request Request for which endpoint is to be resolved + * @return Resolved endpoint + */ + public URL resolveServiceEndpoint(RxDocumentServiceRequest request) { + if(request.requestContext != null && request.requestContext.locationEndpointToRoute != null) { + return request.requestContext.locationEndpointToRoute; + } + + int locationIndex = Utils.getValueOrDefault(request.requestContext.locationIndexToRoute, 0); + + boolean usePreferredLocations = request.requestContext.usePreferredLocations != null ? request.requestContext.usePreferredLocations : true; + if(!usePreferredLocations || (request.getOperationType().isWriteOperation() && !this.canUseMultipleWriteLocations(request))) { + // For non-document resource types in case of client can use multiple write locations + // or when client cannot use multiple write locations, flip-flop between the + // first and the second writable region in DatabaseAccount (for manual failover) + DatabaseAccountLocationsInfo currentLocationInfo = this.locationInfo; + + if(this.enableEndpointDiscovery && currentLocationInfo.availableWriteLocations.size() > 0) { + locationIndex = Math.min(locationIndex%2, currentLocationInfo.availableWriteLocations.size()-1); + String writeLocation = currentLocationInfo.availableWriteLocations.get(locationIndex); + return currentLocationInfo.availableWriteEndpointByLocation.get(writeLocation); + } else { + return this.defaultEndpoint; + } + } else { + UnmodifiableList endpoints = request.getOperationType().isWriteOperation()? this.getWriteEndpoints() : this.getReadEndpoints(); + return endpoints.get(locationIndex % endpoints.size()); + } + } + + public boolean shouldRefreshEndpoints(Utils.ValueHolder canRefreshInBackground) { + canRefreshInBackground.v = true; + DatabaseAccountLocationsInfo currentLocationInfo = this.locationInfo; + String mostPreferredLocation = Utils.firstOrDefault(currentLocationInfo.preferredLocations); + + // we should schedule refresh in background if we are unable to target the user's most preferredLocation. + if (this.enableEndpointDiscovery) { + + boolean shouldRefresh = this.useMultipleWriteLocations && !this.enableMultipleWriteLocations; + if (!Strings.isNullOrEmpty(mostPreferredLocation)) { + Utils.ValueHolder mostPreferredReadEndpointHolder = new Utils.ValueHolder<>(); + List readLocationEndpoints = currentLocationInfo.readEndpoints; + logger.debug("getReadEndpoints [{}]", readLocationEndpoints); + + if (Utils.tryGetValue(currentLocationInfo.availableReadEndpointByLocation, mostPreferredLocation, mostPreferredReadEndpointHolder)) { + logger.debug("most preferred is [{}], most preferred available is [{}]", + mostPreferredLocation, mostPreferredReadEndpointHolder.v); + if (!areEqual(mostPreferredReadEndpointHolder.v, readLocationEndpoints.get(0))) { + // For reads, we can always refresh in background as we can alternate to + // other available read endpoints + logger.debug("shouldRefreshEndpoints = true, most preferred location [{}]" + + " is not available for read.", mostPreferredLocation); + return true; + } + + logger.debug("most preferred is [{}], and most preferred available [{}] are the same", + mostPreferredLocation, mostPreferredReadEndpointHolder.v); + } + else { + logger.debug("shouldRefreshEndpoints = true, most preferred location [{}] " + + "is not in available read locations.", mostPreferredLocation); + return true; + } + } + + Utils.ValueHolder mostPreferredWriteEndpointHolder = new Utils.ValueHolder<>(); + List writeLocationEndpoints = currentLocationInfo.writeEndpoints; + logger.debug("getWriteEndpoints [{}]", writeLocationEndpoints); + + if (!this.canUseMultipleWriteLocations()) { + if (this.isEndpointUnavailable(writeLocationEndpoints.get(0), OperationType.Write)) { + // Since most preferred write endpoint is unavailable, we can only refresh in background if + // we have an alternate write endpoint + canRefreshInBackground.v = writeLocationEndpoints.size() > 1; + logger.debug("shouldRefreshEndpoints = true, most preferred location " + + "[{}] endpoint [{}] is not available for write. canRefreshInBackground = [{}]", + mostPreferredLocation, + writeLocationEndpoints.get(0), + canRefreshInBackground.v); + + return true; + } else { + logger.debug("shouldRefreshEndpoints: false, [{}] is available for Write", writeLocationEndpoints.get(0)); + return shouldRefresh; + } + } else if (!Strings.isNullOrEmpty(mostPreferredLocation)) { + if (Utils.tryGetValue(currentLocationInfo.availableWriteEndpointByLocation, mostPreferredLocation, mostPreferredWriteEndpointHolder)) { + shouldRefresh = ! areEqual(mostPreferredWriteEndpointHolder.v,writeLocationEndpoints.get(0)); + + if (shouldRefresh) { + logger.debug("shouldRefreshEndpoints: true, write endpoint [{}] is not the same as most preferred [{}]", + writeLocationEndpoints.get(0), mostPreferredWriteEndpointHolder.v); + } else { + logger.debug("shouldRefreshEndpoints: false, write endpoint [{}] is the same as most preferred [{}]", + writeLocationEndpoints.get(0), mostPreferredWriteEndpointHolder.v); + } + + return shouldRefresh; + } else { + logger.debug("shouldRefreshEndpoints = true, most preferred location [{}] is not in available write locations", + mostPreferredLocation); + return true; + } + } else { + logger.debug("shouldRefreshEndpoints: false, mostPreferredLocation [{}] is empty", mostPreferredLocation); + return shouldRefresh; + } + } else { + logger.debug("shouldRefreshEndpoints: false, endpoint discovery not enabled"); + return false; + } + } + private boolean areEqual(URL url1, URL url2) { + return url1.equals(url2); + } + + private void clearStaleEndpointUnavailabilityInfo() { + if (!this.locationUnavailabilityInfoByEndpoint.isEmpty()) { + List unavailableEndpoints = new ArrayList<>(this.locationUnavailabilityInfoByEndpoint.keySet()); + + for (URL unavailableEndpoint: unavailableEndpoints) { + Utils.ValueHolder unavailabilityInfoHolder = new Utils.ValueHolder<>(); + Utils.ValueHolder removedHolder = new Utils.ValueHolder<>(); + + if (Utils.tryGetValue(this.locationUnavailabilityInfoByEndpoint, unavailableEndpoint, unavailabilityInfoHolder) + && + durationPassed(Instant.now(), unavailabilityInfoHolder.v.LastUnavailabilityCheckTimeStamp, + this.unavailableLocationsExpirationTime) + + && Utils.tryRemove(this.locationUnavailabilityInfoByEndpoint, unavailableEndpoint, removedHolder)) { + logger.debug( + "Removed endpoint [{}] unavailable for operations [{}] from unavailableEndpoints", + unavailableEndpoint, + unavailabilityInfoHolder.v.UnavailableOperations); + } + } + } + } + + private boolean isEndpointUnavailable(URL endpoint, OperationType expectedAvailableOperations) { + Utils.ValueHolder unavailabilityInfoHolder = new Utils.ValueHolder<>(); + + if (expectedAvailableOperations == OperationType.None + || !Utils.tryGetValue(this.locationUnavailabilityInfoByEndpoint, endpoint, unavailabilityInfoHolder) + || !unavailabilityInfoHolder.v.UnavailableOperations.supports(expectedAvailableOperations)) { + return false; + } else { + if (durationPassed(Instant.now(), unavailabilityInfoHolder.v.LastUnavailabilityCheckTimeStamp, this.unavailableLocationsExpirationTime)) { + return false; + } else { + logger.debug( + "Endpoint [{}] unavailable for operations [{}] present in unavailableEndpoints", + endpoint, + unavailabilityInfoHolder.v.UnavailableOperations); + // Unexpired entry present. Endpoint is unavailable + return true; + } + } + } + + private void markEndpointUnavailable( + URL unavailableEndpoint, + OperationType unavailableOperationType) { + Instant currentTime = Instant.now(); + LocationUnavailabilityInfo updatedInfo = this.locationUnavailabilityInfoByEndpoint.compute( + unavailableEndpoint, + new BiFunction() { + @Override + public LocationUnavailabilityInfo apply(URL url, LocationUnavailabilityInfo info) { + + if (info == null) { + // not already present, add + return new LocationUnavailabilityInfo(currentTime, unavailableOperationType); + } else { + // already present, update + info.LastUnavailabilityCheckTimeStamp = currentTime; + info.UnavailableOperations = OperationType.combine(info.UnavailableOperations, unavailableOperationType); + return info; + } + + } + }); + + this.updateLocationCache(); + + logger.debug( + "Endpoint [{}] unavailable for [{}] added/updated to unavailableEndpoints with timestamp [{}]", + unavailableEndpoint, + unavailableOperationType, + updatedInfo.LastUnavailabilityCheckTimeStamp); + } + + private void updateLocationCache(){ + updateLocationCache(null, null, null, null); + } + + private void updateLocationCache( + Iterable writeLocations, + Iterable readLocations, + UnmodifiableList preferenceList, + Boolean enableMultipleWriteLocations) { + synchronized (this.lockObject) { + DatabaseAccountLocationsInfo nextLocationInfo = new DatabaseAccountLocationsInfo(this.locationInfo); + logger.debug("updating location cache ..., current readLocations [{}], current writeLocations [{}]", + nextLocationInfo.readEndpoints, nextLocationInfo.writeEndpoints); + + if (preferenceList != null) { + nextLocationInfo.preferredLocations = preferenceList; + } + + if (enableMultipleWriteLocations != null) { + this.enableMultipleWriteLocations = enableMultipleWriteLocations; + } + + this.clearStaleEndpointUnavailabilityInfo(); + + if (readLocations != null) { + Utils.ValueHolder> out = Utils.ValueHolder.initialize(nextLocationInfo.availableReadLocations); + nextLocationInfo.availableReadEndpointByLocation = this.getEndpointByLocation(readLocations, out); + nextLocationInfo.availableReadLocations = out.v; + } + + if (writeLocations != null) { + Utils.ValueHolder> out = Utils.ValueHolder.initialize(nextLocationInfo.availableWriteLocations); + nextLocationInfo.availableWriteEndpointByLocation = this.getEndpointByLocation(writeLocations, out); + nextLocationInfo.availableWriteLocations = out.v; + } + + nextLocationInfo.writeEndpoints = this.getPreferredAvailableEndpoints(nextLocationInfo.availableWriteEndpointByLocation, nextLocationInfo.availableWriteLocations, OperationType.Write, this.defaultEndpoint); + nextLocationInfo.readEndpoints = this.getPreferredAvailableEndpoints(nextLocationInfo.availableReadEndpointByLocation, nextLocationInfo.availableReadLocations, OperationType.Read, nextLocationInfo.writeEndpoints.get(0)); + this.lastCacheUpdateTimestamp = Instant.now(); + + logger.debug("updating location cache finished, new readLocations [{}], new writeLocations [{}]", + nextLocationInfo.readEndpoints, nextLocationInfo.writeEndpoints); + this.locationInfo = nextLocationInfo; + } + } + + private UnmodifiableList getPreferredAvailableEndpoints(UnmodifiableMap endpointsByLocation, + UnmodifiableList orderedLocations, + OperationType expectedAvailableOperation, + URL fallbackEndpoint) { + List endpoints = new ArrayList<>(); + DatabaseAccountLocationsInfo currentLocationInfo = this.locationInfo; + // if enableEndpointDiscovery is false, we always use the defaultEndpoint that user passed in during documentClient init + if (this.enableEndpointDiscovery) { + if (this.canUseMultipleWriteLocations() || expectedAvailableOperation.supports(OperationType.Read)) { + List unavailableEndpoints = new ArrayList<>(); + + // When client can not use multiple write locations, preferred locations list should only be used + // determining read endpoints order. + // If client can use multiple write locations, preferred locations list should be used for determining + // both read and write endpoints order. + + for (String location: currentLocationInfo.preferredLocations) { + Utils.ValueHolder endpoint = new Utils.ValueHolder<>(); + if (Utils.tryGetValue(endpointsByLocation, location, endpoint)) { + if (this.isEndpointUnavailable(endpoint.v, expectedAvailableOperation)) { + unavailableEndpoints.add(endpoint.v); + } else { + endpoints.add(endpoint.v); + } + } + } + + if (endpoints.isEmpty()) { + endpoints.add(fallbackEndpoint); + } + + endpoints.addAll(unavailableEndpoints); + } else { + for (String location : orderedLocations) { + + Utils.ValueHolder endpoint = Utils.ValueHolder.initialize(null); + if (!Strings.isNullOrEmpty(location) && // location is empty during manual failover + Utils.tryGetValue(endpointsByLocation, location, endpoint)) { + endpoints.add(endpoint.v); + } + } + } + } + + if (endpoints.isEmpty()) { + endpoints.add(fallbackEndpoint); + } + + return new UnmodifiableList(endpoints); + } + + private UnmodifiableMap getEndpointByLocation(Iterable locations, + Utils.ValueHolder> orderedLocations) { + Map endpointsByLocation = new CaseInsensitiveMap<>(); + List parsedLocations = new ArrayList<>(); + + for (DatabaseAccountLocation location: locations) { + if (!Strings.isNullOrEmpty(location.getName())) { + try { + URL endpoint = new URL(location.getEndpoint().toLowerCase()); + endpointsByLocation.put(location.getName().toLowerCase(), endpoint); + parsedLocations.add(location.getName()); + + } catch (Exception e) { + logger.warn("GetAvailableEndpointsByLocation() - skipping add for location = [{}] as it is location name is either empty or endpoint is malformed [{}]", + location.getName(), + location.getEndpoint()); + } + } + } + + orderedLocations.v = new UnmodifiableList(parsedLocations); + return (UnmodifiableMap) UnmodifiableMap.unmodifiableMap(endpointsByLocation); + } + + private boolean canUseMultipleWriteLocations() { + return this.useMultipleWriteLocations && this.enableMultipleWriteLocations; + } + + public boolean canUseMultipleWriteLocations(RxDocumentServiceRequest request) { + return this.canUseMultipleWriteLocations() && + (request.getResourceType() == ResourceType.Document || + (request.getResourceType() == ResourceType.StoredProcedure && request.getOperationType() == + com.azure.data.cosmos.internal.OperationType.ExecuteJavaScript)); + } + + + private class LocationUnavailabilityInfo { + LocationUnavailabilityInfo(Instant instant, OperationType type) { + this.LastUnavailabilityCheckTimeStamp = instant; + this.UnavailableOperations = type; + } + + public Instant LastUnavailabilityCheckTimeStamp; + public OperationType UnavailableOperations; + } + + private enum OperationType { + None(0x0), + Read(0x1), + Write(0x2), + ReadAndWrite(0x3); + + private final int flag; + + public boolean hasReadFlag() { + return (flag & Read.flag) != 0; + } + + public boolean hasWriteFlag() { + return (flag & Write.flag) != 0; + } + + public static OperationType combine(OperationType t1, OperationType t2) { + switch (t1.flag | t2.flag) { + case 0x0: + return None; + case 0x1: + return Read; + case 0x2: + return Write; + default: + return ReadAndWrite; + } + } + + public boolean supports(OperationType type) { + return (flag & type.flag) != 0; + } + + OperationType(int flag) { + this.flag = flag; + } + } + + private boolean durationPassed(Instant end, Instant start, Duration duration) { + return end.minus(duration).isAfter(start); + } + + private boolean unavailableLocationsExpirationTimePassed() { + return durationPassed(Instant.now(), this.lastCacheUpdateTimestamp, this.unavailableLocationsExpirationTime); + } + + class DatabaseAccountLocationsInfo { + private UnmodifiableList preferredLocations; + // lower-case region + private UnmodifiableList availableWriteLocations; + // lower-case region + private UnmodifiableList availableReadLocations; + private UnmodifiableMap availableWriteEndpointByLocation; + private UnmodifiableMap availableReadEndpointByLocation; + + private UnmodifiableList writeEndpoints; + private UnmodifiableList readEndpoints; + + public DatabaseAccountLocationsInfo(List preferredLocations, + URL defaultEndpoint) { + this.preferredLocations = new UnmodifiableList<>(preferredLocations.stream().map(loc -> loc.toLowerCase()).collect(Collectors.toList())); + this.availableWriteEndpointByLocation = (UnmodifiableMap) UnmodifiableMap.unmodifiableMap(new CaseInsensitiveMap<>()); + this.availableReadEndpointByLocation = (UnmodifiableMap) UnmodifiableMap.unmodifiableMap(new CaseInsensitiveMap<>()); + this.availableReadLocations = new UnmodifiableList<>(Collections.emptyList()); + this.availableWriteLocations = new UnmodifiableList<>(Collections.emptyList()); + this.readEndpoints = new UnmodifiableList<>(Collections.singletonList(defaultEndpoint)); + this.writeEndpoints = new UnmodifiableList<>(Collections.singletonList(defaultEndpoint)); + } + + public DatabaseAccountLocationsInfo(DatabaseAccountLocationsInfo other) { + this.preferredLocations = other.preferredLocations; + this.availableWriteLocations = other.availableWriteLocations; + this.availableReadLocations = other.availableReadLocations; + this.availableWriteEndpointByLocation = other.availableWriteEndpointByLocation; + this.availableReadEndpointByLocation = other.availableReadEndpointByLocation; + this.writeEndpoints = other.writeEndpoints; + this.readEndpoints = other.readEndpoints; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationHelper.java new file mode 100644 index 0000000000000..857da425275f5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/LocationHelper.java @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import org.apache.commons.lang3.StringUtils; + +import java.net.URL; + +public class LocationHelper { + /** + * For example, for https://contoso.documents.azure.com:443/ and "West US", this will return https://contoso-westus.documents.azure.com:443/ + * NOTE: This ONLY called by client first boot when the input endpoint is not available. + * + * @param serviceEndpoint + * @param location + * @return + */ + public static URL getLocationEndpoint(URL serviceEndpoint, String location) { + + // Split the host into 2 parts seperated by '.' + // For example, "contoso.documents.azure.com" is separated into "contoso" and "documents.azure.com" + // If the host doesn't contains '.', this will return the host as is, as the only element + String[] hostParts = StringUtils.split(serviceEndpoint.getHost(), ".", 2); + + String host; + if (hostParts.length != 0) { + // hostParts[0] will be the global account name + hostParts[0] = hostParts[0] + "-" + dataCenterToUriPostfix(location); + + // if hostParts has only one element, '.' is not included in the returned string + host = String.join(".", hostParts); + } else { + host = serviceEndpoint.getHost(); + } + + try { + return new URL(serviceEndpoint.getProtocol(), host, serviceEndpoint.getPort(), serviceEndpoint.getFile()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String dataCenterToUriPostfix(String dataCenter) { + return dataCenter.replace(" ", ""); + } +} + diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxNumberPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxNumberPartitionKeyComponent.java new file mode 100644 index 0000000000000..cc21423e379fb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxNumberPartitionKeyComponent.java @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class MaxNumberPartitionKeyComponent implements IPartitionKeyComponent { + public static final MaxNumberPartitionKeyComponent VALUE = new MaxNumberPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + MaxNumberPartitionKeyComponent otherMaxNumber = Utils.as(other, MaxNumberPartitionKeyComponent.class); + if (otherMaxNumber == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.MAXNUMBER.ordinal(); + } + + @Override + public void JsonEncode(JsonGenerator writer) { + PartitionKeyInternal.PartitionKeyInternalJsonSerializer.jsonEncode(this, writer); + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.MAXNUMBER.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxStringPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxStringPartitionKeyComponent.java new file mode 100644 index 0000000000000..f825135217885 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MaxStringPartitionKeyComponent.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class MaxStringPartitionKeyComponent implements IPartitionKeyComponent { + public static final MaxStringPartitionKeyComponent VALUE = new MaxStringPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + MaxStringPartitionKeyComponent otherMaxString = Utils.as(other, MaxStringPartitionKeyComponent.class); + if (otherMaxString == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.MAXSTRING.ordinal(); + } + + @Override + public void JsonEncode(JsonGenerator writer) { + PartitionKeyInternal.PartitionKeyInternalJsonSerializer.jsonEncode(this, writer); + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.MAXSTRING.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinNumberPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinNumberPartitionKeyComponent.java new file mode 100644 index 0000000000000..56c6063dfe240 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinNumberPartitionKeyComponent.java @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class MinNumberPartitionKeyComponent implements IPartitionKeyComponent { + public static final MinNumberPartitionKeyComponent VALUE = new MinNumberPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + MinNumberPartitionKeyComponent otherMinNumber = Utils.as(other, MinNumberPartitionKeyComponent.class); + if (otherMinNumber == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.MINNUMBER.ordinal(); + } + + @Override + public void JsonEncode(JsonGenerator writer) { + PartitionKeyInternal.PartitionKeyInternalJsonSerializer.jsonEncode(this, writer); + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.MINNUMBER.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinStringPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinStringPartitionKeyComponent.java new file mode 100644 index 0000000000000..21ca27251866f --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MinStringPartitionKeyComponent.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class MinStringPartitionKeyComponent implements IPartitionKeyComponent { + public static final MinStringPartitionKeyComponent VALUE = new MinStringPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + MinStringPartitionKeyComponent otherMinString = Utils.as(other, MinStringPartitionKeyComponent.class); + if (otherMinString == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.MINSTRING.ordinal(); + } + + @Override + public void JsonEncode(JsonGenerator writer) { + PartitionKeyInternal.PartitionKeyInternalJsonSerializer.jsonEncode(this, writer); + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + throw new UnsupportedOperationException(); + } + + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.MINSTRING.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_128.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_128.java new file mode 100644 index 0000000000000..c7214375ff803 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_128.java @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +public class MurmurHash3_128 { + + public static UInt128 hash128(byte[] bytes) { + return hash128(bytes, bytes.length, new UInt128(0, 0)); + } + + public static UInt128 hash128(byte[] bytes, int length, UInt128 seed) { + final long c1 = 0x87c37b91114253d5L; + final long c2 = 0x4cf5ad432745937fL; + + long h1 = seed.high; + long h2 = seed.low; + + // body + int position; + for (position = 0; position < length - 15; position += 16) { + long k1 = getLittleEndianLong(bytes, position); + long k2 = getLittleEndianLong(bytes, position + 8); + + // k1, h1 + k1 *= c1; + k1 = rotateLeft64(k1, 31); + k1 *= c2; + + h1 ^= k1; + h1 = rotateLeft64(h1, 27); + h1 += h2; + h1 = h1 * 5 + 0x52dce729; + + // k2, h2 + k2 *= c2; + k2 = rotateLeft64(k2, 33); + k2 *= c1; + + h2 ^= k2; + h2 = rotateLeft64(h2, 31); + h2 += h1; + h2 = h2 * 5 + 0x38495ab5; + } + + + { + // tail + long k1 = 0; + long k2 = 0; + + int n = length & 15; + if (n >= 15) k2 ^= (bytes[position + 14] & 0xffL) << 48; + if (n >= 14) k2 ^= (bytes[position + 13] & 0xffL) << 40; + if (n >= 13) k2 ^= (bytes[position + 12] & 0xffL) << 32; + if (n >= 12) k2 ^= (bytes[position + 11] & 0xffL) << 24; + if (n >= 11) k2 ^= (bytes[position + 10] & 0xffL) << 16; + if (n >= 10) k2 ^= (bytes[position + 9] & 0xffL) << 8; + if (n >= 9) k2 ^= (bytes[position + 8] & 0xffL) << 0; + + k2 *= c2; + k2 = rotateLeft64(k2, 33); + k2 *= c1; + h2 ^= k2; + + if (n >= 8) k1 ^= (bytes[position + 7] & 0xffL) << 56; + if (n >= 7) k1 ^= (bytes[position + 6] & 0xffL) << 48; + if (n >= 6) k1 ^= (bytes[position + 5] & 0xffL) << 40; + if (n >= 5) k1 ^= (bytes[position + 4] & 0xffL) << 32; + if (n >= 4) k1 ^= (bytes[position + 3] & 0xffL) << 24; + if (n >= 3) k1 ^= (bytes[position + 2] & 0xffL) << 16; + if (n >= 2) k1 ^= (bytes[position + 1] & 0xffL) << 8; + if (n >= 1) k1 ^= (bytes[position + 0] & 0xffL) << 0; + + k1 *= c1; + k1 = rotateLeft64(k1, 31); + k1 *= c2; + h1 ^= k1; + } + + // finalization + h1 ^= length; + h2 ^= length; + + h1 += h2; + h2 += h1; + + // h1 + h1 ^= h1 >>> 33; + h1 *= 0xff51afd7ed558ccdL; + h1 ^= h1 >>> 33; + h1 *= 0xc4ceb9fe1a85ec53L; + h1 ^= h1 >>> 33; + + // h2 + h2 ^= h2 >>> 33; + h2 *= 0xff51afd7ed558ccdL; + h2 ^= h2 >>> 33; + h2 *= 0xc4ceb9fe1a85ec53L; + h2 ^= h2 >>> 33; + + h1 += h2; + h2 += h1; + + h1 = Long.reverseBytes(h1); + h2 = Long.reverseBytes(h2); + + return new UInt128(h1, h2); + } + + + private static int rotateLeft32(int n, int numBits) { + assert numBits < 32; + return Integer.rotateLeft(n, numBits); + } + + private static long rotateLeft64(long n, int numBits) { + assert numBits < 64; + return Long.rotateLeft(n, numBits); + } + + private static final long getLittleEndianLong(byte[] bytes, int offset) { + return ((long) bytes[offset + 7] << 56) // no mask needed + | ((bytes[offset + 6] & 0xffL) << 48) + | ((bytes[offset + 5] & 0xffL) << 40) + | ((bytes[offset + 4] & 0xffL) << 32) + | ((bytes[offset + 3] & 0xffL) << 24) + | ((bytes[offset + 2] & 0xffL) << 16) + | ((bytes[offset + 1] & 0xffL) << 8) + | ((bytes[offset] & 0xffL)); + } + + private static int intAsLittleIndian(byte[] bytes, int i) { + return (bytes[i] & 0xff) | ((bytes[i + 1] & 0xff) << 8) | ((bytes[i + 2] & 0xff) << 16) | (bytes[i + 3] << 24); + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_32.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_32.java new file mode 100644 index 0000000000000..b5c723f177afb --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/MurmurHash3_32.java @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +/* + * The MurmurHash3 algorithm was created by Austin Appleby and placed in the public domain. + * This java port was authored by Yonik Seeley and also placed into the public domain. + * The author hereby disclaims copyright to this source code. + *

    + * This produces exactly the same hash values as the final C++ + * version of MurmurHash3 and is thus suitable for producing the same hash values across + * platforms. + *

    + * The 32 bit x86 version of this hash should be the fastest variant for relatively short keys like ids. + * See http://github.com/yonik/java_util for future updates to this file. + */ +public class MurmurHash3_32 { + /** + * Returns the MurmurHash3_x86_32 hash. + * + * @param data a byte array containing the data to be hashed + * @param len an integer indicating the length of data + * @param seed an integer to be used as hash seed + * @return the hash value + */ + public static int hash(byte[] data, int len, int seed) { + final int c1 = 0xcc9e2d51; + final int c2 = 0x1b873593; + + int h1 = seed; + int roundedEnd = (len & 0xfffffffc); // round down to 4 byte block + + for (int i = 0; i < roundedEnd; i += 4) { + // little endian load order + int k1 = (data[i] & 0xff) | ((data[i + 1] & 0xff) << 8) | ((data[i + 2] & 0xff) << 16) | (data[i + 3] << 24); + k1 *= c1; + k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = (h1 << 13) | (h1 >>> 19); // ROTL32(h1,13); + h1 = h1 * 5 + 0xe6546b64; + } + + // tail + int k1 = 0; + + switch (len & 0x03) { + case 3: + k1 = (data[roundedEnd + 2] & 0xff) << 16; + // fallthrough + case 2: + k1 |= (data[roundedEnd + 1] & 0xff) << 8; + // fallthrough + case 1: + k1 |= (data[roundedEnd] & 0xff); + k1 *= c1; + k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15); + k1 *= c2; + h1 ^= k1; + } + + // finalization + h1 ^= len; + + // fmix(h1); + h1 ^= h1 >>> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >>> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >>> 16; + + return h1; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NullPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NullPartitionKeyComponent.java new file mode 100644 index 0000000000000..5f5a4b9848b86 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NullPartitionKeyComponent.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class NullPartitionKeyComponent implements IPartitionKeyComponent { + + public static final NullPartitionKeyComponent VALUE = new NullPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + NullPartitionKeyComponent otherMinString = Utils.as(other, NullPartitionKeyComponent.class); + if (otherMinString == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.NULL.type; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + try { + writer.writeObject(null); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NULL.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NULL.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NULL.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NumberPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NumberPartitionKeyComponent.java new file mode 100644 index 0000000000000..4fa9d70aa7d1c --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/NumberPartitionKeyComponent.java @@ -0,0 +1,141 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Used internally to represent a number component in the partition key of the Azure Cosmos DB database service. + */ +public class NumberPartitionKeyComponent implements IPartitionKeyComponent { + + public static final NumberPartitionKeyComponent Zero = new NumberPartitionKeyComponent(0); + private final double value; + + public NumberPartitionKeyComponent(double value) { + this.value = value; + } + + private static byte[] doubleToByteArray(double d) { + byte[] output = new byte[8]; + long lng = Double.doubleToLongBits(d); + for (int i = 0; i < 8; i++) { + output[i] = (byte) ((lng >> (i * 8)) & 0xff); + } + return output; + } + + private static long EncodeDoubleAsUInt64(double value) { + long rawLongBits = Double.doubleToRawLongBits(value); + long mask = 0x8000000000000000L; + return Long.compareUnsigned(rawLongBits, mask) < 0 + ? rawLongBits ^ mask + : (~rawLongBits) + 1; + } + + @Override + public int CompareTo(IPartitionKeyComponent other) { + NumberPartitionKeyComponent otherBool = Utils.as(other, NumberPartitionKeyComponent.class); + if (otherBool == null) { + throw new IllegalArgumentException("other"); + } + + return Double.compare(this.value, ((NumberPartitionKeyComponent) other).value); + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.NUMBER.type; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + try { + writer.writeNumber(String.valueOf(value)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NUMBER.type); + outputStream.write(doubleToByteArray(this.value)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NUMBER.type); + outputStream.write(doubleToByteArray(this.value)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.NUMBER.type); + + long payload = NumberPartitionKeyComponent.EncodeDoubleAsUInt64(this.value); + + // Encode first chunk with 8-bits of payload + outputStream.write((byte) (payload >> (64 - 8))); + payload <<= 8; + + // Encode remaining chunks with 7 bits of payload followed by single "1" bit each. + byte byteToWrite = 0; + boolean firstIteration = true; + do { + if (!firstIteration) { + outputStream.write(byteToWrite); + } else { + firstIteration = false; + } + + byteToWrite = (byte) ((payload >> (64 - 8)) | 0x01); + payload <<= 7; + } while (payload != 0); + + // Except for last chunk that ends with "0" bit. + outputStream.write((byte) (byteToWrite & 0xFE)); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyAndResourceTokenPair.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyAndResourceTokenPair.java new file mode 100644 index 0000000000000..66183124b6a95 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyAndResourceTokenPair.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.routing; + +/** + * This is the pair for Partition key and its corresponding Resource Token , + * this is the value in resource token map which is getting filled during the + * construction of AsyncDocumentClient + */ +public class PartitionKeyAndResourceTokenPair { + + private PartitionKeyInternal partitionKey; + private String resourceToken; + + public PartitionKeyAndResourceTokenPair(PartitionKeyInternal partitionKey, String resourceToken) { + this.partitionKey = partitionKey; + this.resourceToken = resourceToken; + } + + /** + * Get the Partition Key + * + * @return Partition Key + */ + public PartitionKeyInternal getPartitionKey() { + return partitionKey; + } + + /** + * Sets the PartitionKey + * + * @param partitionKey + * The Partition key + */ + public void setPartitionKey(PartitionKeyInternal partitionKey) { + this.partitionKey = partitionKey; + } + + /** + * Gets the Resource Token + * + * @return Resource Token + */ + public String getResourceToken() { + return resourceToken; + } + + /** + * Sets the Resource Token + * + * @param resourceToken + * The Resource Token + */ + public void setResourceToken(String resourceToken) { + this.resourceToken = resourceToken; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyComponentType.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyComponentType.java new file mode 100644 index 0000000000000..24d8af6948aaf --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyComponentType.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +enum PartitionKeyComponentType { + UNDEFINED(0x0), + NULL(0x1), + FALSE(0x2), + TRUE(0x3), + MINNUMBER(0x4), + NUMBER(0x5), + MAXNUMBER(0x6), + MINSTRING(0x7), + STRING(0x8), + MAXSTRING(0x9), + INFINITY(0xFF); + + public final int type; + PartitionKeyComponentType(int type) { + this.type = type; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternal.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternal.java new file mode 100644 index 0000000000000..fc9c6e63c4e35 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternal.java @@ -0,0 +1,351 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.Strings; +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static com.azure.data.cosmos.internal.Utils.as; + +/** + * Used internally to encapsulate internal information of a partition key in the Azure Cosmos DB database service. + */ +@JsonSerialize(using = PartitionKeyInternal.PartitionKeyInternalJsonSerializer.class) +@JsonDeserialize(using = PartitionKeyInternal.PartitionKeyInternalJsonDeserializer.class) +public class PartitionKeyInternal implements Comparable { + + private static final String TYPE = "type"; + private static final String MIN_NUMBER = "MinNumber"; + private static final String MAX_NUMBER = "MaxNumber"; + private static final String MIN_STRING = "MinString"; + private static final String MAX_STRING = "MaxString"; + private static final String INFINITY = "Infinity"; + + public static final PartitionKeyInternal NonePartitionKey = + new PartitionKeyInternal(); + + public static final PartitionKeyInternal EmptyPartitionKey = + new PartitionKeyInternal(new ArrayList<>()); + + @SuppressWarnings("serial") + public static final PartitionKeyInternal InfinityPartitionKey = + new PartitionKeyInternal(new ArrayList() {{ + add(new InfinityPartitionKeyComponent()); + }}); + + @SuppressWarnings("serial") + public static final PartitionKeyInternal UndefinedPartitionKey = + new PartitionKeyInternal(new ArrayList() {{ + add(new UndefinedPartitionKeyComponent()); + }}); + + public static final PartitionKeyInternal InclusiveMinimum = PartitionKeyInternal.EmptyPartitionKey; + public static final PartitionKeyInternal ExclusiveMaximum = PartitionKeyInternal.InfinityPartitionKey; + public static final PartitionKeyInternal Empty = PartitionKeyInternal.EmptyPartitionKey; + public static final PartitionKeyInternal None = PartitionKeyInternal.NonePartitionKey; + + final List components; + + public PartitionKeyInternal(List values) { + if (values == null) { + throw new IllegalArgumentException("values"); + } + + this.components = values; + } + + public PartitionKeyInternal() { + this.components = null; + } + + public static PartitionKeyInternal fromJsonString(String partitionKey) { + if (Strings.isNullOrEmpty(partitionKey)) { + throw new IllegalArgumentException(String.format(RMResources.UnableToDeserializePartitionKeyValue, partitionKey)); + } + + try { + return Utils.getSimpleObjectMapper().readValue(partitionKey, PartitionKeyInternal.class); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + public static PartitionKeyInternal fromObjectArray(Object[] values, boolean strict) { + if (values == null) { + throw new IllegalArgumentException("values"); + } + + return PartitionKeyInternal.fromObjectArray(Arrays.asList(values), strict); + } + + public static PartitionKeyInternal fromObjectArray(List values, boolean strict) { + if (values == null) { + throw new IllegalArgumentException("values"); + } + + List components = new ArrayList<>(); + for (Object value : values) { + if (value == NullNode.instance || value == null) { + components.add(NullPartitionKeyComponent.VALUE); + } else if (value instanceof Undefined) { + components.add(UndefinedPartitionKeyComponent.VALUE); + } else if (value instanceof Boolean) { + components.add(new BoolPartitionKeyComponent((boolean) value)); + } else if (value instanceof String) { + components.add(new StringPartitionKeyComponent((String) value)); + } else if (isNumeric(value)) { + components.add(new NumberPartitionKeyComponent(((Number) value).doubleValue())); + } else if (value instanceof ObjectNode && ((ObjectNode) value).get(TYPE) != null) { + switch (((ObjectNode) value).get(TYPE).asText()) { + case MIN_NUMBER: + components.add(MinNumberPartitionKeyComponent.VALUE); + break; + case MAX_NUMBER: + components.add(MaxNumberPartitionKeyComponent.VALUE); + break; + case MIN_STRING: + components.add(MinStringPartitionKeyComponent.VALUE); + break; + case MAX_STRING: + components.add(MaxStringPartitionKeyComponent.VALUE); + break; + } + } else { + if (strict) { + throw new IllegalArgumentException("Unable to construct PartitionKeyInternal from objects array"); + } else { + components.add(UndefinedPartitionKeyComponent.VALUE); + } + } + } + + return new PartitionKeyInternal(components); + } + + private static boolean isNumeric(Object value) { + return value instanceof Number; + } + + private static PartitionKeyInternal getExclusiveMaximum() { + return PartitionKeyInternal.InfinityPartitionKey; + } + + public static PartitionKeyInternal getEmpty() { + return PartitionKeyInternal.EmptyPartitionKey; + } + + @Override + public boolean equals(Object obj) { + PartitionKeyInternal pki = as(obj, PartitionKeyInternal.class); + if (pki == null) { + return false; + } + + if (pki == this) { + return true; + } + + return this.compareTo(pki) == 0; + } + + public int compareTo(PartitionKeyInternal other) { + if (other == null) { + throw new IllegalArgumentException("other"); + } else if (other.components == null || this.components == null) { + int otherComponentsCount = other.components == null ? 0 : other.components.size(); + int thisComponentsCount = this.components == null ? 0 : this.components.size(); + return (int) Math.signum(thisComponentsCount - otherComponentsCount); + } + + for (int i = 0; i < Math.min(this.components.size(), other.components.size()); i++) { + int leftOrdinal = this.components.get(i).GetTypeOrdinal(); + int rightOrdinal = other.components.get(i).GetTypeOrdinal(); + if (leftOrdinal != rightOrdinal) { + return (int) Math.signum(leftOrdinal - rightOrdinal); + } + + int result = this.components.get(i).CompareTo(other.components.get(i)); + if (result != 0) { + return (int) Math.signum(result); + } + } + + return (int) Math.signum(this.components.size() - other.components.size()); + } + + public String toJson() { + try { + return Utils.getSimpleObjectMapper().writeValueAsString(this); + } catch (IOException e) { + throw new IllegalArgumentException("Unable serialize the partition key internal into the JSON string", e); + } + } + + public boolean contains(PartitionKeyInternal nestedPartitionKey) { + if (this.components.size() > nestedPartitionKey.components.size()) { + return false; + } + + for (int i = 0; i < this.components.size(); i++) { + if (this.components.get(i).CompareTo(nestedPartitionKey.components.get(i)) != 0) { + return false; + } + } + + return true; + } + + public List getComponents() { + return components; + } + + @SuppressWarnings("serial") + static final class PartitionKeyInternalJsonSerializer extends StdSerializer { + + protected PartitionKeyInternalJsonSerializer() { this(null); } + + protected PartitionKeyInternalJsonSerializer(Class t) { + super(t); + } + + @Override + public void serialize(PartitionKeyInternal partitionKey, JsonGenerator writer, SerializerProvider serializerProvider) { + try { + if (partitionKey.equals(PartitionKeyInternal.getExclusiveMaximum())) { + writer.writeString(INFINITY); + return; + } + + writer.writeStartArray(); + for (IPartitionKeyComponent componentValue : partitionKey.getComponents()) { + componentValue.JsonEncode(writer); + } + writer.writeEndArray(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + static void jsonEncode(MinNumberPartitionKeyComponent component, JsonGenerator writer) { + jsonEncodeLimit(writer, MIN_NUMBER); + } + + static void jsonEncode(MaxNumberPartitionKeyComponent component, JsonGenerator writer) { + jsonEncodeLimit(writer, MAX_NUMBER); + } + + static void jsonEncode(MinStringPartitionKeyComponent component, JsonGenerator writer) { + jsonEncodeLimit(writer, MIN_STRING); + } + + static void jsonEncode(MaxStringPartitionKeyComponent component, JsonGenerator writer) { + jsonEncodeLimit(writer, MAX_STRING); + } + + private static void jsonEncodeLimit(JsonGenerator writer, String value) { + try { + writer.writeStartObject(); + writer.writeFieldName(TYPE); + writer.writeString(value); + writer.writeEndObject(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + + @SuppressWarnings("serial") + static final class PartitionKeyInternalJsonDeserializer extends StdDeserializer { + + protected PartitionKeyInternalJsonDeserializer() { this(null); } + + protected PartitionKeyInternalJsonDeserializer(Class vc) { + super(vc); + } + + @Override + public PartitionKeyInternal deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) { + + ObjectCodec objectCodec = jsonParser.getCodec(); + JsonNode root; + try { + root = objectCodec.readTree(jsonParser); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + + if (root.isTextual() && root.asText().equals(INFINITY)) { + return PartitionKeyInternal.getExclusiveMaximum(); + } + + List objects = new ArrayList<>(); + if (root.isArray()) { + Iterator iterator = root.iterator(); + while (iterator.hasNext()) { + JsonNode node = iterator.next(); + if (node.isNull()) { + objects.add(null); + } else if (node.isNumber()) { + objects.add(node.asDouble()); + } else if (node.isBoolean()) { + objects.add(node.asBoolean()); + } else if (node.isTextual()) { + objects.add(node.asText()); + } else if (node.isArray() && node.size() == 0 + || node.isObject() + && (node.fields() == null || !node.fields().hasNext())) { + objects.add(Undefined.Value()); + } else { + objects.add(node); + } + } + return PartitionKeyInternal.fromObjectArray(objects, true); + } + + throw new IllegalStateException(String.format( + "Unable to deserialize PartitionKeyInternal '%s'", + root.toString())); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalHelper.java new file mode 100644 index 0000000000000..a322e3bc213e5 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalHelper.java @@ -0,0 +1,196 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.CommonsBridgeInternal; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.PartitionKind; +import com.azure.data.cosmos.internal.Bytes; +import com.azure.data.cosmos.internal.RMResources; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +public class PartitionKeyInternalHelper { + + public static final String MinimumInclusiveEffectivePartitionKey = PartitionKeyInternalHelper.toHexEncodedBinaryString(PartitionKeyInternal.EmptyPartitionKey.components); + public static final String MaximumExclusiveEffectivePartitionKey = PartitionKeyInternalHelper.toHexEncodedBinaryString(PartitionKeyInternal.InfinityPartitionKey.components); + + static final int MaxPartitionKeyBinarySize = + (1 /*type marker */ + + 9 /* hash value*/ + + 1 /* type marker*/ + StringPartitionKeyComponent.MAX_STRING_BYTES_TO_APPEND + + 1 /*trailing zero*/ + ) * 3; + private static final Int128 MaxHashV2Value = new Int128(new byte[] { + (byte) 0x3F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}); + + static byte[] uIntToBytes(UInt128 unit) { + ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * 2); + buffer.putLong(unit.low); + buffer.putLong(unit.high); + return buffer.array(); + } + + static long asUnsignedLong(int x) { + return x & 0x00000000ffffffffL; + } + + static byte[] longToBytes(long x) { + ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); + buffer.putLong(x); + return buffer.array(); + } + + static String toHexEncodedBinaryString(IPartitionKeyComponent... components) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(MaxPartitionKeyBinarySize); + for (IPartitionKeyComponent component: components) { + component.WriteForBinaryEncoding(stream); + } + + return HexConvert.bytesToHex(stream.toByteArray()); + } + + static String toHexEncodedBinaryString(List components) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(MaxPartitionKeyBinarySize); + for (IPartitionKeyComponent component: components) { + component.WriteForBinaryEncoding(stream); + } + + return HexConvert.bytesToHex(stream.toByteArray()); + } + + static public String getEffectivePartitionKeyForHashPartitioningV2(PartitionKeyInternal partitionKeyInternal) { + try(ByteArrayOutputStream byteArrayBuffer = new ByteArrayOutputStream()) { + for (int i = 0; i < partitionKeyInternal.components.size(); i++) { + partitionKeyInternal.components.get(i).WriteForHashingV2(byteArrayBuffer); + } + + byte[] bytes = byteArrayBuffer.toByteArray(); + UInt128 hashAsUnit128 = MurmurHash3_128.hash128(bytes); + + byte[] hash = uIntToBytes(hashAsUnit128); + Bytes.reverse(hash); + + // Reset 2 most significant bits, as max exclusive value is 'FF'. + // Plus one more just in case. + hash[0] &= 0x3F; + + return HexConvert.bytesToHex(hash); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + static String getEffectivePartitionKeyForHashPartitioning(PartitionKeyInternal partitionKeyInternal) { + IPartitionKeyComponent[] truncatedComponents = new IPartitionKeyComponent[partitionKeyInternal.components.size()]; + + for (int i = 0; i < truncatedComponents.length; i++) { + truncatedComponents[i] = partitionKeyInternal.components.get(i).Truncate(); + } + + double hash; + try(ByteArrayOutputStream byteArrayBuffer = new ByteArrayOutputStream()) { + for (int i = 0; i < truncatedComponents.length; i++) { + truncatedComponents[i].WriteForHashing(byteArrayBuffer); + } + + byte[] bytes = byteArrayBuffer.toByteArray(); + int hashAsInt = MurmurHash3_32.hash(bytes, bytes.length, 0); + hash = (double) asUnsignedLong(hashAsInt); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + + IPartitionKeyComponent[] partitionKeyComponents = new IPartitionKeyComponent[partitionKeyInternal.components.size() + 1]; + partitionKeyComponents[0] = new NumberPartitionKeyComponent(hash); + for (int i = 0; i < truncatedComponents.length; i++) { + partitionKeyComponents[i + 1] = truncatedComponents[i]; + } + + return toHexEncodedBinaryString(partitionKeyComponents); + } + + public static String getEffectivePartitionKeyString(PartitionKeyInternal partitionKeyInternal, PartitionKeyDefinition partitionKeyDefinition) { + return getEffectivePartitionKeyString(partitionKeyInternal, partitionKeyDefinition, true); + } + + public static String getEffectivePartitionKeyString(PartitionKeyInternal partitionKeyInternal, PartitionKeyDefinition partitionKeyDefinition, boolean strict) { + if (partitionKeyInternal.components == null) { + throw new IllegalArgumentException(RMResources.TooFewPartitionKeyComponents); + } + + if (partitionKeyInternal.equals(PartitionKeyInternal.EmptyPartitionKey)) { + return MinimumInclusiveEffectivePartitionKey; + } + + if (partitionKeyInternal.equals(PartitionKeyInternal.InfinityPartitionKey)) { + return MaximumExclusiveEffectivePartitionKey; + } + + if (partitionKeyInternal.components.size() < partitionKeyDefinition.paths().size()) { + throw new IllegalArgumentException(RMResources.TooFewPartitionKeyComponents); + } + + if (partitionKeyInternal.components.size() > partitionKeyDefinition.paths().size() && strict) { + throw new IllegalArgumentException(RMResources.TooManyPartitionKeyComponents); + } + + PartitionKind kind = partitionKeyDefinition.kind(); + if (kind == null) { + kind = PartitionKind.HASH; + } + + switch (kind) { + case HASH: + if (CommonsBridgeInternal.isV2(partitionKeyDefinition)) { + // V2 + return getEffectivePartitionKeyForHashPartitioningV2(partitionKeyInternal); + } else { + // V1 + return getEffectivePartitionKeyForHashPartitioning(partitionKeyInternal); + } + + default: + return toHexEncodedBinaryString(partitionKeyInternal.components); + } + } + + static class HexConvert { + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyRangeIdentity.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyRangeIdentity.java new file mode 100644 index 0000000000000..148c4401c58d9 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/PartitionKeyRangeIdentity.java @@ -0,0 +1,111 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import org.apache.commons.lang3.StringUtils; + +/** + * Used internally to represents the identity of a partition key range in the Azure Cosmos DB database service. + */ +public final class PartitionKeyRangeIdentity { + private String collectionRid; + private String partitionKeyRangeId; + + public PartitionKeyRangeIdentity(String collectionRid, String partitionKeyRangeId) { + if (collectionRid == null) { + throw new IllegalArgumentException("collectionRid"); + } + + if (partitionKeyRangeId == null) { + throw new IllegalArgumentException("partitionKeyRangeId"); + } + + this.collectionRid = collectionRid; + this.partitionKeyRangeId = partitionKeyRangeId; + } + + /** + * This should only be used for user provided partitionKeyRangeId, because in this case + * he knows what he is doing. If collection was deleted/created with same name - it is his responsibility. + *

    + * If our code infers partitionKeyRangeId automatically and uses collection information from collection cache, + * we need to ensure that request will reach correct collection. In this case constructor which takes collectionRid MUST + * be used. + * + * @param partitionKeyRangeId a string represents the partition key range Id + */ + public PartitionKeyRangeIdentity(String partitionKeyRangeId) { + if (partitionKeyRangeId == null) { + throw new IllegalArgumentException("partitionKeyRangeId"); + } + + this.partitionKeyRangeId = partitionKeyRangeId; + } + + public static PartitionKeyRangeIdentity fromHeader(String header) { + String[] parts = StringUtils.split(header,","); + if (parts.length == 2) { + return new PartitionKeyRangeIdentity(parts[0], parts[1]); + } else if (parts.length == 1) { + return new PartitionKeyRangeIdentity(parts[0]); + } else { + throw new IllegalStateException("x-ms-documentdb-partitionkeyrangeid header contains invalid value '" + header + "'"); + } + } + + public String toHeader() { + if (this.collectionRid != null) { + return String.format("%s,%s", this.collectionRid, this.partitionKeyRangeId); + } + + return String.format("%s", this.partitionKeyRangeId); + } + + @Override + public boolean equals(Object other) { + if (null == other) { + return false; + } + if (this == other) { + return true; + } + return other instanceof PartitionKeyRangeIdentity + && ((PartitionKeyRangeIdentity) other).collectionRid.equals(this.collectionRid) + && ((PartitionKeyRangeIdentity) other).partitionKeyRangeId.equals(this.partitionKeyRangeId); + } + + @Override + public int hashCode() { + return ((this.collectionRid != null ? this.collectionRid.hashCode() : 0) * 397) + ^ (this.partitionKeyRangeId != null ? this.partitionKeyRangeId.hashCode() : 0); + } + + public String getCollectionRid() { + return collectionRid; + } + + public String getPartitionKeyRangeId() { + return partitionKeyRangeId; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Range.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Range.java new file mode 100644 index 0000000000000..6e074fc337874 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/Range.java @@ -0,0 +1,193 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.JsonSerializable; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Comparator; + +@JsonIgnoreProperties({ "empty", "singleValue", "hashMap" }) +public final class Range> extends JsonSerializable { + private static final String MIN_PROPERTY = "min"; + private static final String MAX_PROPERTY = "max"; + private static final String IS_MIN_INCLUSIVE_PROPERTY = "isMinInclusive"; + private static final String IS_MAX_INCLUSIVE_PROPERTY = "isMaxInclusive"; + + private T minValue; + private T maxValue; + + public Range() { + super(); + } + + public Range(String jsonString) { + super(jsonString); + } + + public Range(T min, T max, boolean isMinInclusive, boolean isMaxInclusive) { + this.setMin(min); + this.setMax(max); + this.setMinInclusive(isMinInclusive); + this.setMaxInclusive(isMaxInclusive); + } + + public static > Range getPointRange(T value) { + return new Range(value, value, true, true); + } + + public static > Range getEmptyRange(T value) { + return new Range(value, value, true, false); + } + + public static > boolean checkOverlapping(Range range1, Range range2) { + if (range1 == null || range2 == null || range1.isEmpty() || range2.isEmpty()) { + return false; + } + + int cmp1 = range1.getMin().compareTo(range2.getMax()); + int cmp2 = range2.getMin().compareTo(range1.getMax()); + + if (cmp1 <= 0 && cmp2 <= 0) { + return !((cmp1 == 0 && !(range1.isMinInclusive() && range2.isMaxInclusive())) + || (cmp2 == 0 && !(range2.isMinInclusive() && range1.isMaxInclusive()))); + } + + return false; + } + + @SuppressWarnings("unchecked") + public T getMin() { + if (this.minValue == null) { + this.minValue = (T) super.get(Range.MIN_PROPERTY); + } + + return this.minValue; + } + + public void setMin(T min) { + this.minValue = min; + BridgeInternal.setProperty(this, Range.MIN_PROPERTY, min); + } + + @SuppressWarnings("unchecked") + public T getMax() { + if (this.maxValue == null) { + this.maxValue = (T) super.get(Range.MAX_PROPERTY); + } + + return this.maxValue; + } + + public void setMax(T max) { + this.maxValue = max; + BridgeInternal.setProperty(this, Range.MAX_PROPERTY, max); + } + + @JsonProperty("isMinInclusive") + public boolean isMinInclusive() { + return super.getBoolean(Range.IS_MIN_INCLUSIVE_PROPERTY); + } + + public void setMinInclusive(boolean isMinInclusive) { + BridgeInternal.setProperty(this, Range.IS_MIN_INCLUSIVE_PROPERTY, isMinInclusive); + } + + @JsonProperty("isMaxInclusive") + public boolean isMaxInclusive() { + return super.getBoolean(Range.IS_MAX_INCLUSIVE_PROPERTY); + } + + public void setMaxInclusive(boolean isMaxInclusive) { + BridgeInternal.setProperty(this, Range.IS_MAX_INCLUSIVE_PROPERTY, isMaxInclusive); + } + + public boolean isSingleValue() { + return this.isMinInclusive() && this.isMaxInclusive() && this.getMin().compareTo(this.getMax()) == 0; + } + + public boolean isEmpty() { + return this.getMin().compareTo(this.getMax()) == 0 && !(this.isMinInclusive() && this.isMaxInclusive()); + } + + public boolean contains(T value) { + int minToValueRelation = this.getMin().compareTo(value); + int maxToValueRelation = this.getMax().compareTo(value); + + return ((this.isMinInclusive() && minToValueRelation <= 0) + || (!this.isMinInclusive() && minToValueRelation < 0)) + && ((this.isMaxInclusive() && maxToValueRelation >= 0) + || (!this.isMaxInclusive() && maxToValueRelation > 0)); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Range)) + return false; + if (obj == this) + return true; + @SuppressWarnings("unchecked") + Range otherRange = (Range) obj; + + return this.getMin().compareTo(otherRange.getMin()) == 0 && this.getMax().compareTo(otherRange.getMax()) == 0 + && this.isMinInclusive() == otherRange.isMinInclusive() + && this.isMaxInclusive() == otherRange.isMaxInclusive(); + } + + @Override + public int hashCode() { + int hash = 0; + hash = (hash * 397) ^ this.getMin().hashCode(); + hash = (hash * 397) ^ this.getMax().hashCode(); + hash = (hash * 397) ^ Boolean.compare(this.isMinInclusive(), false); + hash = (hash * 397) ^ Boolean.compare(this.isMaxInclusive(), false); + return hash; + } + + public static class MinComparator> implements Comparator> { + @Override + public int compare(Range range1, Range range2) { + int result = range1.getMin().compareTo(range2.getMin()); + if (result != 0 || range1.isMinInclusive() == range2.isMinInclusive()) { + return result; + } + + return range1.isMinInclusive() ? -1 : 1; + } + } + + public static class MaxComparator> implements Comparator> { + @Override + public int compare(Range range1, Range range2) { + int result = range1.getMax().compareTo(range2.getMax()); + if (result != 0 || range1.isMaxInclusive() == range2.isMaxInclusive()) { + return result; + } + + return range1.isMaxInclusive() ? 1 : -1; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProvider.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProvider.java new file mode 100644 index 0000000000000..1b71b61269153 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProvider.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; + +import java.util.Collection; + +/** + * Used internally in request routing in the Azure Cosmos DB database service. + */ +public interface RoutingMapProvider { + Collection getOverlappingRanges(String collectionSelfLink, Range range, boolean forceRefresh); + + PartitionKeyRange tryGetRangeByEffectivePartitionKey(String collectionSelfLink, String effectivePartitionKey); + + PartitionKeyRange getPartitionKeyRangeById(String collectionSelfLink, String partitionKeyRangeId, boolean forceRefresh); + +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelper.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelper.java new file mode 100644 index 0000000000000..512e12641f636 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelper.java @@ -0,0 +1,97 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Provide utility functionality to route request in direct connectivity mode in the Azure Cosmos DB database service. + */ +public final class RoutingMapProviderHelper { + private static final Range.MaxComparator MAX_COMPARATOR = new Range.MaxComparator(); + + private static String max(String left, String right) { + return left.compareTo(right) < 0 ? right : left; + } + + private static > boolean IsSortedAndNonOverlapping(List> list) { + for (int i = 1; i < list.size(); i++) { + Range previousRange = list.get(i - 1); + Range currentRange = list.get(i); + + int compareResult = previousRange.getMax().compareTo(currentRange.getMin()); + if (compareResult > 0) { + return false; + } else if (compareResult == 0 && previousRange.isMaxInclusive() && currentRange.isMinInclusive()) { + return false; + } + } + + return true; + } + + public static Collection getOverlappingRanges(RoutingMapProvider routingMapProvider, + String collectionSelfLink, List> sortedRanges) { + if (!IsSortedAndNonOverlapping(sortedRanges)) { + throw new IllegalArgumentException("sortedRanges"); + } + + List targetRanges = new ArrayList(); + int currentProvidedRange = 0; + while (currentProvidedRange < sortedRanges.size()) { + if (sortedRanges.get(currentProvidedRange).isEmpty()) { + currentProvidedRange++; + continue; + } + + Range queryRange; + if (!targetRanges.isEmpty()) { + String left = max(targetRanges.get(targetRanges.size() - 1).getMaxExclusive(), + sortedRanges.get(currentProvidedRange).getMin()); + + boolean leftInclusive = left.compareTo(sortedRanges.get(currentProvidedRange).getMin()) == 0 + ? sortedRanges.get(currentProvidedRange).isMinInclusive() : false; + + queryRange = new Range(left, sortedRanges.get(currentProvidedRange).getMax(), leftInclusive, + sortedRanges.get(currentProvidedRange).isMaxInclusive()); + } else { + queryRange = sortedRanges.get(currentProvidedRange); + } + + targetRanges.addAll(routingMapProvider.getOverlappingRanges(collectionSelfLink, queryRange, false)); + + Range lastKnownTargetRange = targetRanges.get(targetRanges.size() - 1).toRange(); + while (currentProvidedRange < sortedRanges.size() + && MAX_COMPARATOR.compare(sortedRanges.get(currentProvidedRange), lastKnownTargetRange) <= 0) { + currentProvidedRange++; + } + } + + return targetRanges; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponent.java new file mode 100644 index 0000000000000..66b79466f46f3 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponent.java @@ -0,0 +1,132 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +class StringPartitionKeyComponent implements IPartitionKeyComponent { + + public static final int MAX_STRING_CHARS = 100; + public static final int MAX_STRING_BYTES_TO_APPEND = 100; + private final String value; + private final byte[] utf8Value; + + public StringPartitionKeyComponent(String value) { + if (value == null) { + throw new IllegalArgumentException("value"); + } + + this.value = value; + try { + this.utf8Value = com.azure.data.cosmos.internal.Utils.getUTF8Bytes(value); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public int CompareTo(IPartitionKeyComponent other) { + StringPartitionKeyComponent otherString = Utils.as(other, StringPartitionKeyComponent.class) ; + if (otherString == null) { + throw new IllegalArgumentException("other"); + } + + return this.value.compareTo(otherString.value); + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.STRING.type; + } + + @Override + public int hashCode() { + // hashCode for hashmap dictionary, etc + return value.hashCode(); + } + + public IPartitionKeyComponent Truncate() { + if (this.value.length() > MAX_STRING_CHARS) { + return new StringPartitionKeyComponent(this.value.substring(0, MAX_STRING_CHARS)); + } + + return this; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + try { + writer.writeString(this.value); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.STRING.type); + outputStream.write(utf8Value); + outputStream.write((byte) 0); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.STRING.type); + outputStream.write(utf8Value); + outputStream.write((byte) 0xFF); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.STRING.type); + boolean shortString = this.utf8Value.length <= MAX_STRING_BYTES_TO_APPEND; + + for (int index = 0; index < (shortString ? this.utf8Value.length : MAX_STRING_BYTES_TO_APPEND + 1); index++) { + byte charByte = this.utf8Value[index]; + if (charByte < 0xFF) charByte++; + outputStream.write(charByte); + } + + if (shortString) { + outputStream.write((byte) 0x00); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UInt128.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UInt128.java new file mode 100644 index 0000000000000..f34a5ba77b712 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UInt128.java @@ -0,0 +1,34 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +class UInt128 { + long low; + long high; + + UInt128(long x, long y) { + this.low = x; + this.high = y; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UndefinedPartitionKeyComponent.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UndefinedPartitionKeyComponent.java new file mode 100644 index 0000000000000..f67302bf73fb2 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/internal/routing/UndefinedPartitionKeyComponent.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.core.JsonGenerator; + +import java.io.IOException; +import java.io.OutputStream; + +class UndefinedPartitionKeyComponent implements IPartitionKeyComponent { + + public static final UndefinedPartitionKeyComponent VALUE = new UndefinedPartitionKeyComponent(); + + @Override + public int CompareTo(IPartitionKeyComponent other) { + UndefinedPartitionKeyComponent otherUndefined = Utils.as(other, UndefinedPartitionKeyComponent.class); + if (otherUndefined == null) { + throw new IllegalArgumentException("other"); + } + + return 0; + } + + @Override + public int GetTypeOrdinal() { + return PartitionKeyComponentType.UNDEFINED.type; + } + + @Override + public void JsonEncode(JsonGenerator writer) { + try { + writer.writeStartObject(); + writer.writeEndObject(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashing(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.UNDEFINED.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForHashingV2(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.UNDEFINED.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void WriteForBinaryEncoding(OutputStream outputStream) { + try { + outputStream.write((byte) PartitionKeyComponentType.UNDEFINED.type); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public IPartitionKeyComponent Truncate() { + return this; + } +} diff --git a/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/package-info.java b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/package-info.java new file mode 100644 index 0000000000000..683bac20c6956 --- /dev/null +++ b/sdk/cosmos/sdk/src/main/java/com/azure/data/cosmos/package-info.java @@ -0,0 +1,26 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * This package provides Rx interfaces for interacting with Azure Cosmos DB. + */ +package com.azure.data.cosmos; \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/BridgeUtils.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/BridgeUtils.java new file mode 100644 index 0000000000000..864c5cf448874 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/BridgeUtils.java @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.DatabaseAccountLocation; + +import java.util.List; + +/** + * This is a helper class for testing. + */ +public class BridgeUtils { + + public static DatabaseAccount createDatabaseAccount(List readLocations, + List writeLocations, + boolean useMultipleWriteLocations) { + DatabaseAccount dbAccount = new DatabaseAccount(); + dbAccount.setEnableMultipleWriteLocations(useMultipleWriteLocations); + + dbAccount.setReadableLocations(readLocations); + dbAccount.setWritableLocations(writeLocations); + + return dbAccount; + } + + public static DatabaseAccountLocation createDatabaseAccountLocation(String name, String endpoint) { + DatabaseAccountLocation dal = new DatabaseAccountLocation(); + dal.setName(name); + dal.setEndpoint(endpoint); + + return dal; + } + + public static ConflictResolutionPolicy createConflictResolutionPolicy() { + return new ConflictResolutionPolicy(); + } + + public static ConflictResolutionPolicy setMode(ConflictResolutionPolicy policy, ConflictResolutionMode mode) { + policy.mode(mode); + return policy; + } + + public static ConflictResolutionPolicy setPath(ConflictResolutionPolicy policy, String path) { + policy.conflictResolutionPath(path); + return policy; + } + + public static ConflictResolutionPolicy setStoredProc(ConflictResolutionPolicy policy, String storedProcLink) { + policy.conflictResolutionProcedure(storedProcLink); + return policy; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ClientUnderTestBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ClientUnderTestBuilder.java new file mode 100644 index 0000000000000..e597e9d2676d7 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ClientUnderTestBuilder.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.RxDocumentClientUnderTest; +import com.azure.data.cosmos.internal.directconnectivity.ReflectionUtils; + +import java.net.URI; +import java.net.URISyntaxException; + +public class ClientUnderTestBuilder extends CosmosClientBuilder { + + public ClientUnderTestBuilder(CosmosClientBuilder builder) { + this.configs(builder.configs()); + this.connectionPolicy(builder.connectionPolicy()); + this.consistencyLevel(builder.consistencyLevel()); + this.key(builder.key()); + this.endpoint(builder.endpoint()); + } + + @Override + public CosmosClient build() { + RxDocumentClientUnderTest rxClient; + try { + rxClient = new RxDocumentClientUnderTest( + new URI(this.endpoint()), + this.key(), + this.connectionPolicy(), + this.consistencyLevel(), + this.configs()); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getMessage()); + } + CosmosClient cosmosClient = super.build(); + ReflectionUtils.setAsyncDocumentClient(cosmosClient, rxClient); + return cosmosClient; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConflictTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConflictTests.java new file mode 100644 index 0000000000000..2ecafa25a9b90 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConflictTests.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Conflict; +import com.azure.data.cosmos.internal.Document; +import org.apache.commons.io.IOUtils; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConflictTests { + private String conflictAsString; + + @BeforeClass(groups = { "unit" }) + public void setup() throws Exception { + conflictAsString = IOUtils.toString( + getClass().getClassLoader().getResourceAsStream("sampleConflict.json"), "UTF-8"); + } + + @Test(groups = { "unit" }) + public void getSourceResourceId() { + Conflict conf = new Conflict(conflictAsString); + assertThat(conf.getSourceResourceId()).isEqualTo("k6d9ALgBmD+ChB4AAAAAAA=="); + } + + @Test(groups = { "unit" }) + public void getOperationKind() { + Conflict conf = new Conflict(conflictAsString); + assertThat(conf.getOperationKind()).isEqualTo("create"); + conf.getSourceResourceId(); + } + + @Test(groups = { "unit" }) + public void getResourceType() { + Conflict conf = new Conflict(conflictAsString); + assertThat(conf.getResouceType()).isEqualTo("document"); + conf.getSourceResourceId(); + } + + @Test(groups = { "unit" }) + public void getResource() { + Conflict conf = new Conflict(conflictAsString); + Document doc = conf.getResource(Document.class); + assertThat(doc.id()).isEqualTo("0007312a-a1c5-4b54-9e39-35de2367fa33"); + assertThat(doc.getInt("regionId")).isEqualTo(2); + assertThat(doc.resourceId()).isEqualTo("k6d9ALgBmD+ChB4AAAAAAA=="); + assertThat(doc.etag()).isEqualTo("\"00000200-0000-0000-0000-5b6e214b0000\""); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConnectionPolicyTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConnectionPolicyTest.java new file mode 100644 index 0000000000000..ee9878c43ccb5 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ConnectionPolicyTest.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConnectionPolicyTest { + + @DataProvider(name = "connectionModeArgProvider") + public Object[][] connectionModeArgProvider() { + return new Object[][]{ + { ConnectionMode.GATEWAY}, + { ConnectionMode.DIRECT}, + }; + } + + @Test(groups = { "unit" }, dataProvider = "connectionModeArgProvider") + public void connectionMode(ConnectionMode connectionMode) { + ConnectionPolicy policy = new ConnectionPolicy(); + policy.connectionMode(connectionMode); + + assertThat(policy.connectionMode()).isEqualTo(connectionMode); + } + + @DataProvider(name = "connectionProtocolModeArgProvider") + public Object[][] connectionProtocolModeArgProvider() { + return new Object[][]{ + { Protocol.HTTPS}, + { Protocol.TCP}, + }; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientExceptionTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientExceptionTest.java new file mode 100644 index 0000000000000..12b15173cc756 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientExceptionTest.java @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.google.common.collect.ImmutableMap; +import org.testng.annotations.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CosmosClientExceptionTest { + + @Test(groups = { "unit" }) + public void headerNotNull1() { + CosmosClientException dce = BridgeInternal.createCosmosClientException(0); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull2() { + CosmosClientException dce = BridgeInternal.createCosmosClientException(0, "dummy"); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull3() { + CosmosClientException dce = BridgeInternal.createCosmosClientException(0, new RuntimeException()); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull4() { + CosmosClientException dce = BridgeInternal.createCosmosClientException(0, (CosmosError) null, (Map) null); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull5() { + CosmosClientException dce = BridgeInternal.createCosmosClientException((String) null, 0, (CosmosError) null, (Map) null); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull6() { + CosmosClientException dce = BridgeInternal.createCosmosClientException((String) null, (Exception) null, (Map) null, 0, (String) null); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).isEmpty(); + } + + @Test(groups = { "unit" }) + public void headerNotNull7() { + ImmutableMap respHeaders = ImmutableMap.of("key", "value"); + CosmosClientException dce = BridgeInternal.createCosmosClientException((String) null, (Exception) null, respHeaders, 0, (String) null); + assertThat(dce.responseHeaders()).isNotNull(); + assertThat(dce.responseHeaders()).contains(respHeaders.entrySet().iterator().next()); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientTest.java new file mode 100644 index 0000000000000..dce8d389f77aa --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosClientTest.java @@ -0,0 +1,79 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.google.common.base.Strings; +import org.testng.ITest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import java.lang.reflect.Method; + +public abstract class CosmosClientTest implements ITest { + + private final CosmosClientBuilder clientBuilder; + private String testName; + + public CosmosClientTest() { + this(new CosmosClientBuilder()); + } + + public CosmosClientTest(CosmosClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + public final CosmosClientBuilder clientBuilder() { + return this.clientBuilder; + } + + @Override + public final String getTestName() { + return this.testName; + } + + @BeforeMethod(alwaysRun = true) + public final void setTestName(Method method) { + String testClassAndMethodName = Strings.lenientFormat("%s::%s", + method.getDeclaringClass().getSimpleName(), + method.getName()); + + if (this.clientBuilder.connectionPolicy() != null && this.clientBuilder.configs() != null) { + String connectionMode = this.clientBuilder.connectionPolicy().connectionMode() == ConnectionMode.DIRECT + ? "Direct " + this.clientBuilder.configs().getProtocol() + : "Gateway"; + + this.testName = Strings.lenientFormat("%s[%s with %s consistency]", + testClassAndMethodName, + connectionMode, + clientBuilder.consistencyLevel()); + } else { + this.testName = testClassAndMethodName; + } + } + + @AfterMethod(alwaysRun = true) + public final void unsetTestName() { + this.testName = null; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosDatabaseForTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosDatabaseForTest.java new file mode 100644 index 0000000000000..dd9266c790445 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosDatabaseForTest.java @@ -0,0 +1,130 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CosmosDatabaseForTest { + private static Logger logger = LoggerFactory.getLogger(CosmosDatabaseForTest.class); + public static final String SHARED_DB_ID_PREFIX = "RxJava.SDKTest.SharedDatabase"; + private static final Duration CLEANUP_THRESHOLD_DURATION = Duration.ofHours(2); + private static final String DELIMITER = "_"; + private static DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); + + public LocalDateTime createdTime; + public CosmosDatabase createdDatabase; + + private CosmosDatabaseForTest(CosmosDatabase db, LocalDateTime createdTime) { + this.createdDatabase = db; + this.createdTime = createdTime; + } + + private boolean isStale() { + return isOlderThan(CLEANUP_THRESHOLD_DURATION); + } + + private boolean isOlderThan(Duration dur) { + return createdTime.isBefore(LocalDateTime.now().minus(dur)); + } + + public static String generateId() { + return SHARED_DB_ID_PREFIX + DELIMITER + TIME_FORMATTER.format(LocalDateTime.now()) + DELIMITER + RandomStringUtils.randomAlphabetic(3); + } + + private static CosmosDatabaseForTest from(CosmosDatabase db) { + if (db == null || db.id() == null || db.getLink() == null) { + return null; + } + + String id = db.id(); + if (id == null) { + return null; + } + + String[] parts = StringUtils.split(id, DELIMITER); + if (parts.length != 3) { + return null; + } + if (!StringUtils.equals(parts[0], SHARED_DB_ID_PREFIX)) { + return null; + } + + try { + LocalDateTime parsedTime = LocalDateTime.parse(parts[1], TIME_FORMATTER); + return new CosmosDatabaseForTest(db, parsedTime); + } catch (Exception e) { + return null; + } + } + + public static CosmosDatabaseForTest create(DatabaseManager client) { + CosmosDatabaseProperties dbDef = new CosmosDatabaseProperties(generateId()); + + CosmosDatabase db = client.createDatabase(dbDef).block().database(); + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.from(db); + assertThat(dbForTest).isNotNull(); + return dbForTest; + } + + public static void cleanupStaleTestDatabases(DatabaseManager client) { + logger.info("Cleaning stale test databases ..."); + List dbs = client.queryDatabases( + new SqlQuerySpec("SELECT * FROM c WHERE STARTSWITH(c.id, @PREFIX)", + new SqlParameterList(new SqlParameter("@PREFIX", CosmosDatabaseForTest.SHARED_DB_ID_PREFIX)))) + .flatMap(page -> Flux.fromIterable(page.results())).collectList().block(); + + for (CosmosDatabaseProperties db : dbs) { + assertThat(db.id()).startsWith(CosmosDatabaseForTest.SHARED_DB_ID_PREFIX); + + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.from(client.getDatabase(db.id())); + + if (db != null && dbForTest.isStale()) { + logger.info("Deleting database {}", db.id()); + dbForTest.deleteDatabase(db.id()); + } + } + } + + private void deleteDatabase(String id) { + this.createdDatabase.delete().block(); + } + + public interface DatabaseManager { + Flux> queryDatabases(SqlQuerySpec query); + Mono createDatabase(CosmosDatabaseProperties databaseDefinition); + CosmosDatabase getDatabase(String id); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosPartitionKeyTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosPartitionKeyTests.java new file mode 100644 index 0000000000000..2e862ea61c2b1 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosPartitionKeyTests.java @@ -0,0 +1,271 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpClientConfig; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.rx.TestSuiteBase; +import io.netty.handler.codec.http.HttpMethod; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public final class CosmosPartitionKeyTests extends TestSuiteBase { + + private final static String NON_PARTITIONED_CONTAINER_ID = "NonPartitionContainer" + UUID.randomUUID().toString(); + private final static String NON_PARTITIONED_CONTAINER_DOCUEMNT_ID = "NonPartitionContainer_Document" + UUID.randomUUID().toString(); + + private CosmosClient client; + private CosmosDatabase createdDatabase; + + @Factory(dataProvider = "clientBuilders") + public CosmosPartitionKeyTests(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws URISyntaxException, IOException { + assertThat(this.client).isNull(); + client = clientBuilder().build(); + createdDatabase = getSharedCosmosDatabase(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + assertThat(this.client).isNotNull(); + this.client.close(); + } + + private void createContainerWithoutPk() throws URISyntaxException, IOException { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + HttpClientConfig httpClientConfig = new HttpClientConfig(new Configs()) + .withMaxIdleConnectionTimeoutInMillis(connectionPolicy.idleConnectionTimeoutInMillis()) + .withPoolSize(connectionPolicy.maxPoolSize()) + .withHttpProxy(connectionPolicy.proxy()) + .withRequestTimeoutInMillis(connectionPolicy.requestTimeoutInMillis()); + + HttpClient httpClient = HttpClient.createFixed(httpClientConfig); + + // CREATE a non partitioned collection using the rest API and older version + String resourceId = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.id(); + String path = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.id() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/"; + DocumentCollection collection = new DocumentCollection(); + collection.id(NON_PARTITIONED_CONTAINER_ID); + + HashMap headers = new HashMap(); + headers.put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + headers.put(HttpConstants.HttpHeaders.VERSION, "2018-09-17"); + BaseAuthorizationTokenProvider base = new BaseAuthorizationTokenProvider(TestConfigurations.MASTER_KEY); + String authorization = base.generateKeyAuthorizationSignature(HttpConstants.HttpMethods.POST, resourceId, Paths.COLLECTIONS_PATH_SEGMENT, headers); + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, URLEncoder.encode(authorization, "UTF-8")); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Create, + ResourceType.DocumentCollection, path, collection, headers, new RequestOptions()); + + String[] baseUrlSplit = TestConfigurations.HOST.split(":"); + String resourceUri = baseUrlSplit[0] + ":" + baseUrlSplit[1] + ":" + baseUrlSplit[2].split("/")[ + 0] + "//" + Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.id() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/"; + URI uri = new URI(resourceUri); + + HttpRequest httpRequest = new HttpRequest(HttpMethod.POST, uri, uri.getPort(), new HttpHeaders(headers)); + httpRequest.withBody(request.getContent()); + String body = httpClient.send(httpRequest).block().bodyAsString().block(); + assertThat(body).contains("\"id\":\"" + NON_PARTITIONED_CONTAINER_ID + "\""); + + // CREATE a document in the non partitioned collection using the rest API and older version + resourceId = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.id() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + collection.id(); + path = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.id() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + + "/" + collection.id() + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/"; + Document document = new Document(); + document.id(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID); + + authorization = base.generateKeyAuthorizationSignature(HttpConstants.HttpMethods.POST, resourceId, Paths.DOCUMENTS_PATH_SEGMENT, headers); + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, URLEncoder.encode(authorization, "UTF-8")); + request = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, path, + document, headers, new RequestOptions()); + + resourceUri = baseUrlSplit[0] + ":" + baseUrlSplit[1] + ":" + baseUrlSplit[2].split("/")[0] + "//" + Paths.DATABASES_PATH_SEGMENT + "/" + + createdDatabase.id() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + collection.id() + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/"; + uri = new URI(resourceUri); + + httpRequest = new HttpRequest(HttpMethod.POST, uri, uri.getPort(), new HttpHeaders(headers)); + httpRequest.withBody(request.getContent()); + + body = httpClient.send(httpRequest).block().bodyAsString().block(); + assertThat(body).contains("\"id\":\"" + NON_PARTITIONED_CONTAINER_DOCUEMNT_ID + "\""); + } + + @Test(groups = { "simple" }) + public void testNonPartitionedCollectionOperations() throws Exception { + createContainerWithoutPk(); + CosmosContainer createdContainer = createdDatabase.getContainer(NON_PARTITIONED_CONTAINER_ID); + + Mono readMono = createdContainer.getItem(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID, PartitionKey.None).read(); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID).build(); + validateSuccess(readMono, validator); + + String createdItemId = UUID.randomUUID().toString(); + Mono createMono = createdContainer.createItem(new CosmosItemProperties("{'id':'" + createdItemId + "'}")); + validator = new CosmosResponseValidator.Builder() + .withId(createdItemId).build(); + validateSuccess(createMono, validator); + + readMono = createdContainer.getItem(createdItemId, PartitionKey.None).read(); + validator = new CosmosResponseValidator.Builder() + .withId(createdItemId).build(); + validateSuccess(readMono, validator); + + CosmosItem itemToReplace = createdContainer.getItem(createdItemId, PartitionKey.None).read().block().item(); + CosmosItemProperties itemSettingsToReplace = itemToReplace.read().block().properties(); + String replacedItemId = UUID.randomUUID().toString(); + itemSettingsToReplace.id(replacedItemId); + Mono replaceMono = itemToReplace.replace(itemSettingsToReplace); + validator = new CosmosResponseValidator.Builder() + .withId(replacedItemId).build(); + validateSuccess(replaceMono, validator); + + String upsertedItemId = UUID.randomUUID().toString(); + + Mono upsertMono = createdContainer.upsertItem(new CosmosItemProperties("{'id':'" + upsertedItemId + "'}")); + validator = new CosmosResponseValidator.Builder() + .withId(upsertedItemId).build(); + validateSuccess(upsertMono, validator); + + // one document was created during setup, one with create (which was replaced) and one with upsert + FeedOptions feedOptions = new FeedOptions(); + feedOptions.partitionKey(PartitionKey.None); + ArrayList expectedIds = new ArrayList(); + expectedIds.add(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID); + expectedIds.add(replacedItemId); + expectedIds.add(upsertedItemId); + Flux> queryFlux = createdContainer.queryItems("SELECT * from c", feedOptions); + FeedResponseListValidator queryValidator = new FeedResponseListValidator.Builder() + .totalSize(3) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + queryFlux = createdContainer.readAllItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(3) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + String documentCreatedBySprocId = "testDoc"; + CosmosStoredProcedureProperties sproc = new CosmosStoredProcedureProperties( + "{" + + " 'id': '" +UUID.randomUUID().toString() + "'," + + " 'body':'" + + " function() {" + + " var client = getContext().getCollection();" + + " var doc = client.createDocument(client.getSelfLink(), { \\'id\\': \\'" + documentCreatedBySprocId + "\\'}, {}, function(err, docCreated, options) { " + + " if(err) throw new Error(\\'Error while creating document: \\' + err.message);" + + " else {" + + " getContext().getResponse().setBody(1);" + + " }" + + " });" + + "}'" + + "}"); + CosmosStoredProcedure createdSproc = createdContainer.getScripts().createStoredProcedure(sproc).block().storedProcedure(); + + // Partiton Key value same as what is specified in the stored procedure body + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + int result = Integer.parseInt(createdSproc.execute(null, new CosmosStoredProcedureRequestOptions()).block().responseAsString()); + assertThat(result).isEqualTo(1); + + // 3 previous items + 1 created from the sproc + expectedIds.add(documentCreatedBySprocId); + queryFlux = createdContainer.readAllItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(4) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + Mono deleteMono = createdContainer.getItem(upsertedItemId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(replacedItemId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(documentCreatedBySprocId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + queryFlux = createdContainer.readAllItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(0) + .numberOfPages(1) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT*100) + public void testMultiPartitionCollectionReadDocumentWithNoPk() throws InterruptedException { + String partitionedCollectionId = "PartitionedCollection" + UUID.randomUUID().toString(); + String IdOfDocumentWithNoPk = UUID.randomUUID().toString(); + CosmosContainerProperties containerSettings = new CosmosContainerProperties(partitionedCollectionId, "/mypk"); + CosmosContainer createdContainer = createdDatabase.createContainer(containerSettings).block().container(); + CosmosItemProperties cosmosItemProperties = new CosmosItemProperties(); + cosmosItemProperties.id(IdOfDocumentWithNoPk); + CosmosItem createdItem = createdContainer.createItem(cosmosItemProperties).block().item(); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(PartitionKey.None); + Mono readMono = createdItem.read(options); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(IdOfDocumentWithNoPk).build(); + validateSuccess(readMono, validator); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosResponseValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosResponseValidator.java new file mode 100644 index 0000000000000..798e57c1099b2 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/CosmosResponseValidator.java @@ -0,0 +1,281 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface CosmosResponseValidator { + void validate(T cosmosResponse); + + class Builder { + private List> validators = new ArrayList<>(); + + public CosmosResponseValidator build() { + return new CosmosResponseValidator() { + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void validate(T resourceResponse) { + for (CosmosResponseValidator validator : validators) { + validator.validate(resourceResponse); + } + } + }; + } + + public Builder withId(final String resourceId) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(getResource(resourceResponse)).isNotNull(); + assertThat(getResource(resourceResponse).id()).as("check Resource Id").isEqualTo(resourceId); + } + }); + return this; + } + + private Resource getResource(T resourceResponse) { + if (resourceResponse instanceof CosmosDatabaseResponse) { + return ((CosmosDatabaseResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosContainerResponse) { + return ((CosmosContainerResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosItemResponse) { + return ((CosmosItemResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosStoredProcedureResponse) { + return ((CosmosStoredProcedureResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosTriggerResponse) { + return ((CosmosTriggerResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosUserDefinedFunctionResponse) { + return ((CosmosUserDefinedFunctionResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosUserResponse) { + return ((CosmosUserResponse)resourceResponse).properties(); + } else if (resourceResponse instanceof CosmosPermissionResponse) { + return ((CosmosPermissionResponse) resourceResponse).properties(); + } + return null; + } + + public Builder nullResource() { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(getResource(resourceResponse)).isNull(); + } + }); + return this; + } + + public Builder indexingMode(IndexingMode mode) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + assertThat(resourceResponse.properties()).isNotNull(); + assertThat(resourceResponse.properties().indexingPolicy()).isNotNull(); + assertThat(resourceResponse.properties().indexingPolicy().indexingMode()).isEqualTo(mode); + } + }); + return this; + } + + public Builder withProperty(String propertyName, String value) { + validators.add(new CosmosResponseValidator() { + @Override + public void validate(T cosmosResponse) { + assertThat(getResource(cosmosResponse)).isNotNull(); + assertThat(getResource(cosmosResponse).get(propertyName)).isEqualTo(value); + } + }); + return this; + } + + public Builder withCompositeIndexes(List> compositeIndexesWritten) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + Iterator> compositeIndexesReadIterator = resourceResponse.properties() + .indexingPolicy().compositeIndexes().iterator(); + Iterator> compositeIndexesWrittenIterator = compositeIndexesWritten.iterator(); + + ArrayList readIndexesStrings = new ArrayList(); + ArrayList writtenIndexesStrings = new ArrayList(); + + while (compositeIndexesReadIterator.hasNext() && compositeIndexesWrittenIterator.hasNext()) { + Iterator compositeIndexReadIterator = compositeIndexesReadIterator.next().iterator(); + Iterator compositeIndexWrittenIterator = compositeIndexesWrittenIterator.next().iterator(); + + StringBuilder readIndexesString = new StringBuilder(); + StringBuilder writtenIndexesString = new StringBuilder(); + + while (compositeIndexReadIterator.hasNext() && compositeIndexWrittenIterator.hasNext()) { + CompositePath compositePathRead = compositeIndexReadIterator.next(); + CompositePath compositePathWritten = compositeIndexWrittenIterator.next(); + + readIndexesString.append(compositePathRead.path() + ":" + compositePathRead.order() + ";"); + writtenIndexesString.append(compositePathWritten.path() + ":" + compositePathRead.order() + ";"); + } + + readIndexesStrings.add(readIndexesString.toString()); + writtenIndexesStrings.add(writtenIndexesString.toString()); + } + + assertThat(readIndexesStrings).containsExactlyInAnyOrderElementsOf(writtenIndexesStrings); + } + + }); + return this; + } + + public Builder withSpatialIndexes(Collection spatialIndexes) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + Iterator spatialIndexesReadIterator = resourceResponse.properties() + .indexingPolicy().spatialIndexes().iterator(); + Iterator spatialIndexesWrittenIterator = spatialIndexes.iterator(); + + HashMap> readIndexMap = new HashMap>(); + HashMap> writtenIndexMap = new HashMap>(); + + while (spatialIndexesReadIterator.hasNext() && spatialIndexesWrittenIterator.hasNext()) { + SpatialSpec spatialSpecRead = spatialIndexesReadIterator.next(); + SpatialSpec spatialSpecWritten = spatialIndexesWrittenIterator.next(); + + String readPath = spatialSpecRead.path() + ":"; + String writtenPath = spatialSpecWritten.path() + ":"; + + ArrayList readSpatialTypes = new ArrayList(); + ArrayList writtenSpatialTypes = new ArrayList(); + + Iterator spatialTypesReadIterator = spatialSpecRead.spatialTypes().iterator(); + Iterator spatialTypesWrittenIterator = spatialSpecWritten.spatialTypes().iterator(); + + while (spatialTypesReadIterator.hasNext() && spatialTypesWrittenIterator.hasNext()) { + readSpatialTypes.add(spatialTypesReadIterator.next()); + writtenSpatialTypes.add(spatialTypesWrittenIterator.next()); + } + + readIndexMap.put(readPath, readSpatialTypes); + writtenIndexMap.put(writtenPath, writtenSpatialTypes); + } + + for (Entry> entry : readIndexMap.entrySet()) { + assertThat(entry.getValue()) + .containsExactlyInAnyOrderElementsOf(writtenIndexMap.get(entry.getKey())); + } + } + }); + return this; + } + + public Builder withStoredProcedureBody(String storedProcedureBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosStoredProcedureResponse resourceResponse) { + assertThat(resourceResponse.properties().body()).isEqualTo(storedProcedureBody); + } + }); + return this; + } + + public Builder notNullEtag() { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(resourceResponse.resourceSettings()).isNotNull(); + assertThat(resourceResponse.resourceSettings().etag()).isNotNull(); + } + }); + return this; + } + + public Builder withTriggerBody(String functionBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosTriggerResponse resourceResponse) { + assertThat(resourceResponse.properties().body()).isEqualTo(functionBody); + } + }); + return this; + } + + public Builder withTriggerInternals(TriggerType type, TriggerOperation op) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosTriggerResponse resourceResponse) { + assertThat(resourceResponse.properties().triggerType()).isEqualTo(type); + assertThat(resourceResponse.properties().triggerOperation()).isEqualTo(op); + } + }); + return this; + } + + public Builder withUserDefinedFunctionBody(String functionBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosUserDefinedFunctionResponse resourceResponse) { + assertThat(resourceResponse.properties().body()).isEqualTo(functionBody); + } + }); + return this; + } + + public Builder withPermissionMode(PermissionMode mode) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosPermissionResponse resourceResponse) { + assertThat(resourceResponse.properties().permissionMode()).isEqualTo(mode); + } + }); + return this; + + } + + public Builder withPermissionResourceLink(String resourceLink) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosPermissionResponse resourceResponse) { + assertThat(resourceResponse.properties().resourceLink()).isEqualTo(resourceLink); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentClientTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentClientTest.java new file mode 100644 index 0000000000000..deb7b0166ac96 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentClientTest.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.google.common.base.Strings; +import org.testng.ITest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; + +import java.lang.reflect.Method; + +public abstract class DocumentClientTest implements ITest { + + private final AsyncDocumentClient.Builder clientBuilder; + private String testName; + + public DocumentClientTest() { + this(new AsyncDocumentClient.Builder()); + } + + public DocumentClientTest(AsyncDocumentClient.Builder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + public final AsyncDocumentClient.Builder clientBuilder() { + return this.clientBuilder; + } + + @Override + public final String getTestName() { + return this.testName; + } + + @BeforeMethod(alwaysRun = true) + public final void setTestName(Method method) { + String testClassAndMethodName = Strings.lenientFormat("%s::%s", + method.getDeclaringClass().getSimpleName(), + method.getName()); + + if (this.clientBuilder.getConnectionPolicy() != null && this.clientBuilder.getConfigs() != null) { + String connectionMode = this.clientBuilder.getConnectionPolicy().connectionMode() == ConnectionMode.DIRECT + ? "Direct " + this.clientBuilder.getConfigs().getProtocol() + : "Gateway"; + + this.testName = Strings.lenientFormat("%s[%s with %s consistency]", + testClassAndMethodName, + connectionMode, + clientBuilder.getDesiredConsistencyLevel()); + } else { + this.testName = testClassAndMethodName; + } + } + + @AfterMethod(alwaysRun = true) + public final void unsetTestName() { + this.testName = null; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentCollectionTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentCollectionTests.java new file mode 100644 index 0000000000000..da0998b22235d --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentCollectionTests.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.DocumentCollection; +import com.google.common.collect.ImmutableList; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentCollectionTests { + + @Test(groups = { "unit" }) + public void getPartitionKey() { + DocumentCollection collection = new DocumentCollection(); + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.paths(ImmutableList.of("/mypk")); + collection.setPartitionKey(partitionKeyDefinition); + assertThat(collection.getPartitionKey()).isEqualTo(partitionKeyDefinition); + } + + @Test(groups = { "unit" }) + public void getPartitionKey_serializeAndDeserialize() { + DocumentCollection collection = new DocumentCollection(); + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.paths(ImmutableList.of("/mypk")); + partitionKeyDefinition.version(PartitionKeyDefinitionVersion.V2); + collection.setPartitionKey(partitionKeyDefinition); + + DocumentCollection parsedColl = new DocumentCollection(collection.toJson()); + assertThat(parsedColl.getPartitionKey().kind().toString()).isEqualTo(partitionKeyDefinition.kind().toString()); + assertThat(parsedColl.getPartitionKey().paths()).isEqualTo(partitionKeyDefinition.paths()); + assertThat(parsedColl.getPartitionKey().version()).isEqualTo(partitionKeyDefinition.version()); + } + + @Test(groups = { "unit"}) + public void indexingPolicy_serializeAndDeserialize() { + SpatialSpec spatialSpec = new SpatialSpec(); + List spatialSpecList = new ArrayList<>(); + spatialSpecList.add(spatialSpec); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + indexingPolicy.spatialIndexes(spatialSpecList); + DocumentCollection documentCollection = new DocumentCollection(); + documentCollection.setIndexingPolicy(indexingPolicy); + String json = documentCollection.toJson(); + + DocumentCollection documentCollectionPostSerialization = new DocumentCollection(json); + IndexingPolicy indexingPolicyPostSerialization = documentCollectionPostSerialization.getIndexingPolicy(); + assertThat(indexingPolicyPostSerialization).isNotNull(); + List spatialSpecListPostSerialization = indexingPolicyPostSerialization.spatialIndexes(); + assertThat(spatialSpecListPostSerialization).isNotNull(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentTests.java new file mode 100644 index 0000000000000..e336876d67fd9 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/DocumentTests.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Document; +import org.testng.annotations.Test; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; + +import static com.azure.data.cosmos.BridgeInternal.setTimestamp; +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentTests { + + @Test(groups = { "unit" }) + public void timestamp() { + Document d = new Document(); + OffsetDateTime time = OffsetDateTime.of(2019, 8, 6, 12, 53, 29, 0, ZoneOffset.UTC); + setTimestamp(d, time); + assertThat(d.timestamp()).isEqualTo(time); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/GatewayTestUtils.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/GatewayTestUtils.java new file mode 100644 index 0000000000000..af6900d868dc7 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/GatewayTestUtils.java @@ -0,0 +1,36 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.PartitionKeyRange; + +import java.util.List; + +public class GatewayTestUtils { + + public static PartitionKeyRange setParent(PartitionKeyRange pkr, List parents) { + pkr.setParents(parents); + return pkr; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/IncludedPathTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/IncludedPathTest.java new file mode 100644 index 0000000000000..70ab7d2fe9bed --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/IncludedPathTest.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import org.testng.annotations.Test; + +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; + +public class IncludedPathTest { + + @Test(groups = {"unit"}) + public void deserialize() { + String json = "{" + + " 'path': '\\/*'," + + " 'indexes': [" + + " {" + + " 'kind': 'Range'," + + " 'dataType': 'String'," + + " 'precision': -1" + + " }," + + " {" + + " 'kind': 'Range'," + + " 'dataType': 'Number'," + + " 'precision': -1" + + " }" + + " ]" + + "}"; + IncludedPath path = new IncludedPath(json); + Collection indexes = path.indexes(); + assertThat(indexes).hasSize(2); + assertThat(indexes).usingFieldByFieldElementComparator().contains(Index.Range(DataType.STRING, -1)); + assertThat(indexes).usingFieldByFieldElementComparator().contains(Index.Range(DataType.NUMBER, -1)); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/JsonSerializableTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/JsonSerializableTests.java new file mode 100644 index 0000000000000..ed390db320b51 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/JsonSerializableTests.java @@ -0,0 +1,134 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Document; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonParseException; +import org.testng.annotations.Test; + +import java.io.Serializable; + +import static com.azure.data.cosmos.BridgeInternal.setProperty; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.fail; + +public class JsonSerializableTests { + + public static class Pojo implements Serializable { + int a; + int b; + + public Pojo(int a, int b) { + this.a = a; + this.b = b; + } + + @JsonCreator + public Pojo(@JsonProperty("a") String a, @JsonProperty("b") String b) { + this.a = Integer.parseInt(a); + this.b = Integer.parseInt(b); + } + + public int getA() { + return a; + } + + public int getB() { + return b; + } + + public void setA(int a) { + this.a = a; + } + + public void setB(int b) { + this.b = b; + } + + } + + public enum enums { + first, second, third + } + + @Test(groups = { "unit" }) + public void getObjectAndCastToClass() { + Document document = new Document(); + // numeric values + setProperty(document, "intValue", Integer.MAX_VALUE); + setProperty(document, "doubleValue", Double.MAX_VALUE); + setProperty(document, "longValue", Long.MAX_VALUE); + + assertThat(document.getObject("intValue", Integer.class).intValue()).isEqualTo(Integer.MAX_VALUE); + assertThat(document.getObject("doubleValue", Double.class).doubleValue()).isEqualTo(Double.MAX_VALUE); + assertThat(document.getObject("longValue", Long.class).longValue()).isEqualTo(Long.MAX_VALUE); + + // string + setProperty(document, "stringValue", "stringField"); + assertThat(document.getObject("stringValue", String.class)).isEqualTo("stringField"); + + // boolean + setProperty(document, "boolValue", true); + assertThat(document.getObject("boolValue", Boolean.class)).isEqualTo(true); + + // enum + setProperty(document, "enumValue", "third"); + assertThat(document.getObject("enumValue", enums.class)).isEqualTo(enums.third); + + // Pojo + Pojo pojo = new Pojo(1, 2); + setProperty(document, "pojoValue", pojo); + Pojo readPojo = document.getObject("pojoValue", Pojo.class); + assertThat(readPojo.getA()).isEqualTo(pojo.getA()); + assertThat(readPojo.getB()).isEqualTo(pojo.getB()); + + // JsonSerializable + Document innerDocument = new Document(); + innerDocument.id("innerDocument"); + setProperty(document, "innerDocument", innerDocument); + Document readInnerDocument = document.getObject("innerDocument", Document.class); + assertThat(readInnerDocument.id()).isEqualTo(innerDocument.id()); + } + + @Test(groups = { "unit" }) + public void objectMapperInvalidJsonNoQuotesForFieldAndValue() { + // INVALID Json - field and value must be quoted + try { + new Document("{ field: value }"); + fail("failure expected"); + } catch (Exception e) { + assertThat(e.getCause() instanceof JsonParseException).isTrue(); + } + } + + @Test(groups = { "unit" }) + public void objectMapperInvalidJsonNoQuotesForField() { + // INVALID Json - field must be quoted + try { + new Document("{ field: 'value' }"); + fail("failure expected"); + } catch (Exception e) { + assertThat(e.getCause() instanceof JsonParseException).isTrue(); + } + } + + @Test(groups = { "unit" }) + public void objectMapperInvalidJsonNoDuplicatesAllowed() { + // INVALID Json - duplicates must not exist in Json string + try { + new Document("{ 'field': 'value1', 'field': 'value2' }"); + fail("failure expected"); + } catch (Exception e) { + assertThat(e.getCause() instanceof JsonParseException).isTrue(); + } + } + + @Test(groups = { "unit" }) + public void objectMapperValidJsonWithSingleQuotesAndTrailingComma() { + Document document = null; + + // Valid Json - Single quotes and trailing commas allowed in Json string + document = new Document("{ 'field1': 'value1', 'field2': 'value2', }"); + assertThat(document.toJson().equals("{\"field1\":\"value1\",\"field2\":\"value2\"}")).isEqualTo(true); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PartitionKeyHashingTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PartitionKeyHashingTests.java new file mode 100644 index 0000000000000..36b117ce4d249 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PartitionKeyHashingTests.java @@ -0,0 +1,94 @@ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.fasterxml.jackson.databind.node.NullNode; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class PartitionKeyHashingTests { + + @Test(groups = "unit") + public void effectivePartitionKeyHashV1() { + HashMap keyToEffectivePartitionKeyString = new HashMap() {{ + put("", "05C1CF33970FF80800"); + put("partitionKey", "05C1E1B3D9CD2608716273756A756A706F4C667A00"); + put(new String(new char[1024]).replace("\0", "a"), "05C1EB5921F706086262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626262626200"); + put(null, "05C1ED45D7475601"); + put(NullNode.getInstance(), "05C1ED45D7475601"); + put(Undefined.Value(), "05C1D529E345DC00"); + put(true, "05C1D7C5A903D803"); + put(false, "05C1DB857D857C02"); + put(Byte.MIN_VALUE, "05C1D73349F54C053FA0"); + put(Byte.MAX_VALUE, "05C1DD539DDFCC05C05FE0"); + put(Long.MIN_VALUE, "05C1DB35F33D1C053C20"); + put(Long.MAX_VALUE, "05C1B799AB2DD005C3E0"); + put(Integer.MIN_VALUE, "05C1DFBF252BCC053E20"); + put(Integer.MAX_VALUE, "05C1E1F503DFB205C1DFFFFFFFFC"); + put(Double.MIN_VALUE, "05C1E5C91F4D3005800101010101010102"); + put(Double.MAX_VALUE, "05C1CBE367C53005FFEFFFFFFFFFFFFFFE"); + }}; + + for (Map.Entry entry : keyToEffectivePartitionKeyString.entrySet()) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + partitionKeyDef.kind(PartitionKind.HASH); + partitionKeyDef.paths(Arrays.asList(new String[]{"\\id"})); + String actualEffectiveKeyString = PartitionKeyInternalHelper.getEffectivePartitionKeyString(new PartitionKey(entry.getKey()).getInternalPartitionKey(),partitionKeyDef, true); + assertThat(entry.getValue()).isEqualTo(actualEffectiveKeyString); + } + } + + @Test(groups = "unit") + public void effectivePartitionKeyHashV2() { + HashMap keyToEffectivePartitionKeyString = new HashMap() {{ + put("", "32E9366E637A71B4E710384B2F4970A0"); + put("partitionKey", "013AEFCF77FA271571CF665A58C933F1"); + put(new String(new char[1024]).replace("\0", "a"), "332BDF5512AE49615F32C7D98C2DB86C"); + put(null, "378867E4430E67857ACE5C908374FE16"); + put(NullNode.getInstance(), "378867E4430E67857ACE5C908374FE16"); + put(Undefined.Value(), "11622DAA78F835834610ABE56EFF5CB5"); + put(true, "0E711127C5B5A8E4726AC6DD306A3E59"); + put(false, "2FE1BE91E90A3439635E0E9E37361EF2"); + put(Byte.MIN_VALUE, "01DAEDABF913540367FE219B2AD06148"); + put(Byte.MAX_VALUE, "0C507ACAC853ECA7977BF4CEFB562A25"); + put(Long.MIN_VALUE, "23D5C6395512BDFEAFADAD15328AD2BB"); + put(Long.MAX_VALUE, "2EDB959178DFCCA18983F89384D1629B"); + put(Integer.MIN_VALUE, "0B1660D5233C3171725B30D4A5F4CC1F"); + put(Integer.MAX_VALUE, "2D9349D64712AEB5EB1406E2F0BE2725"); + put(Double.MIN_VALUE, "0E6CBA63A280927DE485DEF865800139"); + put(Double.MAX_VALUE, "31424D996457102634591FF245DBCC4D"); + }}; + + for (Map.Entry entry : keyToEffectivePartitionKeyString.entrySet()) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + partitionKeyDef.kind(PartitionKind.HASH); + partitionKeyDef.version(PartitionKeyDefinitionVersion.V2); + partitionKeyDef.paths(Arrays.asList(new String[]{"\\id"})); + String actualEffectiveKeyString = PartitionKeyInternalHelper.getEffectivePartitionKeyString(new PartitionKey(entry.getKey()).getInternalPartitionKey(),partitionKeyDef, true); + assertThat(entry.getValue()).isEqualTo(actualEffectiveKeyString); + } + } + + @Test(groups = "unit") + public void hashV2PartitionKeyDeserialization() { + String partitionKeyDefinitionStr = "{\"paths\":[\"/pk\"],\"kind\":\"Hash\",\"version\":2}"; + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(partitionKeyDefinitionStr); + assertThat(partitionKeyDef.version()).isEqualTo(PartitionKeyDefinitionVersion.V2); + assertThat(partitionKeyDef.kind()).isEqualTo(PartitionKind.HASH); + assertThat(partitionKeyDef.paths().toArray()[0]).isEqualTo("/pk"); + } + + @Test(groups = "unit") + public void hashV1PartitionKeyDeserialization() { + String partitionKeyDefinitionStr = "{\"paths\":[\"/pk\"],\"kind\":\"Hash\"}"; + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(partitionKeyDefinitionStr); + assertThat(partitionKeyDef.version()).isNull(); + assertThat(partitionKeyDef.kind()).isEqualTo(PartitionKind.HASH); + assertThat(partitionKeyDef.paths().toArray()[0]).isEqualTo("/pk"); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PermissionTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PermissionTest.java new file mode 100644 index 0000000000000..50eec6fa13355 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/PermissionTest.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.Permission; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PermissionTest { + + @Test(groups = {"unit"}) + public void deserialize() { + String json = "{" + + " 'id': 'a98eb026-b66b-4cec-8fb9-9b0e10ddab76'," + + " 'permissionMode': 'read'," + + " 'resource': 'dbs/AQAAAA==/colls/AQAAAJ0fgTc='," + + " 'resourcePartitionKey': ['/id']" + + "}"; + Permission p = new Permission(json); + assertThat(p.getResourcePartitionKey()).isEqualToComparingFieldByField(new PartitionKey("/id")); + assertThat(p.getPermissionMode()).isEqualTo(PermissionMode.READ); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ResourceIdTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ResourceIdTests.java new file mode 100644 index 0000000000000..c196baf42c6fd --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/ResourceIdTests.java @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos; + +import com.azure.data.cosmos.internal.ResourceId; +import org.apache.commons.lang3.tuple.Pair; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ResourceIdTests { + + @Test(groups = { "unit" }) + public void resourceIdTryParsing() { + HashMap cases = new HashMap<>(); + cases.put("testDb", false); + cases.put("db", false); + cases.put("cosmosdb", false); + cases.put("asosfactor", false); + + cases.put("f", false); + cases.put("fo", false); + cases.put("foo", false); + cases.put("foob", true); + cases.put("fooba", false); + cases.put("foobar", false); + cases.put("Zm8=", false); + cases.put("Zm9v", true); + cases.put("Zm9vYg==", true); + cases.put("Zm9vYmE=", false); + cases.put("Zm9vYmFy", false); + + // collection rid + cases.put("1-MxAPlgMgA=", true); + cases.put("nJRwAA==", true); + cases.put("MaZyAA==", true); + cases.put("-qpmAA==", true); + cases.put("wsIRAA==", true); + cases.put("GJwnAA==", true); + + // document rid + cases.put("ClZUAPp9+A0=", true); + + // offer rid + cases.put("-d8Hx", false); + + for (Map.Entry testCase : cases.entrySet()) { + Pair resourcePair = ResourceId.tryParse(testCase.getKey()); + assertThat( resourcePair.getKey()).as(String.format("ResourceId.tryParse failed for '%s'", testCase.getKey())).isEqualTo(testCase.getValue()); + } + } + + private static int randomNextIntForTest(Random rnd, Boolean positive) { + return rnd.nextInt(Integer.MAX_VALUE / 2) + (positive ? Integer.MAX_VALUE / 2 : - Integer.MAX_VALUE / 2); + } + + @Test(groups = { "unit" }) + public void resourceIdParsingRoundTrip() { + Random rnd = new Random(System.currentTimeMillis()); + + ResourceId dbRid = ResourceId.newDatabaseId(randomNextIntForTest(rnd, true)); + ResourceId parsedDbRid = ResourceId.parse(dbRid.toString()); + assertThat(parsedDbRid.getDatabase()).isEqualTo(dbRid.getDatabase()); + + ResourceId collRid = ResourceId.newDocumentCollectionId(dbRid.toString(), randomNextIntForTest(rnd, false)); + ResourceId parsedCollRid = ResourceId.parse(collRid.toString()); + assertThat(parsedCollRid.getDatabase()).isEqualTo(collRid.getDatabase()); + assertThat(parsedCollRid.getDocumentCollection()).isEqualTo(collRid.getDocumentCollection()); + + ResourceId userRid = ResourceId.newUserId(dbRid.toString(), randomNextIntForTest(rnd, true)); + ResourceId parsedUserRid = ResourceId.parse(userRid.toString()); + assertThat(parsedUserRid.getDatabase()).isEqualTo(userRid.getDatabase()); + assertThat(parsedUserRid.getUser()).isEqualTo(userRid.getUser()); + + ResourceId permissionRid = ResourceId.newPermissionId(userRid.toString(), randomNextIntForTest(rnd, false)); + ResourceId parsedPermissionRid = ResourceId.parse(permissionRid.toString()); + assertThat(parsedPermissionRid.getDatabase()).isEqualTo(permissionRid.getDatabase()); + assertThat(parsedPermissionRid.getUser()).isEqualTo(permissionRid.getUser()); + assertThat(parsedPermissionRid.getPermission()).isEqualTo(permissionRid.getPermission()); + + ResourceId attachmentRid = ResourceId.newAttachmentId("wsIRALoBhyQ9AAAAAAAACA==", randomNextIntForTest(rnd, true)); + ResourceId parsedAttachmentRid = ResourceId.parse(attachmentRid.toString()); + assertThat(parsedAttachmentRid.getDatabase()).isEqualTo(attachmentRid.getDatabase()); + assertThat(parsedAttachmentRid.getDocumentCollection()).isEqualTo(attachmentRid.getDocumentCollection()); + assertThat(parsedAttachmentRid.getDocument()).isEqualTo(attachmentRid.getDocument()); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ClientRetryPolicyTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ClientRetryPolicyTest.java new file mode 100644 index 0000000000000..fbbf29a9389e8 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ClientRetryPolicyTest.java @@ -0,0 +1,139 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.RetryOptions; +import io.netty.handler.timeout.ReadTimeoutException; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + +public class ClientRetryPolicyTest { + private final static int TIMEOUT = 10000; + + @Test(groups = "unit") + public void networkFailureOnRead() throws Exception { + RetryOptions retryOptions = new RetryOptions(); + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(new URL("http://localhost")).when(endpointManager).resolveServiceEndpoint(Mockito.any(RxDocumentServiceRequest.class)); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + ClientRetryPolicy clientRetryPolicy = new ClientRetryPolicy(endpointManager, true, retryOptions); + + Exception exception = ReadTimeoutException.INSTANCE; + + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + clientRetryPolicy.onBeforeSendRequest(dsr); + + for (int i = 0; i < 10; i++) { + Mono shouldRetry = clientRetryPolicy.shouldRetry(exception); + + validateSuccess(shouldRetry, ShouldRetryValidator.builder() + .nullException() + .shouldRetry(true) + .backOfTime(Duration.ofMillis(ClientRetryPolicy.RetryIntervalInMS)) + .build()); + + Mockito.verify(endpointManager, Mockito.times(i + 1)).markEndpointUnavailableForRead(Mockito.any()); + Mockito.verify(endpointManager, Mockito.times(0)).markEndpointUnavailableForWrite(Mockito.any()); + } + } + + @Test(groups = "unit") + public void networkFailureOnWrite() throws Exception { + RetryOptions retryOptions = new RetryOptions(); + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(new URL("http://localhost")).when(endpointManager).resolveServiceEndpoint(Mockito.any(RxDocumentServiceRequest.class)); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + ClientRetryPolicy clientRetryPolicy = new ClientRetryPolicy(endpointManager, true, retryOptions); + + Exception exception = ReadTimeoutException.INSTANCE; + + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + clientRetryPolicy.onBeforeSendRequest(dsr); + for (int i = 0; i < 10; i++) { + Mono shouldRetry = clientRetryPolicy.shouldRetry(exception); + validateSuccess(shouldRetry, ShouldRetryValidator.builder() + .nullException() + .shouldRetry(true) + .backOfTime(i > 0 ? Duration.ofMillis(ClientRetryPolicy.RetryIntervalInMS) : Duration.ZERO) + .build()); + + Mockito.verify(endpointManager, Mockito.times(0)).markEndpointUnavailableForRead(Mockito.any()); + Mockito.verify(endpointManager, Mockito.times(i + 1)).markEndpointUnavailableForWrite(Mockito.any()); + } + } + + @Test(groups = "unit") + public void onBeforeSendRequestNotInvoked() { + RetryOptions retryOptions = new RetryOptions(); + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + ClientRetryPolicy clientRetryPolicy = new ClientRetryPolicy(endpointManager, true, retryOptions); + + Exception exception = ReadTimeoutException.INSTANCE; + + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + Mono shouldRetry = clientRetryPolicy.shouldRetry(exception); + validateSuccess(shouldRetry, ShouldRetryValidator.builder() + .withException(exception) + .shouldRetry(false) + .build()); + + Mockito.verifyZeroInteractions(endpointManager); + } + + public static void validateSuccess(Mono single, + ShouldRetryValidator validator) { + + validateSuccess(single, validator, TIMEOUT); + } + + public static void validateSuccess(Mono single, + ShouldRetryValidator validator, + long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.flux().subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertComplete(); + testSubscriber.assertNoErrors(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsBuilder.java new file mode 100644 index 0000000000000..f2eba61d20dda --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsBuilder.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.mockito.Mockito; + +/** + * This can be used for testing. + */ +public class ConfigsBuilder { + private Configs configs = Mockito.spy(new Configs()); + + public static ConfigsBuilder instance() { + return new ConfigsBuilder(); + } + + public ConfigsBuilder withProtocol(Protocol protocol) { + Mockito.doReturn(protocol).when(configs).getProtocol(); + return this; + } + + public Configs build() { + return configs; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsTests.java new file mode 100644 index 0000000000000..2e7d95c474d87 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConfigsTests.java @@ -0,0 +1,56 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConfigsTests { + + @Test(groups = { "unit" }) + public void maxHttpHeaderSize() { + Configs config = new Configs(); + assertThat(config.getMaxHttpHeaderSize()).isEqualTo(32 * 1024); + } + + @Test(groups = { "unit" }) + public void maxHttpBodyLength() { + Configs config = new Configs(); + assertThat(config.getMaxHttpBodyLength()).isEqualTo(6 * 1024 * 1024); + } + + @Test(groups = { "unit" }) + public void getProtocol() { + Configs config = new Configs(); + assertThat(config.getProtocol()).isEqualTo(Protocol.valueOf(System.getProperty("cosmos.directModeProtocol", "TCP").toUpperCase())); + } + + @Test(groups = { "unit" }) + public void getDirectHttpsMaxConnectionLimit() { + Configs config = new Configs(); + assertThat(config.getDirectHttpsMaxConnectionLimit()).isEqualTo(Runtime.getRuntime().availableProcessors() * 500); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests1.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests1.java new file mode 100644 index 0000000000000..2c2487447be0a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests1.java @@ -0,0 +1,297 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.PartitionKind; +import org.testng.SkipException; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConsistencyTests1 extends ConsistencyTestsBase { + + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateStrongConsistencyOnSyncReplication() throws Exception { + if (!TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString())) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.STRONG).build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.STRONG).build(); + User userDefinition = getUserDefinition(); + userDefinition.id(userDefinition.id() + "validateStrongConsistencyOnSyncReplication"); + User user = safeCreateUser(this.initClient, createdDatabase.id(), userDefinition); + validateStrongConsistency(user); + } + + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateConsistentLSNForDirectTCPClient() { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + validateConsistentLSN(); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateConsistentLSNForDirectHttpsClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + validateConsistentLSN(); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateConsistentLSNAndQuorumAckedLSNForDirectTCPClient() { + //TODO Need to test with TCP protocol + //https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + validateConsistentLSNAndQuorumAckedLSN(); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateStrongDynamicQuorum() { + if (!TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString())) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + validateReadQuorum(ConsistencyLevel.STRONG, ResourceType.Document, false); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateBoundedStalenessDynamicQuorumSyncReplication() { + if (!(TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString()) || TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.BOUNDED_STALENESS.toString()))) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + validateReadQuorum(ConsistencyLevel.BOUNDED_STALENESS, ResourceType.Document, true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateConsistentLSNAndQuorumAckedLSNForDirectHttpsClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .build(); + validateConsistentLSNAndQuorumAckedLSN(); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateStrongConsistencyOnAsyncReplicationGW() throws InterruptedException { + validateStrongConsistencyOnAsyncReplication(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateStrongConsistencyOnAsyncReplicationDirect() throws InterruptedException { + validateStrongConsistencyOnAsyncReplication(false); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionContainerAfterCollectionCreateReplace() { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //validateSessionContainerAfterCollectionCreateReplace(false, Protocol.TCP); + validateSessionContainerAfterCollectionCreateReplace(false); + validateSessionContainerAfterCollectionCreateReplace(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateConsistentPrefixOnSyncReplication() throws InterruptedException { + if (!(TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString()) || TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.BOUNDED_STALENESS.toString()))) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.BOUNDED_STALENESS).build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.BOUNDED_STALENESS).build(); + User user = safeCreateUser(this.initClient, createdDatabase.id(), getUserDefinition()); + boolean readLagging = validateConsistentPrefix(user); + assertThat(readLagging).isFalse(); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateConsistentPrefixOnAsyncReplication() throws InterruptedException { + if (!(TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString()) || TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.BOUNDED_STALENESS.toString()))) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.BOUNDED_STALENESS) + .build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.BOUNDED_STALENESS) + .build(); + Document documentDefinition = getDocumentDefinition(); + Document document = createDocument(this.initClient, createdDatabase.id(), createdCollection.id(), documentDefinition); + boolean readLagging = validateConsistentPrefix(document); + //assertThat(readLagging).isTrue(); //Will fail if batch repl is turned off + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateConsistentPrefixWithReplicaRestartWithPause() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateConsistentPrefixWithReplicaRestart() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSubstatusCodeOnNotFoundExceptionInSessionReadAsync() { + validateSubstatusCodeOnNotFoundExceptionInSessionReadAsync(false); + validateSubstatusCodeOnNotFoundExceptionInSessionReadAsync(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateBarrierStrongConsistencyForMasterResources() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + private void validateSubstatusCodeOnNotFoundExceptionInSessionReadAsync(boolean useGateway) { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + AsyncDocumentClient client = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + DocumentCollection documentCollection = new DocumentCollection(); + documentCollection.id(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.kind(PartitionKind.HASH); + ArrayList paths = new ArrayList(); + paths.add("/id"); + partitionKeyDefinition.paths(paths); + documentCollection.setPartitionKey(partitionKeyDefinition); + + DocumentCollection collection = client.createCollection(createdDatabase.selfLink(), documentCollection + , null).blockFirst().getResource(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey("1")); + + Document documentDefinition = new Document(); + documentDefinition.id("1"); + Document document = client.createDocument(collection.selfLink(), documentDefinition, requestOptions, false).blockFirst().getResource(); + + Flux> deleteObservable = client.deleteDocument(document.selfLink(), requestOptions); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + Flux> readObservable = client.readDocument(document.selfLink(), requestOptions); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().unknownSubStatusCode().build(); + validateFailure(readObservable, notFoundValidator); + + } finally { + safeClose(client); + } + } + + private static User getUserDefinition() { + User user = new User(); + user.id(USER_NAME); + return user; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests2.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests2.java new file mode 100644 index 0000000000000..9a58d4b056795 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTests2.java @@ -0,0 +1,298 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import org.apache.commons.lang3.Range; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConsistencyTests2 extends ConsistencyTestsBase { + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateReadSessionOnAsyncReplication() throws InterruptedException { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + + Document document = this.initClient.createDocument(createdCollection.selfLink(), getDocumentDefinition(), + null, false).blockFirst().getResource(); + Thread.sleep(5000);//WaitForServerReplication + boolean readLagging = this.validateReadSession(document); + //assertThat(readLagging).isTrue(); //Will fail if batch repl is turned off + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateWriteSessionOnAsyncReplication() throws InterruptedException { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + + Document document = this.initClient.createDocument(createdCollection.selfLink(), getDocumentDefinition(), + null, false).blockFirst().getResource(); + Thread.sleep(5000);//WaitForServerReplication + boolean readLagging = this.validateWriteSession(document); + //assertThat(readLagging).isTrue(); //Will fail if batch repl is turned off + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateEventualConsistencyOnAsyncReplicationDirect() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateEventualConsistencyOnAsyncReplicationGateway() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionContainerAfterCollectionDeletion() throws Exception { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + // Verify the collection deletion will trigger the session token clean up (even for different client) + //this.ValidateSessionContainerAfterCollectionDeletion(true, Protocol.TCP); + this.validateSessionContainerAfterCollectionDeletion(true); + this.validateSessionContainerAfterCollectionDeletion(false); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT, enabled = false) + public void validateReadDistributionForSessionReads() { + // .NET uses lock method which is eventfully using LastReadAddress only for the test case to pass, we are not implementing this in java + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenWithPreConditionFailure() throws Exception { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenWithPreConditionFailure(false, Protocol.TCP); + this.validateSessionTokenWithPreConditionFailure(false); + this.validateSessionTokenWithPreConditionFailure(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenWithDocumentNotFound() throws Exception { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenWithDocumentNotFoundException(false, Protocol.TCP); + this.validateSessionTokenWithDocumentNotFoundException(false); + this.validateSessionTokenWithDocumentNotFoundException(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenWithExpectedException() throws Exception { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenWithExpectedException(false, Protocol.TCP); + this.validateSessionTokenWithExpectedException(false); + this.validateSessionTokenWithExpectedException(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenWithConflictException() { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenWithConflictException(false, Protocol.TCP); + this.validateSessionTokenWithConflictException(false); + this.validateSessionTokenWithConflictException(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenMultiPartitionCollection() throws Exception { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenMultiPartitionCollection(false, Protocol.TCP); + this.validateSessionTokenMultiPartitionCollection(false); + this.validateSessionTokenMultiPartitionCollection(true); + } + + @Test(groups = {"direct"}, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenFromCollectionReplaceIsServerToken() { + //TODO Need to test with TCP protocol + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355057 + //this.validateSessionTokenFromCollectionReplaceIsServerToken(false, Protocol.TCP); + this.validateSessionTokenFromCollectionReplaceIsServerToken(false); + this.validateSessionTokenFromCollectionReplaceIsServerToken(true); + } + + //TODO ReadFeed is broken, will enable the test case once it get fixed + //https://msdata.visualstudio.com/CosmosDB/_workitems/edit/358715 + @Test(groups = {"direct"}, enabled = false, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateNoChargeOnFailedSessionRead() throws Exception { + // DIRECT clients for read and write operations + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + // Client locked to replica for pause/resume + RxDocumentClientImpl readSecondaryClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + // CREATE collection + DocumentCollection parentResource = writeClient.createCollection(createdDatabase.selfLink(), + getCollectionDefinition(), null).blockFirst().getResource(); + + // Document to lock pause/resume clients + Document documentDefinition = getDocumentDefinition(); + documentDefinition.id("test" + documentDefinition.id()); + ResourceResponse childResource = writeClient.createDocument(parentResource.selfLink(), documentDefinition, null, true).blockFirst(); + logger.info("Created {} child resource", childResource.getResource().resourceId()); + + String token = childResource.getSessionToken().split(":")[0] + ":" + this.createSessionToken(SessionTokenHelper.parse(childResource.getSessionToken()), 100000000).convertToString(); + + FeedOptions feedOptions = new FeedOptions(); + feedOptions.partitionKey(new PartitionKey(PartitionKeyInternal.Empty.toJson())); + feedOptions.sessionToken(token); + FailureValidator validator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.NOTFOUND).subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); + Flux> feedObservable = readSecondaryClient.readDocuments(parentResource.selfLink(), feedOptions); + validateQueryFailure(feedObservable, validator); + } finally { + safeClose(writeClient); + safeClose(readSecondaryClient); + } + } + + @Test(groups = {"direct"}, enabled = false, timeOut = CONSISTENCY_TEST_TIMEOUT) + public void validateStrongReadOnOldDocument() { + //TODO this need to complete once we implement emulator container in java, and the we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + // TODO: DANOBLE: Investigate DIRECT TCP performance issue + // Note that we need multiple CONSISTENCY_TEST_TIMEOUT + // SEE: https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028 + + @Test(groups = {"direct"}, timeOut = 4 * CONSISTENCY_TEST_TIMEOUT) + public void validateSessionTokenAsync() { + // Validate that document query never fails + // with NotFoundException + List documents = new ArrayList<>(); + for (int i = 0; i < 1000; i++) { + Document documentDefinition = getDocumentDefinition(); + BridgeInternal.setProperty(documentDefinition, UUID.randomUUID().toString(), UUID.randomUUID().toString()); + documents.add(documentDefinition); + } + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + RxDocumentClientImpl client = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + + try { + Document lastDocument = client.createDocument(createdCollection.selfLink(), getDocumentDefinition(), + null, true) + .blockFirst() + .getResource(); + + Mono task1 = ParallelAsync.forEachAsync(Range.between(0, 1000), 5, index -> client.createDocument(createdCollection.selfLink(), documents.get(index % documents.size()), + null, true) + .blockFirst()); + + Mono task2 = ParallelAsync.forEachAsync(Range.between(0, 1000), 5, index -> { + try { + FeedOptions feedOptions = new FeedOptions(); + feedOptions.enableCrossPartitionQuery(true); + FeedResponse queryResponse = client.queryDocuments(createdCollection.selfLink(), + "SELECT * FROM c WHERE c.Id = " + + "'foo'", feedOptions) + .blockFirst(); + String lsnHeaderValue = queryResponse.responseHeaders().get(WFConstants.BackendHeaders.LSN); + long lsn = Long.valueOf(lsnHeaderValue); + String sessionTokenHeaderValue = queryResponse.responseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + ISessionToken sessionToken = SessionTokenHelper.parse(sessionTokenHeaderValue); + logger.info("SESSION Token = {}, LSN = {}", sessionToken.convertToString(), lsn); + assertThat(lsn).isEqualTo(sessionToken.getLSN()); + } catch (Exception ex) { + CosmosClientException clientException = (CosmosClientException) ex.getCause(); + if (clientException.statusCode() != 0) { + if (clientException.statusCode() == HttpConstants.StatusCodes.REQUEST_TIMEOUT) { + // ignore + } else if (clientException.statusCode() == HttpConstants.StatusCodes.NOTFOUND) { + String lsnHeaderValue = clientException.responseHeaders().get(WFConstants.BackendHeaders.LSN); + long lsn = Long.valueOf(lsnHeaderValue); + String sessionTokenHeaderValue = clientException.responseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + ISessionToken sessionToken = SessionTokenHelper.parse(sessionTokenHeaderValue); + + logger.info("SESSION Token = {}, LSN = {}", sessionToken.convertToString(), lsn); + assertThat(lsn).isEqualTo(sessionToken.getLSN()); + } else { + throw ex; + } + } else { + throw ex; + } + } + }); + Mono.whenDelayError(task1, task2).block(); + } finally { + safeClose(client); + } + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTestsBase.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTestsBase.java new file mode 100644 index 0000000000000..7dbdddea5586b --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ConsistencyTestsBase.java @@ -0,0 +1,869 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.AccessCondition; +import com.azure.data.cosmos.AccessConditionType; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.PartitionKind; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.azure.data.cosmos.internal.routing.Range; +import org.apache.commons.collections4.map.UnmodifiableMap; +import org.apache.commons.lang3.StringUtils; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import reactor.core.publisher.Flux; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConsistencyTestsBase extends TestSuiteBase { + static final int CONSISTENCY_TEST_TIMEOUT = 120000; + static final String USER_NAME = "TestUser"; + RxDocumentClientImpl writeClient; + RxDocumentClientImpl readClient; + AsyncDocumentClient initClient; + Database createdDatabase; + DocumentCollection createdCollection; + + @BeforeClass(groups = {"direct"}, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + initClient = createGatewayRxDocumentClient().build(); + createdDatabase = SHARED_DATABASE; + createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + } + + void validateStrongConsistency(Resource resourceToWorkWith) throws Exception { + int numberOfTestIteration = 5; + Resource writeResource = resourceToWorkWith; + while (numberOfTestIteration-- > 0) //Write from a client and do point read through second client and ensure TS matches. + { + OffsetDateTime sourceTimestamp = writeResource.timestamp(); + Thread.sleep(1000); //Timestamp is in granularity of seconds. + Resource updatedResource = null; + if (resourceToWorkWith instanceof User) { + updatedResource = this.writeClient.upsertUser(createdDatabase.selfLink(), (User) writeResource, null).blockFirst().getResource(); + } else if (resourceToWorkWith instanceof Document) { + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); + updatedResource = this.writeClient.upsertDocument(createdCollection.selfLink(), (Document) writeResource, options, false).blockFirst().getResource(); + } + assertThat(updatedResource.timestamp().isAfter(sourceTimestamp)).isTrue(); + + User readResource = this.readClient.readUser(resourceToWorkWith.selfLink(), null).blockFirst().getResource(); + assertThat(updatedResource.timestamp().equals(readResource.timestamp())); + } + } + + void validateConsistentLSN() { + Document documentDefinition = getDocumentDefinition(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(documentDefinition.get("mypk"))); + Document document = createDocument(this.writeClient, createdDatabase.id(), createdCollection.id(), documentDefinition); + ResourceResponse response = this.writeClient.deleteDocument(document.selfLink(), options).single().block(); + assertThat(response.getStatusCode()).isEqualTo(204); + + long quorumAckedLSN = Long.parseLong((String) response.getResponseHeaders().get(WFConstants.BackendHeaders.QUORUM_ACKED_LSN)); + assertThat(quorumAckedLSN > 0).isTrue(); + FailureValidator validator = new FailureValidator.Builder().statusCode(404).lsnGreaterThan(quorumAckedLSN).build(); + Flux> readObservable = this.readClient.readDocument(document.selfLink(), options); + validateFailure(readObservable, validator); + } + + void validateConsistentLSNAndQuorumAckedLSN() { + Document documentDefinition = getDocumentDefinition(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(documentDefinition.get("mypk"))); + Document document = createDocument(this.writeClient, createdDatabase.id(), createdCollection.id(), documentDefinition); + ResourceResponse response = this.writeClient.deleteDocument(document.selfLink(), options).single().block(); + assertThat(response.getStatusCode()).isEqualTo(204); + + long quorumAckedLSN = Long.parseLong((String) response.getResponseHeaders().get(WFConstants.BackendHeaders.QUORUM_ACKED_LSN)); + assertThat(quorumAckedLSN > 0).isTrue(); + + FailureValidator validator = new FailureValidator.Builder().statusCode(404).lsnGreaterThanEqualsTo(quorumAckedLSN).exceptionQuorumAckedLSNInNotNull().build(); + Flux> readObservable = this.readClient.deleteDocument(document.selfLink(), options); + validateFailure(readObservable, validator); + + } + + void validateReadQuorum(ConsistencyLevel consistencyLevel, ResourceType childResourceType, boolean isBoundedStaleness) { + //TODO this need to complete once we implement emulator container in java, and then we can do operation + // like pause, resume, stop, recycle on it needed for this test. + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/355053 + } + + void validateStrongConsistencyOnAsyncReplication(boolean useGateway) throws InterruptedException { + if (!TestConfigurations.CONSISTENCY.equalsIgnoreCase(ConsistencyLevel.STRONG.toString())) { + throw new SkipException("Endpoint does not have strong consistency"); + } + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } + + this.writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.STRONG).build(); + + this.readClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.STRONG).build(); + + Document documentDefinition = getDocumentDefinition(); + Document document = createDocument(this.writeClient, createdDatabase.id(), createdCollection.id(), documentDefinition); + validateStrongConsistency(document); + } + + void validateStrongConsistency(Document documentToWorkWith) throws InterruptedException { + int numberOfTestIteration = 5; + Document writeDocument = documentToWorkWith; + while (numberOfTestIteration-- > 0) { + OffsetDateTime sourceTimestamp = writeDocument.timestamp(); + Thread.sleep(1000);//Timestamp is in granularity of seconds. + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(documentToWorkWith.get("mypk"))); + Document updatedDocument = this.writeClient.replaceDocument(writeDocument, options).blockFirst().getResource(); + assertThat(updatedDocument.timestamp().isAfter(sourceTimestamp)).isTrue(); + + Document readDocument = this.readClient.readDocument(documentToWorkWith.selfLink(), options).blockFirst().getResource(); + assertThat(updatedDocument.timestamp().equals(readDocument.timestamp())); + } + } + + void validateSessionContainerAfterCollectionCreateReplace(boolean useGateway) { + // DIRECT clients for read and write operations + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + + try { + PartitionKeyDefinition partitionKey = new PartitionKeyDefinition(); + partitionKey.paths(Arrays.asList("/customerid")); + partitionKey.kind(PartitionKind.HASH); + DocumentCollection coll = null; + { + // self link + ResourceResponse collection = writeClient.createCollection(createdDatabase.selfLink(), getCollectionDefinition(), null).blockFirst(); + String globalSessionToken1 = ((SessionContainer) writeClient.getSession()).getSessionToken(collection.getResource().selfLink()); + String globalSessionToken2 = ((SessionContainer) writeClient.getSession()).getSessionToken(BridgeInternal.getAltLink(collection.getResource())); + System.out.println("BridgeInternal.getAltLink(collection.getResource()) " + BridgeInternal.getAltLink(collection.getResource())); + assertThat(collection.getSessionToken()).isEqualTo(globalSessionToken1); + assertThat(collection.getSessionToken()).isEqualTo(globalSessionToken2); + + coll = collection.getResource(); + ResourceResponse collectionRead = writeClient.readCollection(coll.selfLink(), null).blockFirst(); + // timesync might bump the version, comment out the check + //assertThat(collection.sessionToken()).isEqualTo(collectionRead.sessionToken()); + } + { + // name link + ResourceResponse collection = writeClient.createCollection(BridgeInternal.getAltLink(createdDatabase), getCollectionDefinition(), null).blockFirst(); + + String globalSessionToken1 = ((SessionContainer) writeClient.getSession()).getSessionToken(collection.getResource().selfLink()); + String globalSessionToken2 = ((SessionContainer) writeClient.getSession()).getSessionToken(BridgeInternal.getAltLink(collection.getResource())); + assertThat(collection.getSessionToken()).isEqualTo(globalSessionToken1); + //assertThat(collection.sessionToken()).isEqualTo(globalSessionToken2); + + ResourceResponse collectionRead = + writeClient.readCollection(BridgeInternal.getAltLink(collection.getResource()), null).blockFirst(); + // timesync might bump the version, comment out the check + //assertThat(collection.sessionToken()).isEqualTo(collectionRead.sessionToken()); + } + { + Document document2 = new Document(); + document2.id("test" + UUID.randomUUID().toString()); + BridgeInternal.setProperty(document2, "customerid", 2); + // name link + ResourceResponse document = writeClient.createDocument(BridgeInternal.getAltLink(coll), + document2, null, false) + .blockFirst(); + String globalSessionToken1 = ((SessionContainer) writeClient.getSession()).getSessionToken(coll.selfLink()); + String globalSessionToken2 = ((SessionContainer) writeClient.getSession()).getSessionToken(BridgeInternal.getAltLink(coll)); + + assertThat(globalSessionToken1.indexOf(document.getSessionToken())).isNotNegative(); + assertThat(globalSessionToken2.indexOf(document.getSessionToken())).isNotNegative(); + } + { + Document document2 = new Document(); + document2.id("test" + UUID.randomUUID().toString()); + BridgeInternal.setProperty(document2, "customerid", 3); + // name link + ResourceResponse document = writeClient.createDocument(BridgeInternal.getAltLink(coll), + document2, null, false) + .blockFirst(); + String globalSessionToken1 = ((SessionContainer) writeClient.getSession()).getSessionToken(coll.selfLink()); + String globalSessionToken2 = ((SessionContainer) writeClient.getSession()).getSessionToken(BridgeInternal.getAltLink(coll)); + + assertThat(globalSessionToken1.indexOf(document.getSessionToken())).isNotNegative(); + assertThat(globalSessionToken2.indexOf(document.getSessionToken())).isNotNegative(); + } + } finally { + safeClose(writeClient); + } + } + + boolean validateConsistentPrefix(Resource resourceToWorkWith) throws InterruptedException { + int numberOfTestIteration = 5; + OffsetDateTime lastReadDateTime = resourceToWorkWith.timestamp(); + boolean readLagging = false; + Resource writeResource = resourceToWorkWith; + + while (numberOfTestIteration-- > 0) { //Write from a client and do point read through second client and ensure TS monotonically increases. + OffsetDateTime sourceTimestamp = writeResource.timestamp(); + Thread.sleep(1000); //Timestamp is in granularity of seconds. + Resource updatedResource = null; + if (resourceToWorkWith instanceof User) { + updatedResource = this.writeClient.upsertUser(createdDatabase.selfLink(), (User) writeResource, + null) + .blockFirst() + .getResource(); + } else if (resourceToWorkWith instanceof Document) { + updatedResource = this.writeClient.upsertDocument(createdCollection.selfLink(), + (Document) writeResource, null, false) + .blockFirst() + .getResource(); + } + assertThat(updatedResource.timestamp().isAfter(sourceTimestamp)).isTrue(); + writeResource = updatedResource; + + Resource readResource = null; + if (resourceToWorkWith instanceof User) { + readResource = this.readClient.readUser(resourceToWorkWith.selfLink(), null) + .blockFirst() + .getResource(); + } else if (resourceToWorkWith instanceof Document) { + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); + readResource = this.readClient.readDocument(resourceToWorkWith.selfLink(), options) + .blockFirst() + .getResource(); + } + assertThat(readResource.timestamp().compareTo(lastReadDateTime) >= 0).isTrue(); + lastReadDateTime = readResource.timestamp(); + if (readResource.timestamp().isBefore(updatedResource.timestamp())) { + readLagging = true; + } + } + return readLagging; + } + + boolean validateReadSession(Resource resourceToWorkWith) throws InterruptedException { + int numberOfTestIteration = 5; + OffsetDateTime lastReadDateTime = OffsetDateTime.MIN; + boolean readLagging = false; + Resource writeResource = resourceToWorkWith; + + while (numberOfTestIteration-- > 0) { + OffsetDateTime sourceTimestamp = writeResource.timestamp(); + Thread.sleep(1000); + Resource updatedResource = null; + if (resourceToWorkWith instanceof Document) { + updatedResource = this.writeClient.upsertDocument(createdCollection.selfLink(), writeResource, + null, false) + .single() + .block() + .getResource(); + } + assertThat(updatedResource.timestamp().isAfter(sourceTimestamp)).isTrue(); + writeResource = updatedResource; + + Resource readResource = null; + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); + if (resourceToWorkWith instanceof Document) { + readResource = this.readClient.readDocument(resourceToWorkWith.selfLink(), requestOptions).blockFirst().getResource(); + } + assertThat(readResource.timestamp().compareTo(lastReadDateTime) >= 0).isTrue(); + lastReadDateTime = readResource.timestamp(); + + if (readResource.timestamp().isBefore(updatedResource.timestamp())) { + readLagging = true; + } + } + return readLagging; + } + + boolean validateWriteSession(Resource resourceToWorkWith) throws InterruptedException { + int numberOfTestIteration = 5; + OffsetDateTime lastReadDateTime = OffsetDateTime.MIN; + boolean readLagging = false; + Resource writeResource = resourceToWorkWith; + + while (numberOfTestIteration-- > 0) { + OffsetDateTime sourceTimestamp = writeResource.timestamp(); + Thread.sleep(1000); + Resource updatedResource = null; + if (resourceToWorkWith instanceof Document) { + updatedResource = this.writeClient.upsertDocument(createdCollection.selfLink(), writeResource, null, false).single().block().getResource(); + } + assertThat(updatedResource.timestamp().isAfter(sourceTimestamp)).isTrue(); + writeResource = updatedResource; + + Resource readResource = null; + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceToWorkWith.get("mypk"))); + if (resourceToWorkWith instanceof Document) { + readResource = + this.readClient.readDocument(resourceToWorkWith.selfLink(), requestOptions) + .blockFirst() + .getResource(); + } + assertThat(readResource.timestamp().compareTo(lastReadDateTime) >= 0).isTrue(); + lastReadDateTime = readResource.timestamp(); + + if (readResource.timestamp().isBefore(updatedResource.timestamp())) { + readLagging = true; + } + + //Now perform write on session and update our session token and lastReadTS + Thread.sleep(1000); + if (resourceToWorkWith instanceof Document) { + readResource = this.writeClient.upsertDocument(createdCollection.selfLink(), readResource, + requestOptions, false) + .blockFirst() + .getResource(); + //Now perform write on session + } + assertThat(readResource.timestamp().isAfter(lastReadDateTime)); + + this.readClient.setSession(this.writeClient.getSession()); + } + return readLagging; + } + + void validateSessionContainerAfterCollectionDeletion(boolean useGateway) throws Exception { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl client1 = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RxDocumentClientImpl client2 = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + + String collectionId = UUID.randomUUID().toString(); + try { + DocumentCollection collectionDefinition = getCollectionDefinition(); + collectionDefinition.id(collectionId); + DocumentCollection collection = createCollection(client2, createdDatabase.id(), collectionDefinition, null); + ResourceResponseValidator successValidatorCollection = new ResourceResponseValidator.Builder() + .withId(collection.id()) + .build(); + Flux> readObservableCollection = client2.readCollection(collection.selfLink(), null); + validateSuccess(readObservableCollection, successValidatorCollection); + + for (int i = 0; i < 5; i++) { + String documentId = "Generation1-" + i; + Document documentDefinition = getDocumentDefinition(); + documentDefinition.id(documentId); + Document documentCreated = client2.createDocument(collection.selfLink(), documentDefinition, null, true).blockFirst().getResource(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(documentCreated.get("mypk"))); + client2.readDocument(BridgeInternal.getAltLink(documentCreated), requestOptions).blockFirst(); + client2.readDocument(documentCreated.selfLink(), requestOptions).blockFirst(); + } + + { + // just create the second for fun + DocumentCollection collection2 = createCollection(client2, createdDatabase.id(), getCollectionDefinition(), null); + successValidatorCollection = new ResourceResponseValidator.Builder() + .withId(collection2.id()) + .build(); + readObservableCollection = client2.readCollection(collection2.selfLink(), null); + validateSuccess(readObservableCollection, successValidatorCollection); + } + // verify the client2 has the same token. + { + String token1 = ((SessionContainer) client2.getSession()).getSessionToken(BridgeInternal.getAltLink(collection)); + String token2 = ((SessionContainer) client2.getSession()).getSessionToken(collection.selfLink()); + assertThat(token1).isEqualTo(token2); + } + + // now delete collection use different client + client1.deleteCollection(collection.selfLink(), null).blockFirst(); + + DocumentCollection collectionRandom1 = createCollection(client2, createdDatabase.id(), getCollectionDefinition()); + DocumentCollection documentCollection = getCollectionDefinition(); + collectionDefinition.id(collectionId); + DocumentCollection collectionSameName = createCollection(client2, createdDatabase.id(), collectionDefinition); + String documentId1 = "Generation2-" + 0; + Document databaseDefinition2 = getDocumentDefinition(); + databaseDefinition2.id(documentId1); + Document createdDocument = client1.createDocument(collectionSameName.selfLink(), databaseDefinition2, null, true).blockFirst().getResource(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(createdDocument.get("mypk"))); + ResourceResponseValidator successValidator = new ResourceResponseValidator.Builder() + .withId(createdDocument.id()) + .build(); + Flux> readObservable = client1.readDocument(createdDocument.selfLink(), requestOptions); + validateSuccess(readObservable, successValidator); + { + String token1 = ((SessionContainer) client1.getSession()).getSessionToken(BridgeInternal.getAltLink(collectionSameName)); + String token2 = ((SessionContainer) client1.getSession()).getSessionToken(collectionSameName.selfLink()); + assertThat(token1).isEqualTo(token2); + } + + { + // Client2 read using name link should fail with higher LSN. + String token = ((SessionContainer) client1.getSession()).getSessionToken(collectionSameName.selfLink()); + // artificially bump to higher LSN + String higherLsnToken = this.getDifferentLSNToken(token, 2000); + RequestOptions requestOptions1 = new RequestOptions(); + requestOptions1.setSessionToken(higherLsnToken); + requestOptions1.setPartitionKey(new PartitionKey(createdDocument.get("mypk"))); + readObservable = client2.readDocument(BridgeInternal.getAltLink(createdDocument), requestOptions1); + FailureValidator failureValidator = new FailureValidator.Builder().subStatusCode(1002).build(); + validateFailure(readObservable, failureValidator); + } + // this will trigger client2 to clear the token + { + // verify token by altlink is gone! + String token1 = ((SessionContainer) client2.getSession()).getSessionToken(BridgeInternal.getAltLink(collectionSameName)); + String token2 = ((SessionContainer) client2.getSession()).getSessionToken(collection.selfLink()); + assertThat(token1).isEmpty(); + //assertThat(token2).isNotEmpty(); In java both SelfLink and AltLink token remain in sync. + } + { + // second read should succeed! + readObservable = client2.readDocument(BridgeInternal.getAltLink(createdDocument), requestOptions); + validateSuccess(readObservable, successValidator); + } + // verify deleting indeed delete the collection session token + { + Document documentTest = + client1.createDocument(BridgeInternal.getAltLink(collectionSameName), getDocumentDefinition(), null, true).blockFirst().getResource(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(documentTest.get("mypk"))); + successValidator = new ResourceResponseValidator.Builder() + .withId(documentTest.id()) + .build(); + readObservable = client1.readDocument(documentTest.selfLink(), options); + validateSuccess(readObservable, successValidator); + + client1.deleteCollection(collectionSameName.selfLink(), null).blockFirst(); + String token1 = ((SessionContainer) client2.getSession()).getSessionToken(BridgeInternal.getAltLink(collectionSameName)); + String token2 = ((SessionContainer) client2.getSession()).getSessionToken(collectionSameName.selfLink()); + // currently we can't delete the token from Altlink when deleting using selflink + assertThat(token1).isNotEmpty(); + //assertThat(token2).isEmpty(); In java both SelfLink and AltLink token remain in sync. + } + } finally { + safeClose(client1); + safeClose(client2); + } + + } + + void validateSessionTokenWithPreConditionFailure(boolean useGateway) throws Exception { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RxDocumentClientImpl validationClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + // write a document, and upsert to it to update etag. + ResourceResponse documentResponse = writeClient.createDocument(BridgeInternal.getAltLink(createdCollection), getDocumentDefinition(), null, true).blockFirst(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); + ResourceResponse upsertResponse = + writeClient.upsertDocument(BridgeInternal.getAltLink(createdCollection), documentResponse.getResource(), requestOptions, true).blockFirst(); + + // create a conditioned read request, with first write request's etag, so the read fails with PreconditionFailure + AccessCondition ac = new AccessCondition(); + ac.condition(documentResponse.getResource().etag()); + ac.type(AccessConditionType.IF_MATCH); + RequestOptions requestOptions1 = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); + requestOptions1.setAccessCondition(ac); + Flux> preConditionFailureResponseObservable = validationClient.upsertDocument(BridgeInternal.getAltLink(createdCollection), + documentResponse.getResource(), requestOptions1, true); + FailureValidator failureValidator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.PRECONDITION_FAILED).build(); + validateFailure(preConditionFailureResponseObservable, failureValidator); + assertThat(isSessionEqual(((SessionContainer) validationClient.getSession()), (SessionContainer) writeClient.getSession())).isTrue(); + + } finally { + safeClose(writeClient); + safeClose(validationClient); + } + } + + void validateSessionTokenWithDocumentNotFoundException(boolean useGateway) throws Exception { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RxDocumentClientImpl validationClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + DocumentCollection collectionDefinition = getCollectionDefinition(); + collectionDefinition.id("TestCollection"); + + ResourceResponse documentResponse = writeClient.createDocument(BridgeInternal.getAltLink(createdCollection), getDocumentDefinition(), null, true).blockFirst(); + + FailureValidator failureValidator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.NOTFOUND).build(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); + // try to read a non existent document in the same partition that we previously wrote to + Flux> readObservable = validationClient.readDocument(BridgeInternal.getAltLink(documentResponse.getResource()) + "dummy", requestOptions); + validateFailure(readObservable, failureValidator); + assertThat(isSessionEqual(((SessionContainer) validationClient.getSession()), (SessionContainer) writeClient.getSession())).isTrue(); + } finally { + safeClose(writeClient); + safeClose(validationClient); + } + } + + void validateSessionTokenWithExpectedException(boolean useGateway) throws Exception { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + ResourceResponse documentResponse = + writeClient.createDocument(BridgeInternal.getAltLink(createdCollection), getDocumentDefinition(), null, false).blockFirst(); + String token = documentResponse.getResponseHeaders().get(HttpConstants.HttpHeaders.SESSION_TOKEN); + + // artificially bump to higher LSN + String higherLsnToken = this.getDifferentLSNToken(token, 2000); + FailureValidator failureValidator = new FailureValidator.Builder().subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(documentResponse.getResource().get("mypk"))); + requestOptions.setSessionToken(higherLsnToken); + // try to read a non existent document in the same partition that we previously wrote to + Flux> readObservable = writeClient.readDocument(BridgeInternal.getAltLink(documentResponse.getResource()), + requestOptions); + validateFailure(readObservable, failureValidator); + + } finally { + safeClose(writeClient); + } + } + + void validateSessionTokenWithConflictException(boolean useGateway) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RxDocumentClientImpl validationClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + Document documentDefinition = getDocumentDefinition(); + ResourceResponse documentResponse = + writeClient.createDocument(BridgeInternal.getAltLink(createdCollection), documentDefinition, null, true).blockFirst(); + + FailureValidator failureValidator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.CONFLICT).build(); + Flux> conflictDocumentResponse = validationClient.createDocument(BridgeInternal.getAltLink(createdCollection), + documentDefinition, null, + true); + validateFailure(conflictDocumentResponse, failureValidator); + } finally { + safeClose(writeClient); + safeClose(validationClient); + } + } + + void validateSessionTokenMultiPartitionCollection(boolean useGateway) throws Exception { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl writeClient = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + try { + + Range fullRange = new Range(PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, + PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey, true, false); + + IRoutingMapProvider routingMapProvider = writeClient.getPartitionKeyRangeCache(); + // assertThat(routingMapProvider.tryGetOverlappingRangesAsync(collection.resourceId(), fullRange, false).toBlocking().value().size()).isEqualTo(5); + + // Document to lock pause/resume clients + Document document1 = new Document(); + document1.id("test" + UUID.randomUUID().toString()); + BridgeInternal.setProperty(document1, "mypk", 1); + ResourceResponse childResource1 = writeClient.createDocument(createdCollection.selfLink(), document1, null, true).blockFirst(); + logger.info("Created {} child resource", childResource1.getResource().resourceId()); + assertThat(childResource1.getSessionToken()).isNotNull(); + assertThat(childResource1.getSessionToken().contains(":")).isTrue(); + String globalSessionToken1 = ((SessionContainer) writeClient.getSession()).getSessionToken(createdCollection.selfLink()); + assertThat(globalSessionToken1.contains(childResource1.getSessionToken())); + + // Document to lock pause/resume clients + Document document2 = new Document(); + document2.id("test" + UUID.randomUUID().toString()); + BridgeInternal.setProperty(document2, "mypk", 2); + ResourceResponse childResource2 = writeClient.createDocument(createdCollection.selfLink(), document2, null, true).blockFirst(); + assertThat(childResource2.getSessionToken()).isNotNull(); + assertThat(childResource2.getSessionToken().contains(":")).isTrue(); + String globalSessionToken2 = ((SessionContainer) writeClient.getSession()).getSessionToken(createdCollection.selfLink()); + logger.info("globalsessiontoken2 {}, childtoken1 {}, childtoken2 {}", globalSessionToken2, childResource1.getSessionToken(), childResource2.getSessionToken()); + assertThat(globalSessionToken2.contains(childResource2.getSessionToken())).isTrue(); + + // this token can read childresource2 but not childresource1 + String sessionToken = + StringUtils.split(childResource1.getSessionToken(), ':')[0] + ":" + createSessionToken(SessionTokenHelper.parse(childResource1.getSessionToken()), 100000000).convertToString() + "," + childResource2.getSessionToken(); + + RequestOptions option = new RequestOptions(); + option.setSessionToken(sessionToken); + option.setPartitionKey(new PartitionKey(2)); + writeClient.readDocument(childResource2.getResource().selfLink(), option).blockFirst(); + + option = new RequestOptions(); + option.setSessionToken(StringUtils.EMPTY); + option.setPartitionKey(new PartitionKey(1)); + writeClient.readDocument(childResource1.getResource().selfLink(), option).blockFirst(); + + option = new RequestOptions(); + option.setSessionToken(sessionToken); + option.setPartitionKey(new PartitionKey(1)); + Flux> readObservable = writeClient.readDocument(childResource1.getResource().selfLink(), option); + FailureValidator failureValidator = + new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.NOTFOUND).subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); + validateFailure(readObservable, failureValidator); + + readObservable = writeClient.readDocument(childResource2.getResource().selfLink(), option); + failureValidator = + new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.NOTFOUND).subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); + validateFailure(readObservable, failureValidator); + + assertThat(((SessionContainer) writeClient.getSession()).getSessionToken(createdCollection.selfLink())).isEqualTo + (((SessionContainer) writeClient.getSession()).getSessionToken(BridgeInternal.getAltLink(createdCollection))); + + assertThat(((SessionContainer) writeClient.getSession()).getSessionToken("asdfasdf")).isEmpty(); + assertThat(((SessionContainer) writeClient.getSession()).getSessionToken(createdDatabase.selfLink())).isEmpty(); + } finally { + safeClose(writeClient); + } + } + + void validateSessionTokenFromCollectionReplaceIsServerToken(boolean useGateway) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + if (useGateway) { + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + } else { + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + } + RxDocumentClientImpl client1 = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RxDocumentClientImpl client2 = null; + try { + Document doc = client1.createDocument(createdCollection.selfLink(), getDocumentDefinition(), null, true).blockFirst().getResource(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(doc.get("mypk"))); + Document doc1 = client1.readDocument(BridgeInternal.getAltLink(doc), requestOptions).blockFirst().getResource(); + + String token1 = ((SessionContainer) client1.getSession()).getSessionToken(createdCollection.selfLink()); + client2 = (RxDocumentClientImpl) new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + client2.replaceCollection(createdCollection, null).blockFirst(); + String token2 = ((SessionContainer) client2.getSession()).getSessionToken(createdCollection.selfLink()); + + logger.info("Token after document and after collection replace {} = {}", token1, token2); + } finally { + safeClose(client1); + safeClose(client2); + } + } + + @AfterClass(groups = {"direct"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(this.initClient); + safeClose(this.writeClient); + safeClose(this.readClient); + } + + private String getDifferentLSNToken(String token, long lsnDifferent) throws Exception { + String[] tokenParts = StringUtils.split(token, ':'); + ISessionToken sessionToken = SessionTokenHelper.parse(tokenParts[1]); + ISessionToken differentSessionToken = createSessionToken(sessionToken, sessionToken.getLSN() + lsnDifferent); + return String.format("%s:%s", tokenParts[0], differentSessionToken.convertToString()); + } + + public static ISessionToken createSessionToken(ISessionToken from, long globalLSN) throws Exception { + // Creates session token with specified GlobalLSN + if (from instanceof VectorSessionToken) { + VectorSessionToken fromSessionToken = (VectorSessionToken) from; + Field fieldVersion = VectorSessionToken.class.getDeclaredField("version"); + fieldVersion.setAccessible(true); + Long version = (Long) fieldVersion.get(fromSessionToken); + + Field fieldLocalLsnByRegion = VectorSessionToken.class.getDeclaredField("localLsnByRegion"); + fieldLocalLsnByRegion.setAccessible(true); + UnmodifiableMap localLsnByRegion = (UnmodifiableMap) fieldLocalLsnByRegion.get(fromSessionToken); + + Constructor constructor = VectorSessionToken.class.getDeclaredConstructor(long.class, long.class, UnmodifiableMap.class); + constructor.setAccessible(true); + VectorSessionToken vectorSessionToken = constructor.newInstance(version, globalLSN, localLsnByRegion); + return vectorSessionToken; + } else { + throw new IllegalArgumentException(); + } + } + + Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + private boolean isSessionEqual(SessionContainer sessionContainer1, SessionContainer sessionContainer2) throws Exception { + if (sessionContainer1 == null) { + return false; + } + + if (sessionContainer2 == null) { + return false; + } + + if (sessionContainer1 == sessionContainer2) { + return true; + } + + Field fieldCollectionResourceIdToSessionTokens1 = SessionContainer.class.getDeclaredField("collectionResourceIdToSessionTokens"); + Field fieldCollectionNameToCollectionResourceId1 = SessionContainer.class.getDeclaredField("collectionNameToCollectionResourceId"); + fieldCollectionResourceIdToSessionTokens1.setAccessible(true); + fieldCollectionNameToCollectionResourceId1.setAccessible(true); + ConcurrentHashMap> collectionResourceIdToSessionTokens1 = + (ConcurrentHashMap>) fieldCollectionResourceIdToSessionTokens1.get(sessionContainer1); + ConcurrentHashMap collectionNameToCollectionResourceId1 = (ConcurrentHashMap) fieldCollectionNameToCollectionResourceId1.get(sessionContainer1); + + + Field fieldCollectionResourceIdToSessionTokens2 = SessionContainer.class.getDeclaredField("collectionResourceIdToSessionTokens"); + Field fieldCollectionNameToCollectionResourceId2 = SessionContainer.class.getDeclaredField("collectionNameToCollectionResourceId"); + fieldCollectionResourceIdToSessionTokens2.setAccessible(true); + fieldCollectionNameToCollectionResourceId2.setAccessible(true); + ConcurrentHashMap> collectionResourceIdToSessionTokens2 = + (ConcurrentHashMap>) fieldCollectionResourceIdToSessionTokens2.get(sessionContainer2); + ConcurrentHashMap collectionNameToCollectionResourceId2 = (ConcurrentHashMap) fieldCollectionNameToCollectionResourceId2.get(sessionContainer2); + + if (collectionResourceIdToSessionTokens1.size() != collectionResourceIdToSessionTokens2.size() || + collectionNameToCollectionResourceId1.size() != collectionNameToCollectionResourceId2.size()) { + return false; + } + + // get keys, and compare entries + for (Long resourceId : collectionResourceIdToSessionTokens1.keySet()) { + if (!collectionResourceIdToSessionTokens1.get(resourceId).equals(collectionResourceIdToSessionTokens2.get(resourceId))) { + return false; + } + } + + for (String collectionName : collectionNameToCollectionResourceId1.keySet()) { + if (!collectionNameToCollectionResourceId1.get(collectionName).equals(collectionNameToCollectionResourceId2.get(collectionName))) { + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentQuerySpyWireContentTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentQuerySpyWireContentTest.java new file mode 100644 index 0000000000000..266ace95c5764 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentQuerySpyWireContentTest.java @@ -0,0 +1,208 @@ +/** + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.http.HttpRequest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentQuerySpyWireContentTest extends TestSuiteBase { + + private Database createdDatabase; + private DocumentCollection createdSinglePartitionCollection; + private DocumentCollection createdMultiPartitionCollection; + + private List createdDocumentsInSinglePartitionCollection = new ArrayList<>(); + private List createdDocumentsInMultiPartitionCollection = new ArrayList<>(); + + private SpyClientUnderTestFactory.ClientUnderTest client; + + public String getSinglePartitionCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdSinglePartitionCollection.id()); + } + + public String getMultiPartitionCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdMultiPartitionCollection.id()); + } + + @Factory(dataProvider = "clientBuilders") + public DocumentQuerySpyWireContentTest(Builder clientBuilder) { + super(clientBuilder); + } + + @DataProvider(name = "responseContinuationTokenLimitParamProvider") + public static Object[][] responseContinuationTokenLimitParamProvider() { + + FeedOptions options1 = new FeedOptions(); + options1.maxItemCount(1); + options1.responseContinuationTokenLimitInKb(5); + options1.partitionKey(new PartitionKey("99")); + String query1 = "Select * from r"; + boolean multiPartitionCollection1 = true; + + FeedOptions options2 = new FeedOptions(); + options2.maxItemCount(1); + options2.responseContinuationTokenLimitInKb(5); + options2.partitionKey(new PartitionKey("99")); + String query2 = "Select * from r order by r.prop"; + boolean multiPartitionCollection2 = false; + + FeedOptions options3 = new FeedOptions(); + options3.maxItemCount(1); + options3.responseContinuationTokenLimitInKb(5); + options3.partitionKey(new PartitionKey("99")); + String query3 = "Select * from r"; + boolean multiPartitionCollection3 = false; + + FeedOptions options4 = new FeedOptions(); + options4.partitionKey(new PartitionKey("99")); + String query4 = "Select * from r order by r.prop"; + boolean multiPartitionCollection4 = false; + + return new Object[][]{ + {options1, query1, multiPartitionCollection1}, + {options2, query2, multiPartitionCollection2}, + {options3, query3, multiPartitionCollection3}, + {options4, query4, multiPartitionCollection4}, + }; + } + + @Test(dataProvider = "responseContinuationTokenLimitParamProvider", groups = { "simple" }, timeOut = TIMEOUT) + public void queryWithContinuationTokenLimit(FeedOptions options, String query, boolean isMultiParitionCollection) throws Exception { + String collectionLink; + if (isMultiParitionCollection) { + collectionLink = getMultiPartitionCollectionLink(); + } else { + collectionLink = getSinglePartitionCollectionLink(); + } + + client.clearCapturedRequests(); + + Flux> queryObservable = client + .queryDocuments(collectionLink, query, options); + + List results = queryObservable.flatMap(p -> Flux.fromIterable(p.results())) + .collectList().block(); + + assertThat(results.size()).describedAs("total results").isGreaterThanOrEqualTo(1); + + List requests = client.getCapturedRequests(); + + for(HttpRequest req: requests) { + validateRequestHasContinuationTokenLimit(req, options.responseContinuationTokenLimitInKb()); + } + } + + private void validateRequestHasContinuationTokenLimit(HttpRequest request, Integer expectedValue) { + Map headers = request.headers().toMap(); + if (expectedValue != null && expectedValue > 0) { + assertThat(headers + .containsKey(HttpConstants.HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB)) + .isTrue(); + assertThat(headers + .get("x-ms-documentdb-responsecontinuationtokenlimitinkb")) + .isEqualTo(Integer.toString(expectedValue)); + } else { + assertThat(headers + .containsKey(HttpConstants.HttpHeaders.RESPONSE_CONTINUATION_TOKEN_LIMIT_IN_KB)) + .isFalse(); + } + } + + public Document createDocument(AsyncDocumentClient client, String collectionLink, int cnt) { + + Document docDefinition = getDocumentDefinition(cnt); + return client + .createDocument(collectionLink, docDefinition, null, false).blockFirst().getResource(); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + + client = new SpyClientBuilder(this.clientBuilder()).build(); + + createdDatabase = SHARED_DATABASE; + createdSinglePartitionCollection = SHARED_SINGLE_PARTITION_COLLECTION; + truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION); + + createdMultiPartitionCollection = SHARED_MULTI_PARTITION_COLLECTION; + truncateCollection(SHARED_MULTI_PARTITION_COLLECTION); + + for(int i = 0; i < 3; i++) { + createdDocumentsInSinglePartitionCollection.add(createDocument(client, getCollectionLink(createdSinglePartitionCollection), i)); + createdDocumentsInMultiPartitionCollection.add(createDocument(client, getCollectionLink(createdMultiPartitionCollection), i)); + } + + for(int i = 0; i < 5; i++) { + createdDocumentsInSinglePartitionCollection.add(createDocument(client, getCollectionLink(createdSinglePartitionCollection), 99)); + createdDocumentsInMultiPartitionCollection.add(createDocument(client, getCollectionLink(createdMultiPartitionCollection), 99)); + } + + // wait for catch up + TimeUnit.SECONDS.sleep(1); + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + + // do the query once to ensure the collection is cached. + client.queryDocuments(getMultiPartitionCollectionLink(), "select * from root", options) + .then().block(); + + // do the query once to ensure the collection is cached. + client.queryDocuments(getSinglePartitionCollectionLink(), "select * from root", options) + .then().block(); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static Document getDocumentDefinition(int cnt) { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"prop\" : %d, " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, cnt, cnt)); + return doc; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestContextValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestContextValidator.java new file mode 100644 index 0000000000000..1075d78b8d5bf --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestContextValidator.java @@ -0,0 +1,93 @@ + +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface DocumentServiceRequestContextValidator { + + static Builder builder() { + return new Builder(); + } + + void validate(T v); + + class Builder { + private List> validators = new ArrayList<>(); + + public DocumentServiceRequestContextValidator build() { + return new DocumentServiceRequestContextValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(T v) { + for (DocumentServiceRequestContextValidator validator : validators) { + validator.validate(v); + } + } + }; + } + + + public Builder add(DocumentServiceRequestContextValidator validator) { + validators.add(validator); + return this; + } + + public Builder qurorumSelectedLSN(long quoriumSelectedLSN) { + add(new DocumentServiceRequestContextValidator() { + @Override + public void validate(DocumentServiceRequestContext v) { + assertThat(v.quorumSelectedLSN).isEqualTo(quoriumSelectedLSN); + } + }); + return this; + } + + public Builder globalCommittedSelectedLSN(long globalCommittedSelectedLSN) { + add(new DocumentServiceRequestContextValidator() { + @Override + public void validate(DocumentServiceRequestContext v) { + assertThat(v.globalCommittedSelectedLSN).isEqualTo(globalCommittedSelectedLSN); + } + }); + return this; + } + + public Builder storeResponses(List storeResponses) { + add(new DocumentServiceRequestContextValidator() { + @Override + public void validate(DocumentServiceRequestContext v) { + assertThat(v.storeResponses).isEqualTo(storeResponses); + } + }); + return this; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestValidator.java new file mode 100644 index 0000000000000..b599a39ea5528 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/DocumentServiceRequestValidator.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface DocumentServiceRequestValidator { + + static Builder builder() { + return new Builder(); + } + + void validate(T v); + + class Builder { + private List> validators = new ArrayList<>(); + + public DocumentServiceRequestValidator build() { + return new DocumentServiceRequestValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(T v) { + for (DocumentServiceRequestValidator validator : validators) { + validator.validate(v); + } + } + }; + } + + public Builder add(DocumentServiceRequestValidator validator) { + validators.add(validator); + return this; + } + + public Builder withResourceType(ResourceType resourceType) { + add(new DocumentServiceRequestValidator() { + @Override + public void validate(T v) { + assertThat(v.getResourceType()).isEqualTo(resourceType); + } + }); + return this; + } + + public Builder withOperationType(OperationType operationType) { + add(new DocumentServiceRequestValidator() { + @Override + public void validate(T v) { + assertThat(v.getOperationType()).isEqualTo(operationType); + } + }); + return this; + } + + public Builder resourceTypeIn(ResourceType... resourceType) { + add(new DocumentServiceRequestValidator() { + @Override + public void validate(T v) { + assertThat(v.getResourceType()).isIn((Object[]) resourceType); + } + }); + return this; + } + + public Builder resourceTypeNotIn(ResourceType... resourceType) { + add(new DocumentServiceRequestValidator() { + @Override + public void validate(T v) { + assertThat(v.getResourceType()).isNotIn((Object[]) resourceType); + } + }); + return this; + } + + public Builder add(DocumentServiceRequestContextValidator validator) { + add(new DocumentServiceRequestValidator() { + @Override + public void validate(RxDocumentServiceRequest request) { + validator.validate(request.requestContext); + } + }); + return this; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FailureValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FailureValidator.java new file mode 100644 index 0000000000000..c45ccbc696ce7 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FailureValidator.java @@ -0,0 +1,347 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface FailureValidator { + + static Builder builder() { + return new Builder(); + } + + void validate(Throwable t); + + class Builder { + private List validators = new ArrayList<>(); + + public FailureValidator build() { + return new FailureValidator() { + @Override + public void validate(Throwable t) { + for (FailureValidator validator : validators) { + validator.validate(t); + } + } + }; + } + + public Builder statusCode(int statusCode) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).statusCode()).isEqualTo(statusCode); + } + }); + return this; + } + + public Builder lsnGreaterThan(long quorumAckedLSN) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(BridgeInternal.getLSN((CosmosClientException) t) > quorumAckedLSN).isTrue(); + } + }); + return this; + } + + public Builder lsnGreaterThanEqualsTo(long quorumAckedLSN) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(BridgeInternal.getLSN((CosmosClientException) t) >= quorumAckedLSN).isTrue(); + } + }); + return this; + } + + public Builder exceptionQuorumAckedLSNInNotNull() { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException cosmosClientException = (CosmosClientException) t; + long exceptionQuorumAckedLSN = -1; + if (cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.QUORUM_ACKED_LSN) != null) { + exceptionQuorumAckedLSN = Long.parseLong((String) cosmosClientException.responseHeaders().get(WFConstants.BackendHeaders.QUORUM_ACKED_LSN)); + + } + assertThat(exceptionQuorumAckedLSN).isNotEqualTo(-1); + } + }); + return this; + } + + public Builder errorMessageContains(String errorMsg) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t.getMessage()).contains(errorMsg); + } + }); + return this; + } + + public Builder notNullActivityId() { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).message()).isNotNull(); + } + }); + return this; + } + + public Builder error(CosmosError cosmosError) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).error().toJson()).isEqualTo(cosmosError.toJson()); + } + }); + return this; + } + + public Builder subStatusCode(Integer substatusCode) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).subStatusCode()).isEqualTo(substatusCode); + } + }); + return this; + } + + public Builder unknownSubStatusCode() { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).subStatusCode()).isEqualTo(HttpConstants.SubStatusCodes.UNKNOWN); + } + }); + return this; + } + + public Builder responseHeader(String key, String value) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + assertThat(((CosmosClientException) t).responseHeaders().get(key)).isEqualTo(value); + } + }); + return this; + } + + public Builder lsn(long lsn) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(BridgeInternal.getLSN(ex)).isEqualTo(lsn); + } + }); + return this; + } + + public Builder partitionKeyRangeId(String pkrid) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(BridgeInternal.getPartitionKeyRangeId(ex)).isEqualTo(pkrid); + } + }); + return this; + } + + public Builder resourceAddress(String resourceAddress) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(BridgeInternal.getResourceAddress(ex)).isEqualTo(resourceAddress); + } + }); + return this; + } + + public Builder instanceOf(Class cls) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(cls); + } + }); + return this; + } + + public Builder sameAs(Exception exception) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isSameAs(exception); + } + }); + return this; + } + + public Builder resourceNotFound() { + + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(ex.statusCode()).isEqualTo(404); + + } + }); + return this; + } + + public Builder resourceTokenNotFound() { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(IllegalArgumentException.class); + IllegalArgumentException ex = (IllegalArgumentException) t; + assertThat(ex.getMessage()).isEqualTo(RMResources.ResourceTokenNotFound); + } + }); + return this; + } + + public Builder resourceAlreadyExists() { + + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(ex.statusCode()).isEqualTo(409); + + } + }); + return this; + } + + public Builder causeInstanceOf(Class cls) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t.getCause()).isNotNull(); + assertThat(t.getCause()).isInstanceOf(cls); + } + }); + return this; + } + + public Builder causeOfCauseInstanceOf(Class cls) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t.getCause()).isNotNull(); + assertThat(t.getCause().getCause()).isNotNull(); + assertThat(t.getCause().getCause()).isInstanceOf(cls); + } + }); + return this; + } + + public Builder documentClientExceptionHeaderRequestContainsEntry(String key, String value) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(CosmosClientException.class); + CosmosClientException ex = (CosmosClientException) t; + assertThat(BridgeInternal.getRequestHeaders(ex)).containsEntry(key, value); + } + }); + return this; + } + + public Builder withRuntimeExceptionMessage(String message) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(RuntimeException.class); + assertThat(t.getMessage()).isEqualTo(message); + } + }); + return this; + } + + public Builder withRuntimeExceptionClass(Class k) { + validators.add(new FailureValidator() { + @Override + public void validate(Throwable t) { + assertThat(t).isNotNull(); + assertThat(t).isInstanceOf(RuntimeException.class); + assertThat(t).isInstanceOf(k); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseListValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseListValidator.java new file mode 100644 index 0000000000000..4da9e76512226 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseListValidator.java @@ -0,0 +1,320 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.fasterxml.jackson.databind.node.ArrayNode; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface FeedResponseListValidator { + + void validate(List> feedList); + + class Builder { + private List> validators = new ArrayList<>(); + + public FeedResponseListValidator build() { + return new FeedResponseListValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(List> feedList) { + for (FeedResponseListValidator validator : validators) { + validator.validate(feedList); + } + } + }; + } + + public Builder totalSize(final int expectedCount) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + int resultCount = feedList.stream().mapToInt(f -> f.results().size()).sum(); + assertThat(resultCount) + .describedAs("total number of results").isEqualTo(expectedCount); + } + }); + return this; + } + + public Builder containsExactly(List expectedRids) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List actualIds = feedList + .stream() + .flatMap(f -> f.results().stream()) + .map(r -> r.resourceId()) + .collect(Collectors.toList()); + assertThat(actualIds) + .describedAs("Resource IDs of results") + .containsExactlyElementsOf(expectedRids); + } + }); + return this; + } + + public Builder containsExactlyIds(List expectedIds) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List actualIds = feedList + .stream() + .flatMap(f -> f.results().stream()) + .map(r -> r.id()) + .collect(Collectors.toList()); + assertThat(actualIds) + .describedAs("IDs of results") + .containsExactlyElementsOf(expectedIds); + } + }); + return this; + } + + public Builder validateAllResources(Map> resourceIDToValidator) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List resources = feedList + .stream() + .flatMap(f -> f.results().stream()) + .collect(Collectors.toList()); + + for(T r: resources) { + ResourceValidator validator = resourceIDToValidator.get(r.resourceId()); + assertThat(validator).isNotNull(); + validator.validate(r); + } + } + }); + return this; + } + + public Builder exactlyContainsInAnyOrder(List expectedIds) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List actualIds = feedList + .stream() + .flatMap(f -> f.results().stream()) + .map(Resource::resourceId) + .collect(Collectors.toList()); + assertThat(actualIds) + .describedAs("Resource IDs of results") + .containsOnlyElementsOf(expectedIds); + } + }); + return this; + } + + public Builder numberOfPages(int expectedNumberOfPages) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + assertThat(feedList) + .describedAs("number of pages") + .hasSize(expectedNumberOfPages); + } + }); + return this; + } + + public Builder numberOfPagesIsGreaterThanOrEqualTo(int leastNumber) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + assertThat(feedList.size()) + .describedAs("number of pages") + .isGreaterThanOrEqualTo(leastNumber); + } + }); + return this; + } + + public Builder totalRequestChargeIsAtLeast(double minimumCharge) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + assertThat(feedList.stream().mapToDouble(p -> p.requestCharge()).sum()) + .describedAs("total request charge") + .isGreaterThanOrEqualTo(minimumCharge); + } + }); + return this; + } + + public Builder pageSatisfy(int pageNumber, FeedResponseValidator pageValidator) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + assertThat(feedList.size()).isGreaterThan(pageNumber); + pageValidator.validate(feedList.get(pageNumber)); + } + }); + return this; + } + + public Builder allPagesSatisfy(FeedResponseValidator pageValidator) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + + for(FeedResponse fp: feedList) { + pageValidator.validate(fp); + } + } + }); + return this; + } + + public Builder withAggregateValue(Object value) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List list = feedList.get(0).results(); + CosmosItemProperties result = list.size() > 0 ? list.get(0) : null; + + if (result != null) { + if (value instanceof Double) { + + Double d = result.getDouble("_aggregate"); + assertThat(d).isEqualTo(value); + } else if (value instanceof Integer) { + + Integer d = result.getInt("_aggregate"); + assertThat(d).isEqualTo(value); + } else if (value instanceof String) { + + String d = result.getString("_aggregate"); + assertThat(d).isEqualTo(value); + } else if (value instanceof Document){ + + assertThat(result.toString()).isEqualTo(value.toString()); + } else { + + assertThat(result.get("_aggregate")).isNull(); + assertThat(value).isNull(); + } + } else { + + assertThat(value).isNull(); + } + + } + }); + return this; + } + + public Builder withOrderedResults(List expectedOrderedList, + List compositeIndex) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + + List resultOrderedList = feedList.stream() + .flatMap(f -> f.results().stream()) + .collect(Collectors.toList()); + assertThat(expectedOrderedList.size()).isEqualTo(resultOrderedList.size()); + + ArrayList paths = new ArrayList(); + Iterator compositeIndexIterator = compositeIndex.iterator(); + while (compositeIndexIterator.hasNext()) { + paths.add(compositeIndexIterator.next().path().replace("/", "")); + } + for (int i = 0; i < resultOrderedList.size(); i ++) { + ArrayNode resultValues = (ArrayNode) resultOrderedList.get(i).get("$1"); + assertThat(resultValues.size()).isEqualTo(paths.size()); + for (int j = 0; j < paths.size(); j++) { + if (paths.get(j).contains("number")) { + assertThat(expectedOrderedList.get(i).getInt(paths.get(j))).isEqualTo(resultValues.get(j).intValue()); + } else if (paths.get(j).toLowerCase().contains("string")) { + assertThat(expectedOrderedList.get(i).getString(paths.get(j))).isEqualTo(resultValues.get(j).asText()); + } else if (paths.get(j).contains("bool")) { + assertThat(expectedOrderedList.get(i).getBoolean(paths.get(j))).isEqualTo(resultValues.get(j).asBoolean()); + } else { + assertThat(resultValues.get(j).isNull()).isTrue(); + assertThat(expectedOrderedList.get(i).get("nullField")).isNull(); + } + } + } + + } + }); + return this; + } + + public Builder pageLengths(int[] pageLengths) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + assertThat(feedList).hasSize(pageLengths.length); + for (int i = 0; i < pageLengths.length; i++) + assertThat(feedList.get(i).results().size()).isEqualTo(pageLengths[i]); + } + }); + return this; + } + + public Builder hasValidQueryMetrics(boolean shouldHaveMetrics) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + for(FeedResponse feedPage: feedList) { + if (shouldHaveMetrics) { + QueryMetrics queryMetrics = BridgeInternal.createQueryMetricsFromCollection(BridgeInternal.queryMetricsFromFeedResponse(feedPage).values()); + assertThat(queryMetrics.getIndexHitDocumentCount()).isGreaterThanOrEqualTo(0); + assertThat(queryMetrics.getRetrievedDocumentSize()).isGreaterThan(0); + assertThat(queryMetrics.getTotalQueryExecutionTime().compareTo(Duration.ZERO)).isGreaterThan(0); + assertThat(queryMetrics.getOutputDocumentCount()).isGreaterThan(0); + assertThat(queryMetrics.getRetrievedDocumentCount()).isGreaterThan(0); + assertThat(queryMetrics.getDocumentLoadTime().compareTo(Duration.ZERO)).isGreaterThan(0); + assertThat(queryMetrics.getDocumentWriteTime().compareTo(Duration.ZERO)).isGreaterThanOrEqualTo(0); + assertThat(queryMetrics.getVMExecutionTime().compareTo(Duration.ZERO)).isGreaterThan(0); + assertThat(queryMetrics.getQueryPreparationTimes().getLogicalPlanBuildTime().compareTo(Duration.ZERO)).isGreaterThan(0); + assertThat(queryMetrics.getQueryPreparationTimes().getPhysicalPlanBuildTime().compareTo(Duration.ZERO)).isGreaterThanOrEqualTo(0); + assertThat(queryMetrics.getQueryPreparationTimes().getQueryCompilationTime().compareTo(Duration.ZERO)).isGreaterThan(0); + assertThat(queryMetrics.getRuntimeExecutionTimes().getQueryEngineExecutionTime().compareTo(Duration.ZERO)).isGreaterThanOrEqualTo(0); + assertThat(BridgeInternal.getClientSideMetrics(queryMetrics).getRequestCharge()).isGreaterThan(0); + } else { + assertThat(BridgeInternal.queryMetricsFromFeedResponse(feedPage).isEmpty()); + } + } + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseValidator.java new file mode 100644 index 0000000000000..20a190603c25d --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/FeedResponseValidator.java @@ -0,0 +1,145 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface FeedResponseValidator { + + void validate(FeedResponse feedList); + + public class Builder { + private List> validators = new ArrayList<>(); + + public FeedResponseValidator build() { + return new FeedResponseValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(FeedResponse feedPage) { + for (FeedResponseValidator validator : validators) { + validator.validate(feedPage); + } + } + }; + } + + public Builder pageSizeIsLessThanOrEqualTo(final int maxPageSize) { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.results().size()).isLessThanOrEqualTo(maxPageSize); + } + }); + return this; + } + + public Builder pageSizeOf(final int expectedCount) { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.results()).hasSize(expectedCount); + } + }); + return this; + } + + public Builder positiveRequestCharge() { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.requestCharge()).isPositive(); + } + }); + return this; + } + + public Builder requestChargeGreaterThanOrEqualTo(double minRequestCharge) { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.requestCharge()).isGreaterThanOrEqualTo(minRequestCharge); + } + }); + return this; + } + + public Builder requestChargeLessThanOrEqualTo(double maxRequestCharge) { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.requestCharge()).isLessThanOrEqualTo(maxRequestCharge); + } + }); + return this; + } + + public Builder hasHeader(String headerKey) { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.responseHeaders()).containsKey(headerKey); + } + }); + return this; + } + + public Builder hasRequestChargeHeader() { + + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage.responseHeaders()).containsKey(HttpConstants.HttpHeaders.REQUEST_CHARGE); + } + }); + return this; + } + + public Builder idsExactlyAre(final List expectedIds) { + validators.add(new FeedResponseValidator() { + @Override + public void validate(FeedResponse feedPage) { + assertThat(feedPage + .results().stream() + .map(r -> r.resourceId()) + .collect(Collectors.toList())) + .containsExactlyElementsOf(expectedIds); + } + }); + return this; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/HttpClientUnderTestWrapper.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/HttpClientUnderTestWrapper.java new file mode 100644 index 0000000000000..d7543eaafc597 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/HttpClientUnderTestWrapper.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpRequest; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.mockito.Mockito.doAnswer; + +/** + * This is a helper class for capturing requests sent over a httpClient. + */ +public class HttpClientUnderTestWrapper { + + final private HttpClient origHttpClient; + final private HttpClient spyHttpClient; + + public final List capturedRequests = Collections.synchronizedList(new ArrayList<>()); + + public HttpClientUnderTestWrapper(HttpClient origHttpClient) { + this.origHttpClient = origHttpClient; + this.spyHttpClient = Mockito.spy(origHttpClient); + initRequestCapture(spyHttpClient); + } + + public HttpClient getSpyHttpClient() { + return spyHttpClient; + } + + private void initRequestCapture(HttpClient spyClient) { + doAnswer(invocationOnMock -> { + HttpRequest httpRequest = invocationOnMock.getArgumentAt(0, HttpRequest.class); + capturedRequests.add(httpRequest); + return origHttpClient.send(httpRequest); + }).when(spyClient).send(Mockito.any(HttpRequest.class)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/LocationHelperTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/LocationHelperTest.java new file mode 100644 index 0000000000000..c24e244a1452a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/LocationHelperTest.java @@ -0,0 +1,19 @@ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.routing.LocationHelper; +import org.testng.annotations.Test; + +import java.net.URI; +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LocationHelperTest { + @Test(groups = "unit") + public void getLocationEndpoint() throws Exception { + URL globalServiceEndpoint = URI.create("https://account-name.documents.azure.com:443").toURL(); + URL expectedRegionServiceEndpoint = URI.create("https://account-name-east-us.documents.azure.com:443").toURL(); + assertThat(LocationHelper.getLocationEndpoint(globalServiceEndpoint, "east-us")) + .isEqualTo(expectedRegionServiceEndpoint); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/NetworkFailureTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/NetworkFailureTest.java new file mode 100644 index 0000000000000..c045cd9cb6670 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/NetworkFailureTest.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.net.UnknownHostException; +import java.time.Instant; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class NetworkFailureTest extends TestSuiteBase { + private static final int TIMEOUT = ClientRetryPolicy.MaxRetryCount * ClientRetryPolicy.RetryIntervalInMS + 60000; + private final DocumentCollection collectionDefinition; + + @Factory(dataProvider = "simpleClientBuildersWithDirect") + public NetworkFailureTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + this.collectionDefinition = getCollectionDefinition(); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createCollectionWithUnreachableHost() { + SpyClientUnderTestFactory.ClientWithGatewaySpy client = null; + + try { + client = SpyClientUnderTestFactory.createClientWithGatewaySpy(clientBuilder()); + + Database database = SHARED_DATABASE; + + Flux> createObservable = client + .createCollection(database.selfLink(), collectionDefinition, null); + + + final RxGatewayStoreModel origGatewayStoreModel = client.getOrigGatewayStoreModel(); + + Mockito.doAnswer(invocation -> { + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + + if (request.getResourceType() == ResourceType.DocumentCollection) { + return Flux.error(new UnknownHostException()); + } + + return origGatewayStoreModel.processMessage(request); + + }).when(client.getSpyGatewayStoreModel()).processMessage(Mockito.any()); + + + FailureValidator validator = new FailureValidator.Builder().instanceOf(UnknownHostException.class).build(); + Instant start = Instant.now(); + validateFailure(createObservable, validator, TIMEOUT); + Instant after = Instant.now(); + assertThat(after.toEpochMilli() - start.toEpochMilli()) + .isGreaterThanOrEqualTo(ClientRetryPolicy.MaxRetryCount * ClientRetryPolicy.RetryIntervalInMS); + + } finally { + safeClose(client); + } + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + AsyncDocumentClient client = createGatewayHouseKeepingDocumentClient().build(); + safeDeleteCollection(client, collectionDefinition); + client.close(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ParallelAsync.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ParallelAsync.java new file mode 100644 index 0000000000000..e454a20ee7a1e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ParallelAsync.java @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.apache.commons.lang3.Range; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class ParallelAsync { + + static Mono forEachAsync(Range range, int partition, Consumer func) { + + int partitionSize = (range.getMaximum() - range.getMinimum()) / partition; + List> task = new ArrayList<>(); + int startRange = range.getMinimum(); + for (int i = 0; i < partition; i++) { + Range integerRange = Range.between(startRange, startRange + partitionSize); + task.add(Mono.defer(() -> { + for(int j = integerRange.getMinimum(); j < integerRange.getMaximum();j++) { + func.accept(j); + } + return Mono.empty(); + })); + startRange = startRange + partitionSize ; + } + return Mono.whenDelayError(task); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/PathsHelperTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/PathsHelperTest.java new file mode 100644 index 0000000000000..2538b0faf95dd --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/PathsHelperTest.java @@ -0,0 +1,117 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PathsHelperTest { + + private static final String DATABASE_ID = "IXYFAA=="; + private static final String DATABASE_COLLECTION_ID = "IXYFAOHEBPM="; + private static final String DOCUMENT_ID = "IXYFAOHEBPMBAAAAAAAAAA=="; + private static final String ATTACHMENT_ID = "IXYFAOHEBPMBAAAAAAAAABJYSJk="; + private static final String PERMISSION_ID = "IXYFAE9ZOwBGkyqWIsNKAA=="; + private static final String STORED_PRCEDURE_ID = "IXYFAOHEBPMCAAAAAAAAgA=="; + private static final String TRIGGER_ID = "IXYFAOHEBPMCAAAAAAAAcA=="; + private static final String USER_DEFINED_FUNCTION_ID = "IXYFAOHEBPMBAAAAAAAAYA=="; + private static final String USER_ID = "IXYFAE9ZOwA="; + private static final String CONFLICT_ID = "k6d9ALgBmD8BAAAAAAAAQA=="; + + private static final String DATABASE_FULL_NAME = "dbs/IXYFAA==/"; + private static final String DOCUMENT_COLLECTION_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/"; + private static final String DOCUMENT_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/"; + private static final String STORED_PRCEDURE_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/sprocs/IXYFAOHEBPMCAAAAAAAAgA==/"; + private static final String USER_DEFINED_FUNCTION_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/udfs/IXYFAOHEBPMBAAAAAAAAYA==/"; + private static final String USER_FULL_NAME = "dbs/IXYFAA==/users/IXYFAE9ZOwA=/"; + private static final String PERMISSION_FULL_NAME = "dbs/IXYFAA==/users/IXYFAE9ZOwA=/permissions/IXYFAE9ZOwBGkyqWIsNKAA==/"; + private static final String ATTACHMENT_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/attachments/IXYFAOHEBPMBAAAAAAAAABJYSJk=/"; + private static final String TRIGGER_FULL_NAME = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/triggers/IXYFAOHEBPMCAAAAAAAAcA==/"; + private static final String CONFLICT_FULL_NAME = "dbs/k6d9AA==/colls/k6d9ALgBmD8=/conflicts/k6d9ALgBmD8BAAAAAAAAQA==/"; + + private static final String INCORRECT = "incorrect"; + + @Test(groups = { "unit" }) + public void validateResourceID() { + assertThat(PathsHelper.validateResourceId(ResourceType.Database, DATABASE_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.DocumentCollection, DATABASE_COLLECTION_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.Document, DOCUMENT_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.Attachment, ATTACHMENT_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.Permission, PERMISSION_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.StoredProcedure, STORED_PRCEDURE_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.Trigger, TRIGGER_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.UserDefinedFunction, USER_DEFINED_FUNCTION_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.User, USER_ID)).isTrue(); + assertThat(PathsHelper.validateResourceId(ResourceType.Conflict, CONFLICT_ID)).isTrue(); + + assertThat(PathsHelper.validateResourceId(ResourceType.Database, DATABASE_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.DocumentCollection, DATABASE_COLLECTION_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.Document, DOCUMENT_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.Attachment, ATTACHMENT_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.Permission, PERMISSION_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.StoredProcedure, STORED_PRCEDURE_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.Trigger, TRIGGER_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.UserDefinedFunction, USER_DEFINED_FUNCTION_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.User, USER_ID + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceId(ResourceType.Conflict, CONFLICT_ID + INCORRECT)).isFalse(); + } + + @Test(groups = { "unit" }) + public void validateResourceFullName() { + assertThat(PathsHelper.validateResourceFullName(ResourceType.Database, DATABASE_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.DocumentCollection, DOCUMENT_COLLECTION_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Document, DOCUMENT_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Attachment, ATTACHMENT_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Permission, PERMISSION_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.User, USER_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Conflict, CONFLICT_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.UserDefinedFunction, USER_DEFINED_FUNCTION_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.StoredProcedure, STORED_PRCEDURE_FULL_NAME)).isTrue(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Trigger, TRIGGER_FULL_NAME)).isTrue(); + + assertThat(PathsHelper.validateResourceFullName(ResourceType.Database, DATABASE_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.DocumentCollection, DOCUMENT_COLLECTION_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Document, DOCUMENT_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Attachment, ATTACHMENT_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Permission, PERMISSION_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.User, USER_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Conflict, CONFLICT_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.UserDefinedFunction, USER_DEFINED_FUNCTION_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.StoredProcedure, STORED_PRCEDURE_FULL_NAME + INCORRECT)).isFalse(); + assertThat(PathsHelper.validateResourceFullName(ResourceType.Trigger, TRIGGER_FULL_NAME + INCORRECT)).isFalse(); + + } + + @Test(groups = {"unit"}) + public void generatePathAtDBLevel() { + RxDocumentServiceRequest rxDocumentServiceRequest = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.DatabaseAccount); + String path = PathsHelper.generatePath(ResourceType.DatabaseAccount, rxDocumentServiceRequest, rxDocumentServiceRequest.isFeed); + assertThat(path).isEqualTo(Paths.DATABASE_ACCOUNT_PATH_SEGMENT + "/"); + + rxDocumentServiceRequest = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database); + path = PathsHelper.generatePath(ResourceType.Database, rxDocumentServiceRequest, rxDocumentServiceRequest.isFeed); + assertThat(path).isEqualTo(Paths.DATABASES_PATH_SEGMENT + "/"); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicyTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicyTest.java new file mode 100644 index 0000000000000..7a03819197c2e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RenameCollectionAwareClientRetryPolicyTest.java @@ -0,0 +1,155 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.caches.RxClientCollectionCache; +import io.netty.handler.timeout.ReadTimeoutException; +import org.mockito.Mockito; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import static com.azure.data.cosmos.internal.ClientRetryPolicyTest.validateSuccess; +import static org.assertj.core.api.Assertions.assertThat; + +public class RenameCollectionAwareClientRetryPolicyTest { + + private final static int TIMEOUT = 10000; + + @Test(groups = "unit", timeOut = TIMEOUT) + public void onBeforeSendRequestNotInvoked() { + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + + IRetryPolicyFactory retryPolicyFactory = new RetryPolicy(endpointManager, ConnectionPolicy.defaultPolicy()); + RxClientCollectionCache rxClientCollectionCache = Mockito.mock(RxClientCollectionCache.class); + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + RenameCollectionAwareClientRetryPolicy renameCollectionAwareClientRetryPolicy = new RenameCollectionAwareClientRetryPolicy(sessionContainer + , rxClientCollectionCache + , retryPolicyFactory.getRequestPolicy()); + + Exception exception = ReadTimeoutException.INSTANCE; + + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + Mono shouldRetry = + renameCollectionAwareClientRetryPolicy.shouldRetry(exception); + validateSuccess(shouldRetry, ShouldRetryValidator.builder() + .withException(exception) + .shouldRetry(false) + .build()); + + Mockito.verifyZeroInteractions(endpointManager); + } + + @Test(groups = "unit", timeOut = TIMEOUT) + public void shouldRetryWithNotFoundStatusCode() { + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + IRetryPolicyFactory retryPolicyFactory = new RetryPolicy(endpointManager, ConnectionPolicy.defaultPolicy()); + RxClientCollectionCache rxClientCollectionCache = Mockito.mock(RxClientCollectionCache.class); + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + RenameCollectionAwareClientRetryPolicy renameCollectionAwareClientRetryPolicy = new RenameCollectionAwareClientRetryPolicy(sessionContainer + , rxClientCollectionCache + , retryPolicyFactory.getRequestPolicy()); + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + renameCollectionAwareClientRetryPolicy.onBeforeSendRequest(request); + + NotFoundException notFoundException = new NotFoundException(); + + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + .shouldRetry(notFoundException); + validateSuccess(singleShouldRetry, ShouldRetryValidator.builder() + .withException(notFoundException) + .shouldRetry(false) + .build()); + } + + @Test(groups = "unit", timeOut = TIMEOUT) + public void shouldRetryWithNotFoundStatusCodeAndReadSessionNotAvailableSubStatusCode() { + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + IRetryPolicyFactory retryPolicyFactory = new RetryPolicy(endpointManager, ConnectionPolicy.defaultPolicy()); + RxClientCollectionCache rxClientCollectionCache = Mockito.mock(RxClientCollectionCache.class); + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + RenameCollectionAwareClientRetryPolicy renameCollectionAwareClientRetryPolicy = new RenameCollectionAwareClientRetryPolicy(sessionContainer + , rxClientCollectionCache + , retryPolicyFactory.getRequestPolicy()); + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + request.requestContext.resolvedCollectionRid = "rid_0"; + renameCollectionAwareClientRetryPolicy.onBeforeSendRequest(request); + + NotFoundException notFoundException = new NotFoundException(); + notFoundException.responseHeaders().put(WFConstants.BackendHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE)); + + DocumentCollection documentCollection = new DocumentCollection(); + documentCollection.resourceId("rid_1"); + + Mockito.when(rxClientCollectionCache.resolveCollectionAsync(request)).thenReturn(Mono.just(documentCollection)); + + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + .shouldRetry(notFoundException); + validateSuccess(singleShouldRetry, ShouldRetryValidator.builder() + .nullException() + .shouldRetry(true) + .build()); + } + + /** + * No retry on bad request exception + */ + @Test(groups = "unit", timeOut = TIMEOUT) + public void shouldRetryWithGenericException() { + GlobalEndpointManager endpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(Mono.empty()).when(endpointManager).refreshLocationAsync(Mockito.eq(null)); + IRetryPolicyFactory retryPolicyFactory = new RetryPolicy(endpointManager, ConnectionPolicy.defaultPolicy()); + RxClientCollectionCache rxClientCollectionCache = Mockito.mock(RxClientCollectionCache.class); + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + RenameCollectionAwareClientRetryPolicy renameCollectionAwareClientRetryPolicy = new RenameCollectionAwareClientRetryPolicy(sessionContainer + , rxClientCollectionCache + , retryPolicyFactory.getRequestPolicy()); + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + renameCollectionAwareClientRetryPolicy.onBeforeSendRequest(request); + + Mono singleShouldRetry = renameCollectionAwareClientRetryPolicy + .shouldRetry(new BadRequestException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isFalse(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceResponseValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceResponseValidator.java new file mode 100644 index 0000000000000..8a2ca2755902f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceResponseValidator.java @@ -0,0 +1,359 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.IndexingMode; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.SpatialSpec; +import com.azure.data.cosmos.SpatialType; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import org.assertj.core.api.Condition; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface ResourceResponseValidator { + + static Builder builder() { + return new Builder(); + } + + void validate(ResourceResponse resourceResponse); + + class Builder { + private List> validators = new ArrayList<>(); + + public ResourceResponseValidator build() { + return new ResourceResponseValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(ResourceResponse resourceResponse) { + for (ResourceResponseValidator validator : validators) { + validator.validate(resourceResponse); + } + } + }; + } + + public Builder withId(final String resourceId) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().id()).as("check Resource Id").isEqualTo(resourceId); + } + }); + return this; + } + + public Builder nullResource() { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNull(); + } + }); + return this; + } + + public Builder withProperty(String propertyName, Condition validatingCondition) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().get(propertyName)).is(validatingCondition); + + } + }); + return this; + } + + public Builder withProperty(String propertyName, Object value) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().get(propertyName)).isEqualTo(value); + + } + }); + return this; + } + + + public Builder withTimestampIsAfterOrEqualTo(Instant time) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().timestamp()).isNotNull(); + OffsetDateTime d = resourceResponse.getResource().timestamp(); + System.out.println(d.toString()); + assertThat(d.toInstant()).isAfterOrEqualTo(time); + } + }); + return this; + } + + public Builder withTimestampIsBeforeOrEqualTo(Instant time) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().timestamp()).isNotNull(); + OffsetDateTime d = resourceResponse.getResource().timestamp(); + assertThat(d.toInstant()).isBeforeOrEqualTo(time); + } + }); + return this; + } + + public Builder withPermissionMode(PermissionMode mode) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getPermissionMode()).isEqualTo(mode); + } + }); + return this; + } + + public Builder withPermissionResourceLink(String link) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getResourceLink()).isEqualTo(link); + } + }); + return this; + } + + public Builder indexingMode(IndexingMode mode) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().getIndexingPolicy()).isNotNull(); + assertThat(resourceResponse.getResource().getIndexingPolicy().indexingMode()).isEqualTo(mode); + } + }); + return this; + } + + public Builder withStoredProcedureBody(String functionBody) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getBody()).isEqualTo(functionBody); + } + }); + return this; + } + + public Builder withUserDefinedFunctionBody(String functionBody) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getBody()).isEqualTo(functionBody); + } + }); + return this; + } + + + public Builder withTriggerBody(String functionBody) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getBody()).isEqualTo(functionBody); + } + }); + return this; + } + + public Builder notNullEtag() { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().etag()).isNotNull(); + } + }); + return this; + } + + public Builder notEmptySelfLink() { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().selfLink()).isNotEmpty(); + } + }); + return this; + } + + public Builder withTriggerInternals(TriggerType type, TriggerOperation op) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getTriggerType()).isEqualTo(type); + assertThat(resourceResponse.getResource().getTriggerOperation()).isEqualTo(op); + } + }); + return this; + } + + public Builder withOfferThroughput(int throughput) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource().getThroughput()) + .isEqualTo(throughput); + } + }); + return this; + } + + public Builder validatePropertyCondition(String key, Condition condition) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + assertThat(resourceResponse.getResource()).isNotNull(); + assertThat(resourceResponse.getResource().get(key)).is(condition); + + } + }); + return this; + } + + public Builder withCompositeIndexes(Collection> compositeIndexesWritten) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + Iterator> compositeIndexesReadIterator = resourceResponse.getResource() + .getIndexingPolicy().compositeIndexes().iterator(); + Iterator> compositeIndexesWrittenIterator = compositeIndexesWritten.iterator(); + + ArrayList readIndexesStrings = new ArrayList(); + ArrayList writtenIndexesStrings = new ArrayList(); + + while (compositeIndexesReadIterator.hasNext() && compositeIndexesWrittenIterator.hasNext()) { + Iterator compositeIndexReadIterator = compositeIndexesReadIterator.next().iterator(); + Iterator compositeIndexWrittenIterator = compositeIndexesWrittenIterator.next().iterator(); + + StringBuilder readIndexesString = new StringBuilder(); + StringBuilder writtenIndexesString = new StringBuilder(); + + while (compositeIndexReadIterator.hasNext() && compositeIndexWrittenIterator.hasNext()) { + CompositePath compositePathRead = compositeIndexReadIterator.next(); + CompositePath compositePathWritten = compositeIndexWrittenIterator.next(); + + readIndexesString.append(compositePathRead.path() + ":" + compositePathRead.order() + ";"); + writtenIndexesString.append(compositePathWritten.path() + ":" + compositePathRead.order() + ";"); + } + + readIndexesStrings.add(readIndexesString.toString()); + writtenIndexesStrings.add(writtenIndexesString.toString()); + } + + assertThat(readIndexesStrings).containsExactlyInAnyOrderElementsOf(writtenIndexesStrings); + } + }); + return this; + } + + public Builder withSpatialIndexes(Collection spatialIndexes) { + validators.add(new ResourceResponseValidator() { + + @Override + public void validate(ResourceResponse resourceResponse) { + Iterator spatialIndexesReadIterator = resourceResponse.getResource() + .getIndexingPolicy().spatialIndexes().iterator(); + Iterator spatialIndexesWrittenIterator = spatialIndexes.iterator(); + + HashMap> readIndexMap = new HashMap>(); + HashMap> writtenIndexMap = new HashMap>(); + + while (spatialIndexesReadIterator.hasNext() && spatialIndexesWrittenIterator.hasNext()) { + SpatialSpec spatialSpecRead = spatialIndexesReadIterator.next(); + SpatialSpec spatialSpecWritten = spatialIndexesWrittenIterator.next(); + + String readPath = spatialSpecRead.path() + ":"; + String writtenPath = spatialSpecWritten.path() + ":"; + + ArrayList readSpatialTypes = new ArrayList(); + ArrayList writtenSpatialTypes = new ArrayList(); + + Iterator spatialTypesReadIterator = spatialSpecRead.spatialTypes().iterator(); + Iterator spatialTypesWrittenIterator = spatialSpecWritten.spatialTypes().iterator(); + + while (spatialTypesReadIterator.hasNext() && spatialTypesWrittenIterator.hasNext()) { + readSpatialTypes.add(spatialTypesReadIterator.next()); + writtenSpatialTypes.add(spatialTypesWrittenIterator.next()); + } + + readIndexMap.put(readPath, readSpatialTypes); + writtenIndexMap.put(writtenPath, writtenSpatialTypes); + } + + for (Entry> entry : readIndexMap.entrySet()) { + assertThat(entry.getValue()) + .containsExactlyInAnyOrderElementsOf(writtenIndexMap.get(entry.getKey())); + } + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceValidator.java new file mode 100644 index 0000000000000..78a019628e461 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ResourceValidator.java @@ -0,0 +1,72 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface ResourceValidator { + + void validate(T v); + + class Builder { + private List> validators = new ArrayList<>(); + + public ResourceValidator build() { + return new ResourceValidator() { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void validate(T v) { + for (ResourceValidator validator : validators) { + validator.validate(v); + } + } + }; + } + + public Builder areEqual(T expectedValue) { + validators.add(new ResourceValidator() { + @Override + public void validate(T v) { + + assertThat(v.getMap().keySet()) + .describedAs("number of fields"). + hasSize(expectedValue.getMap().keySet().size()); + expectedValue.getMap().keySet(); + for(String key: expectedValue.getMap().keySet()) { + assertThat(expectedValue.get(key)) + .describedAs("value for " + key) + .isEqualTo(expectedValue.get(key)); + } + } + }); + return this; + } + + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryAnalyzer.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryAnalyzer.java new file mode 100644 index 0000000000000..1289516c55037 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryAnalyzer.java @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.TestConfigurations; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.ITestResult; +import org.testng.util.RetryAnalyzerCount; + +import java.util.concurrent.TimeUnit; + +public class RetryAnalyzer extends RetryAnalyzerCount { + private final Logger logger = LoggerFactory.getLogger(RetryAnalyzer.class); + private final int waitBetweenRetriesInSeconds = 120; + + public RetryAnalyzer() { + this.setCount(Integer.parseInt(TestConfigurations.MAX_RETRY_LIMIT)); + } + + @Override + public boolean retryMethod(ITestResult result) { + try { + TimeUnit.SECONDS.sleep(waitBetweenRetriesInSeconds); + } catch (InterruptedException e) { + return false; + } + + return true; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryCreateDocumentTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryCreateDocumentTest.java new file mode 100644 index 0000000000000..061694d03f1b3 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryCreateDocumentTest.java @@ -0,0 +1,194 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosError; +import com.google.common.collect.ImmutableMap; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.lang.reflect.Method; +import java.time.Duration; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doAnswer; + +public class RetryCreateDocumentTest extends TestSuiteBase { + + private SpyClientUnderTestFactory.ClientWithGatewaySpy client; + + private Database database; + private DocumentCollection collection; + + @Factory(dataProvider = "clientBuilders") + public RetryCreateDocumentTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void retryDocumentCreate() throws Exception { + // create a document to ensure collection is cached + client.createDocument(collection.selfLink(), getDocumentDefinition(), null, false).single().block(); + + Document docDefinition = getDocumentDefinition(); + + Flux> createObservable = client + .createDocument(collection.selfLink(), docDefinition, null, false); + AtomicInteger count = new AtomicInteger(); + + doAnswer((Answer>) invocation -> { + RxDocumentServiceRequest req = (RxDocumentServiceRequest) invocation.getArguments()[0]; + if (req.getOperationType() != OperationType.Create) { + return client.getOrigGatewayStoreModel().processMessage(req); + } + + int currentAttempt = count.getAndIncrement(); + if (currentAttempt == 0) { + Map header = ImmutableMap.of( + HttpConstants.HttpHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.PARTITION_KEY_MISMATCH)); + + return Flux.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.BADREQUEST, new CosmosError() , header)); + } else { + return client.getOrigGatewayStoreModel().processMessage(req); + } + }).when(client.getSpyGatewayStoreModel()).processMessage(anyObject()); + + // validate + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocument_noRetryOnNonRetriableFailure() throws Exception { + + AtomicInteger count = new AtomicInteger(); + doAnswer((Answer>) invocation -> { + RxDocumentServiceRequest req = (RxDocumentServiceRequest) invocation.getArguments()[0]; + + if (req.getResourceType() != ResourceType.Document) { + return client.getOrigGatewayStoreModel().processMessage(req); + } + + int currentAttempt = count.getAndIncrement(); + if (currentAttempt == 0) { + return client.getOrigGatewayStoreModel().processMessage(req); + } else { + Map header = ImmutableMap.of( + HttpConstants.HttpHeaders.SUB_STATUS, + Integer.toString(2)); + + return Flux.error(BridgeInternal.createCosmosClientException(1, new CosmosError() , header)); + } + }).when(client.getSpyGatewayStoreModel()).processMessage(anyObject()); + + // create a document to ensure collection is cached + client.createDocument(collection.selfLink(), getDocumentDefinition(), null, false) + .single() + .block(); + + Document docDefinition = getDocumentDefinition(); + + Flux> createObservable = client + .createDocument(collection.selfLink(), docDefinition, null, false); + + // validate + FailureValidator validator = new FailureValidator.Builder().statusCode(1).subStatusCode(2).build(); + validateFailure(createObservable, validator, TIMEOUT); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocument_failImmediatelyOnNonRetriable() throws Exception { + // create a document to ensure collection is cached + client.createDocument(collection.selfLink(), getDocumentDefinition(), null, false).single().block(); + AtomicInteger count = new AtomicInteger(); + + doAnswer((Answer>) invocation -> { + RxDocumentServiceRequest req = (RxDocumentServiceRequest) invocation.getArguments()[0]; + if (req.getOperationType() != OperationType.Create) { + return client.getOrigGatewayStoreModel().processMessage(req); + } + int currentAttempt = count.getAndIncrement(); + if (currentAttempt == 0) { + Map header = ImmutableMap.of( + HttpConstants.HttpHeaders.SUB_STATUS, + Integer.toString(2)); + + return Flux.error(BridgeInternal.createCosmosClientException(1, new CosmosError() , header)); + } else { + return client.getOrigGatewayStoreModel().processMessage(req); + } + }).when(client.getSpyGatewayStoreModel()).processMessage(anyObject()); + + Document docDefinition = getDocumentDefinition(); + + Flux> createObservable = client + .createDocument(collection.selfLink(), docDefinition, null, false); + // validate + + FailureValidator validator = new FailureValidator.Builder().statusCode(1).subStatusCode(2).build(); + validateFailure(createObservable.timeout(Duration.ofMillis(100)), validator); + } + + @BeforeMethod(groups = { "simple" }) + public void beforeMethod(Method method) { + Mockito.reset(client.getSpyGatewayStoreModel()); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + // set up the client + client = SpyClientUnderTestFactory.createClientWithGatewaySpy(clientBuilder()); + + database = SHARED_DATABASE; + collection = SHARED_SINGLE_PARTITION_COLLECTION; + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryThrottleTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryThrottleTest.java new file mode 100644 index 0000000000000..1f8e1c2fe381a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryThrottleTest.java @@ -0,0 +1,158 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.RetryOptions; +import org.mockito.stubbing.Answer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doAnswer; + +public class RetryThrottleTest extends TestSuiteBase { + private final static int TIMEOUT = 10000; + private final static int TOTAL_DOCS = 500; + private final static int LARGE_TIMEOUT = 30000; + + private SpyClientUnderTestFactory.ClientWithGatewaySpy client; + private Database database; + private DocumentCollection collection; + + @Test(groups = { "long" }, timeOut = LARGE_TIMEOUT, enabled = false) + public void retryCreateDocumentsOnSpike() throws Exception { + ConnectionPolicy policy = new ConnectionPolicy(); + RetryOptions retryOptions = new RetryOptions(); + retryOptions.maxRetryAttemptsOnThrottledRequests(Integer.MAX_VALUE); + retryOptions.maxRetryWaitTimeInSeconds(LARGE_TIMEOUT); + policy.retryOptions(retryOptions); + + AsyncDocumentClient.Builder builder = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(policy) + .withConsistencyLevel(ConsistencyLevel.EVENTUAL); + + client = SpyClientUnderTestFactory.createClientWithGatewaySpy(builder); + + // create a document to ensure collection is cached + client.createDocument(getCollectionLink(collection), getDocumentDefinition(), null, false).blockFirst(); + + List>> list = new ArrayList<>(); + for(int i = 0; i < TOTAL_DOCS; i++) { + Flux> obs = client.createDocument(getCollectionLink(collection), getDocumentDefinition(), null, false); + list.add(obs); + } + + // registers a spy to count number of invocation + AtomicInteger totalCount = new AtomicInteger(); + AtomicInteger successCount = new AtomicInteger(); + + doAnswer((Answer>) invocation -> { + RxDocumentServiceRequest req = (RxDocumentServiceRequest) invocation.getArguments()[0]; + if (req.getResourceType() == ResourceType.Document && req.getOperationType() == OperationType.Create) { + // increment the counter per Document CREATE operations + totalCount.incrementAndGet(); + } + return client.getOrigGatewayStoreModel().processMessage(req).doOnNext(rsp -> successCount.incrementAndGet()); + }).when(client.getSpyGatewayStoreModel()).processMessage(anyObject()); + + List> rsps = Flux.merge(Flux.fromIterable(list), 100).collectList().single().block(); + System.out.println("total: " + totalCount.get()); + assertThat(rsps).hasSize(TOTAL_DOCS); + assertThat(successCount.get()).isEqualTo(TOTAL_DOCS); + System.out.println("total count is " + totalCount.get()); + } + + @Test(groups = { "long" }, timeOut = TIMEOUT, enabled = false) + public void retryDocumentCreate() throws Exception { + client = SpyClientUnderTestFactory.createClientWithGatewaySpy(createGatewayRxDocumentClient()); + + // create a document to ensure collection is cached + client.createDocument(getCollectionLink(collection), getDocumentDefinition(), null, false).blockFirst(); + + Document docDefinition = getDocumentDefinition(); + + Flux> createObservable = client + .createDocument(collection.selfLink(), docDefinition, null, false); + AtomicInteger count = new AtomicInteger(); + + doAnswer((Answer>) invocation -> { + RxDocumentServiceRequest req = (RxDocumentServiceRequest) invocation.getArguments()[0]; + if (req.getOperationType() != OperationType.Create) { + return client.getOrigGatewayStoreModel().processMessage(req); + } + int currentAttempt = count.getAndIncrement(); + if (currentAttempt == 0) { + return Flux.error(BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.TOO_MANY_REQUESTS)); + } else { + return client.getOrigGatewayStoreModel().processMessage(req); + } + }).when(client.getSpyGatewayStoreModel()).processMessage(anyObject()); + + // validate + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator, TIMEOUT); + } + + @AfterMethod(groups = { "long" }, enabled = false) + private void afterMethod() { + safeClose(client); + } + + @BeforeClass(groups = { "long" }, timeOut = SETUP_TIMEOUT, enabled = false) + public void beforeClass() { + // set up the client + database = SHARED_DATABASE; + collection = SHARED_SINGLE_PARTITION_COLLECTION; + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + @AfterClass(groups = { "long" }, timeOut = SHUTDOWN_TIMEOUT, enabled = false) + public void afterClass() { + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryUtilsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryUtilsTest.java new file mode 100644 index 0000000000000..9d4a156948f42 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RetryUtilsTest.java @@ -0,0 +1,158 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponseValidator; +import com.azure.data.cosmos.internal.IRetryPolicy.ShouldRetryResult; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class RetryUtilsTest { + IRetryPolicy retryPolicy; + Function, Mono> callbackMethod; + Function, Mono> inBackoffAlternateCallbackMethod; + private static final Duration minBackoffForInBackoffCallback = Duration.ofMillis(10); + private static final int TIMEOUT = 30000; + private static final Duration BACK_OFF_DURATION = Duration.ofMillis(20); + private StoreResponse storeResponse; + + @BeforeClass(groups = { "unit" }) + public void beforeClass() throws Exception { + retryPolicy = Mockito.mock(IRetryPolicy.class); + callbackMethod = Mockito.mock(Function.class); + inBackoffAlternateCallbackMethod = Mockito.mock(Function.class); + storeResponse = getStoreResponse(); + } + + /** + * This method will make sure we are throwing original exception in case of + * ShouldRetryResult.noRetry() instead of Single.error(null). + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void toRetryWithAlternateFuncWithNoRetry() { + Function> onErrorFunc = RetryUtils.toRetryWithAlternateFunc(callbackMethod, + retryPolicy, inBackoffAlternateCallbackMethod, minBackoffForInBackoffCallback); + Mockito.when(retryPolicy.shouldRetry(Matchers.any())).thenReturn(Mono.just(ShouldRetryResult.noRetry())); + Mono response = onErrorFunc.apply(new GoneException()); + validateFailure(response, TIMEOUT, GoneException.class); + } + + /** + * This method will test retries on callbackMethod, eventually returning success + * response after some failures and making sure it failed for at least specific + * number before passing. + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void toRetryWithAlternateFuncTestingMethodOne() { + Function> onErrorFunc = RetryUtils.toRetryWithAlternateFunc(callbackMethod, + retryPolicy, null, minBackoffForInBackoffCallback); + + toggleMockFuncBtwFailureSuccess(callbackMethod); + Mockito.when(retryPolicy.shouldRetry(Matchers.any())) + .thenReturn(Mono.just(ShouldRetryResult.retryAfter(BACK_OFF_DURATION))); + Mono response = onErrorFunc.apply(new GoneException()); + StoreResponseValidator validator = StoreResponseValidator.create().withStatus(storeResponse.getStatus()) + .withContent(storeResponse.getResponseBody()).build(); + validateSuccess(response, validator, TIMEOUT); + Mockito.verify(callbackMethod, Mockito.times(4)).apply(Matchers.any()); + } + + /** + * This method will test retries on inBackoffAlternateCallbackMethod, eventually + * returning success response after some failures and making sure it failed for + * at least specific number before passing. + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void toRetryWithAlternateFuncTestingMethodTwo() { + Function> onErrorFunc = RetryUtils.toRetryWithAlternateFunc(callbackMethod, + retryPolicy, inBackoffAlternateCallbackMethod, minBackoffForInBackoffCallback); + Mockito.when(callbackMethod.apply(Matchers.any())).thenReturn(Mono.error(new GoneException())); + toggleMockFuncBtwFailureSuccess(inBackoffAlternateCallbackMethod); + Mockito.when(retryPolicy.shouldRetry(Matchers.any())) + .thenReturn(Mono.just(ShouldRetryResult.retryAfter(BACK_OFF_DURATION))); + Mono response = onErrorFunc.apply(new GoneException()); + StoreResponseValidator validator = StoreResponseValidator.create().withStatus(storeResponse.getStatus()) + .withContent(storeResponse.getResponseBody()).build(); + validateSuccess(response, validator, TIMEOUT); + Mockito.verify(inBackoffAlternateCallbackMethod, Mockito.times(4)).apply(Matchers.any()); + } + + private void validateFailure(Mono single, long timeout, Class class1) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + if (!(testSubscriber.getEvents().get(1).get(0).getClass().equals(class1))) { + fail("Not expecting " + testSubscriber.getEvents().get(1).get(0)); + } + } + + private void validateSuccess(Mono single, StoreResponseValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + assertThat(testSubscriber.valueCount()).isEqualTo(1); + validator.validate(testSubscriber.values().get(0)); + } + + private void toggleMockFuncBtwFailureSuccess( + Function, Mono> method) { + Mockito.when(method.apply(Matchers.any())).thenAnswer(new Answer>() { + + private int count = 0; + + @Override + public Mono answer(InvocationOnMock invocation) throws Throwable { + if (count++ < 3) { + return Mono.error(new GoneException()); + } + return Mono.just(storeResponse); + } + }); + } + + private StoreResponse getStoreResponse() { + StoreResponseBuilder storeResponseBuilder = new StoreResponseBuilder().withContent("Test content") + .withStatus(200); + return storeResponseBuilder.build(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentClientUnderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentClientUnderTest.java new file mode 100644 index 0000000000000..f7415164cfd3e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentClientUnderTest.java @@ -0,0 +1,86 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ClientUnderTestBuilder; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.mockito.Mockito.doAnswer; + +/** + * This class in conjunction with {@link ClientUnderTestBuilder} + * provides the functionality for spying the client behavior and the http requests sent. + */ +public class RxDocumentClientUnderTest extends RxDocumentClientImpl { + + public HttpClient spyHttpClient; + public HttpClient origHttpClient; + + public List httpRequests = Collections.synchronizedList(new ArrayList<>()); + + public RxDocumentClientUnderTest(URI serviceEndpoint, + String masterKey, + ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, + Configs configs) { + super(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, configs); + init(); + } + + RxGatewayStoreModel createRxGatewayProxy( + ISessionContainer sessionContainer, + ConsistencyLevel consistencyLevel, + QueryCompatibilityMode queryCompatibilityMode, + UserAgentContainer userAgentContainer, + GlobalEndpointManager globalEndpointManager, + HttpClient rxOrigClient) { + + origHttpClient = rxOrigClient; + spyHttpClient = Mockito.spy(rxOrigClient); + + doAnswer((Answer>) invocationOnMock -> { + HttpRequest httpRequest = invocationOnMock.getArgumentAt(0, HttpRequest.class); + httpRequests.add(httpRequest); + return origHttpClient.send(httpRequest); + }).when(spyHttpClient).send(Mockito.any(HttpRequest.class)); + + return super.createRxGatewayProxy(sessionContainer, + consistencyLevel, + queryCompatibilityMode, + userAgentContainer, + globalEndpointManager, + spyHttpClient); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentServiceRequestTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentServiceRequestTest.java new file mode 100644 index 0000000000000..f6463cd8530cd --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxDocumentServiceRequestTest.java @@ -0,0 +1,450 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.apache.commons.collections4.map.HashedMap; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RxDocumentServiceRequestTest { + + private final static String DOCUMENT_DEFINITION = "{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + "}"; + private static final String PARTITION_KEY_VALUE = "1"; + + private final String DOCUMENT_URL_WITH_ID = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/"; + private final String DOCUMENT_URL_WITH_NAME = "/dbs/testDB/colls/testColl/docs/testDoc/"; + private final String DOCUMENT_URL_WITH_ID_WITHOUT_SLASH = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/"; + private final String DOCUMENT_URL_WITH_NAME_WITHOUT_SLASH = "dbs/testDB/colls/testColl/docs/testDoc/"; + + private static final String DATABASE_URL = "/dbs/IXYFAA==/"; + private static final String DOCUMENT_COLLECTION_URL = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/"; + private static final String STORED_PRCEDURE_URL = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/sprocs/IXYFAOHEBPMCAAAAAAAAgA==/"; + private static final String USER_DEFINED_FUNCTION_URL = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/udfs/IXYFAOHEBPMBAAAAAAAAYA==/"; + private static final String USER_URL = "/dbs/IXYFAA==/users/IXYFAE9ZOwA=/"; + private static final String PERMISSION_URL = "/dbs/IXYFAA==/users/IXYFAE9ZOwA=/permissions/IXYFAE9ZOwBGkyqWIsNKAA==/"; + private static final String ATTACHMENT_URL = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/attachments/IXYFAOHEBPMBAAAAAAAAABJYSJk=/"; + private static final String TRIGGER_URL = "/dbs/IXYFAA==/colls/IXYFAOHEBPM=/triggers/IXYFAOHEBPMCAAAAAAAAcA==/"; + private static final String CONFLICT_URL = "/dbs/k6d9AA==/colls/k6d9ALgBmD8=/conflicts/k6d9ALgBmD8BAAAAAAAAQA==/"; + + @DataProvider(name = "documentUrl") + public Object[][] documentUrlWithId() { + return new Object[][] { { DOCUMENT_URL_WITH_ID, DOCUMENT_URL_WITH_NAME, OperationType.Read }, + { DOCUMENT_URL_WITH_ID, DOCUMENT_URL_WITH_NAME, OperationType.Delete }, + { DOCUMENT_URL_WITH_ID, DOCUMENT_URL_WITH_NAME, OperationType.Replace }, + { DOCUMENT_URL_WITH_ID_WITHOUT_SLASH, DOCUMENT_URL_WITH_NAME_WITHOUT_SLASH, OperationType.Read }, + { DOCUMENT_URL_WITH_ID_WITHOUT_SLASH, DOCUMENT_URL_WITH_NAME_WITHOUT_SLASH, OperationType.Delete }, + { DOCUMENT_URL_WITH_ID_WITHOUT_SLASH, DOCUMENT_URL_WITH_NAME_WITHOUT_SLASH, OperationType.Replace }, }; + } + + @DataProvider(name = "resourceUrlWithOperationType") + public Object[][] resourceOperation() { + return new Object[][] { { DATABASE_URL, ResourceType.Database, OperationType.Read }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Read }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Read }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Read }, + { USER_URL, ResourceType.User, OperationType.Read }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Read }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Read }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Read }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Read }, + + { DATABASE_URL, ResourceType.Database, OperationType.Create }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Create }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Create }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Create }, + { USER_URL, ResourceType.User, OperationType.Create }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Create }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Create }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Create }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Create }, + + { DATABASE_URL, ResourceType.Database, OperationType.Delete }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Delete }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Delete }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Delete }, + { USER_URL, ResourceType.User, OperationType.Delete }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Delete }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Delete }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Delete }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Delete }, + + { DATABASE_URL, ResourceType.Database, OperationType.Replace }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Replace }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Replace }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Replace }, + { USER_URL, ResourceType.User, OperationType.Replace }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Replace }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Replace }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Replace }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Replace }, + + { DATABASE_URL, ResourceType.Database, OperationType.Query }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Query }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Query }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Query }, + { USER_URL, ResourceType.User, OperationType.Query }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Query }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Query }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Query }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Query }, + + { DATABASE_URL, ResourceType.Database, OperationType.Update }, + { DOCUMENT_COLLECTION_URL, ResourceType.DocumentCollection, OperationType.Update }, + { STORED_PRCEDURE_URL, ResourceType.StoredProcedure, OperationType.Update }, + { USER_DEFINED_FUNCTION_URL, ResourceType.UserDefinedFunction, OperationType.Update }, + { USER_URL, ResourceType.User, OperationType.Update }, + { PERMISSION_URL, ResourceType.Permission, OperationType.Update }, + { ATTACHMENT_URL, ResourceType.Attachment, OperationType.Update }, + { TRIGGER_URL, ResourceType.Trigger, OperationType.Update }, + { CONFLICT_URL, ResourceType.Conflict, OperationType.Update } }; + } + + @DataProvider(name = "resourceIdOrFullNameRequestAndOperationTypeData") + public Object[][] resourceIdOrFullNameRequestAndOperationTypeData() { + return new Object[][]{ + {"IXYFAA==", "dbs/testDB", ResourceType.Database, OperationType.Read}, + {"IXYFAA==", "dbs/testDB", ResourceType.Database, OperationType.Create}, + + {"IXYFAOHEBPM=", "dbs/testDB/colls/testColl", ResourceType.DocumentCollection, OperationType.Read}, + {"IXYFAOHEBPM=", "dbs/testDB/colls/testColl", ResourceType.DocumentCollection, OperationType.Create}, + {"IXYFAOHEBPM=", "dbs/testDB/colls/testColl", ResourceType.DocumentCollection, OperationType.Delete}, + {"IXYFAOHEBPM=", "dbs/testDB/colls/testColl", ResourceType.DocumentCollection, OperationType.Query}, + + {"IXYFAOHEBPMBAAAAAAAAAA==", "dbs/testDB/colls/testColl/docs/testDoc", ResourceType.Document, OperationType.Read}, + {"IXYFAOHEBPMBAAAAAAAAAA==", "dbs/testDB/colls/testColl/docs/testDoc", ResourceType.Document, OperationType.Create}, + {"IXYFAOHEBPMBAAAAAAAAAA==", "dbs/testDB/colls/testColl/docs/testDoc", ResourceType.Document, OperationType.Delete}, + {"IXYFAOHEBPMBAAAAAAAAAA==", "dbs/testDB/colls/testColl/docs/testDoc", ResourceType.Document, OperationType.Query}, + }; + } + + /** + * This test case will cover various create methods through resource url with Id in detail for document resource. + * @param documentUrlWithId Document url with id + * @param documentUrlWithName Document url with name + * @param operationType Operation type + */ + @Test(groups = { "unit" }, dataProvider = "documentUrl") + public void createWithResourceIdURL(String documentUrlWithId, String documentUrlWithName, + OperationType operationType) { + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithId, + new HashedMap(), AuthorizationTokenType.PrimaryMasterKey); + + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getResourceAddress()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getResourceId()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + + request = RxDocumentServiceRequest.create(operationType, "IXYFAOHEBPMBAAAAAAAAAA==", ResourceType.Document, + new HashedMap(), AuthorizationTokenType.PrimaryReadonlyMasterKey); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryReadonlyMasterKey); + assertThat(request.getResourceAddress()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getResourceId()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + + Document document = getDocumentDefinition(); + request = RxDocumentServiceRequest.create(operationType, document, ResourceType.Document, documentUrlWithId, + new HashedMap(), AuthorizationTokenType.Invalid); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.Invalid); + assertThat(request.getResourceAddress()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getResourceId()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getContent()).isEqualTo(document.toJson().getBytes(StandardCharsets.UTF_8)); + + Flux inputStream = Flux.just(document.toJson().getBytes(StandardCharsets.UTF_8)); + request = RxDocumentServiceRequest.create(operationType, ResourceType.Document, documentUrlWithId, inputStream, + new HashedMap(), AuthorizationTokenType.SecondaryMasterKey); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.SecondaryMasterKey); + assertThat(request.getResourceAddress()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getResourceId()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getContentObservable()).isEqualTo(inputStream); + + // Creating one request without giving AuthorizationTokenType , it should take + // PrimaryMasterKey by default + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithId, + new HashedMap()); + + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getResourceAddress()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + assertThat(request.getResourceId()).isEqualTo("IXYFAOHEBPMBAAAAAAAAAA=="); + + } + + /** + * This test case will cover various create method through resource url with name in detail for document resource. + * @param documentUrlWithId Document url with id + * @param documentUrlWithName Document url with name + * @param operationType Operation type + */ + @Test(groups = { "unit" }, dataProvider = "documentUrl") + public void createWithResourceNameURL(String documentUrlWithId, String documentUrlWithName, + OperationType operationType) { + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithName, + new HashedMap(), AuthorizationTokenType.PrimaryMasterKey); + + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getResourceAddress()) + .isEqualTo(StringUtils.removeEnd(StringUtils.removeStart(documentUrlWithName, Paths.ROOT), Paths.ROOT)); + assertThat(request.getResourceId()).isNull(); + + Document document = getDocumentDefinition(); + Flux inputStream = Flux.just(document.toJson().getBytes(StandardCharsets.UTF_8)); + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithName, + inputStream, + new HashedMap(), + AuthorizationTokenType.SecondaryMasterKey); + + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.SecondaryMasterKey); + assertThat(request.getResourceAddress()) + .isEqualTo(StringUtils.removeEnd(StringUtils.removeStart(documentUrlWithName, Paths.ROOT), Paths.ROOT)); + assertThat(request.getResourceId()).isNull(); + assertThat(request.getContentObservable()).isEqualTo(inputStream); + + // Creating one request without giving AuthorizationTokenType , it should take + // PrimaryMasterKey by default + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithName, + new HashedMap()); + + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getResourceAddress()) + .isEqualTo(StringUtils.removeEnd(StringUtils.removeStart(documentUrlWithName, Paths.ROOT), Paths.ROOT)); + assertThat(request.getResourceId()).isNull(); + } + + + /** + * This will cover sanity for most of the combination of different source with various + * operation. + * @param resourceUrl Resource Url + * @param resourceType Resource Type + * @param operationType Operation type + */ + @Test(groups = { "unit" }, dataProvider = "resourceUrlWithOperationType") + public void createDifferentResourceRequestWithDiffOperation(String resourceUrl, ResourceType resourceType, + OperationType operationType) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, resourceType, resourceUrl, + new HashedMap(), AuthorizationTokenType.PrimaryMasterKey); + assertThat(resourceUrl.contains(request.getResourceAddress())).isTrue(); + assertThat(resourceUrl.contains(request.getResourceId())).isTrue(); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.getHeaders()).isNotNull(); + } + + /** + * This will test all the create method without request path. + * + * @param resourceId Resource id + * @param resourceType Resource Type + * @param operationType Operation type + */ + @Test(groups = {"unit"}, dataProvider = "resourceIdOrFullNameRequestAndOperationTypeData") + public void createRequestWithoutPath(String resourceId, String resourceFullName, ResourceType resourceType, + OperationType operationType) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, resourceId, resourceType, null); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceId); + assertThat(request.getResourceId()).isEqualTo(resourceId); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + + + request = RxDocumentServiceRequest.create(operationType, resourceId, resourceType, null, AuthorizationTokenType.ResourceToken); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceId); + assertThat(request.getResourceId()).isEqualTo(resourceId); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.ResourceToken); + + Document document = getDocumentDefinition(); + request = RxDocumentServiceRequest.create(operationType, resourceId, resourceType, document, null); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceId); + assertThat(request.getResourceId()).isEqualTo(resourceId); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getContent()).isEqualTo(document.toJson().getBytes(StandardCharsets.UTF_8)); + + request = RxDocumentServiceRequest.create(operationType, resourceId, resourceType, document, null, AuthorizationTokenType.ResourceToken); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceId); + assertThat(request.getResourceId()).isEqualTo(resourceId); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.ResourceToken); + assertThat(request.getContent()).isEqualTo(document.toJson().getBytes(StandardCharsets.UTF_8)); + + request = RxDocumentServiceRequest.createFromName(operationType, resourceFullName, resourceType); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceFullName); + assertThat(request.getResourceId()).isNull(); + assertThat(request.getIsNameBased()).isTrue(); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + + request = RxDocumentServiceRequest.createFromName(operationType, resourceFullName, resourceType, AuthorizationTokenType.ResourceToken); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceFullName); + assertThat(request.getResourceId()).isNull(); + assertThat(request.getIsNameBased()).isTrue(); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.ResourceToken); + + request = RxDocumentServiceRequest.createFromName(operationType, document, resourceFullName, resourceType); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceFullName); + assertThat(request.getResourceId()).isNull(); + assertThat(request.getIsNameBased()).isTrue(); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.PrimaryMasterKey); + assertThat(request.getContent()).isEqualTo(document.toJson().getBytes(StandardCharsets.UTF_8)); + + request = RxDocumentServiceRequest.createFromName(operationType, document, resourceFullName, resourceType, AuthorizationTokenType.ResourceToken); + assertThat(request.getHeaders()).isNotNull(); + assertThat(request.getResourceAddress()).isEqualTo(resourceFullName); + assertThat(request.getResourceId()).isNull(); + assertThat(request.getIsNameBased()).isTrue(); + assertThat(request.getResourceType()).isEqualTo(resourceType); + assertThat(request.getOperationType()).isEqualTo(operationType); + assertThat(request.authorizationTokenType).isEqualTo(AuthorizationTokenType.ResourceToken); + assertThat(request.getContent()).isEqualTo(document.toJson().getBytes(StandardCharsets.UTF_8)); + } + + @Test(groups = { "unit" }, dataProvider = "documentUrl") + public void isValidAddress(String documentUrlWithId, String documentUrlWithName, OperationType operationType) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithId, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Database)).isTrue(); + assertThat(request.isValidAddress(ResourceType.DocumentCollection)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Document)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + assertThat(request.isValidAddress(ResourceType.User)).isFalse(); + assertThat(request.isValidAddress(ResourceType.Trigger)).isFalse(); + assertThat(request.isValidAddress(ResourceType.Offer)).isFalse(); + assertThat(request.isValidAddress(ResourceType.Permission)).isFalse(); + assertThat(request.isValidAddress(ResourceType.Attachment)).isFalse(); + assertThat(request.isValidAddress(ResourceType.StoredProcedure)).isFalse(); + assertThat(request.isValidAddress(ResourceType.Conflict)).isFalse(); + assertThat(request.isValidAddress(ResourceType.PartitionKeyRange)).isFalse(); + + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Document)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + String collectionFullName = "/dbs/testDB/colls/testColl/"; + request = RxDocumentServiceRequest.create(operationType, ResourceType.DocumentCollection, collectionFullName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.DocumentCollection)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + + String databaseFullName = "/dbs/testDB"; + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Database, + databaseFullName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Database)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + + String permissionFullName = "/dbs/testDB/users/testUser/permissions/testPermission"; + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Permission, + permissionFullName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Permission)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + + String triggerFullName = "/dbs/testDB/colls/testUser/triggers/testTrigger"; + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Trigger, + triggerFullName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Trigger)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + + String attachmentFullName = "/dbs/testDB/colls/testUser/docs/testDoc/attachments/testAttachment"; + request = RxDocumentServiceRequest.create(operationType, + ResourceType.Attachment, + attachmentFullName, + new HashedMap()); + + assertThat(request.isValidAddress(ResourceType.Attachment)).isTrue(); + assertThat(request.isValidAddress(ResourceType.Unknown)).isTrue(); + } + + @Test(groups = { "unit" }, dataProvider = "documentUrl") + public void addPreferHeader(String documentUrlWithId, String documentUrlWithName, OperationType operationType) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(operationType, + ResourceType.Document, + documentUrlWithId, + new HashedMap()); + + request.addPreferHeader("preferHeaderName1", "preferHeaderValue1"); + assertThat(request.getHeaders().size()).isEqualTo(1); + assertThat(request.getHeaders().get(HttpConstants.HttpHeaders.PREFER)) + .isEqualTo("preferHeaderName1=preferHeaderValue1"); + + request.addPreferHeader("preferHeaderName2", "preferHeaderValue2"); + assertThat(request.getHeaders().size()).isEqualTo(1); + assertThat(request.getHeaders().get(HttpConstants.HttpHeaders.PREFER)) + .isEqualTo("preferHeaderName1=preferHeaderValue1;" + "preferHeaderName2=preferHeaderValue2"); + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format(DOCUMENT_DEFINITION, uuid, PARTITION_KEY_VALUE)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxGatewayStoreModelTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxGatewayStoreModelTest.java new file mode 100644 index 0000000000000..41579731c3f5d --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/RxGatewayStoreModelTest.java @@ -0,0 +1,96 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpRequest; +import io.netty.handler.timeout.ReadTimeoutException; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +; + +public class RxGatewayStoreModelTest { + private final static int TIMEOUT = 10000; + + @Test(groups = "unit") + public void readTimeout() throws Exception { + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + QueryCompatibilityMode queryCompatibilityMode = QueryCompatibilityMode.Default; + UserAgentContainer userAgentContainer = new UserAgentContainer(); + GlobalEndpointManager globalEndpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(new URL("https://localhost")) + .when(globalEndpointManager).resolveServiceEndpoint(Mockito.any()); + HttpClient httpClient = Mockito.mock(HttpClient.class); + Mockito.doReturn(Mono.error(ReadTimeoutException.INSTANCE)) + .when(httpClient).send(Mockito.any(HttpRequest.class)); + + RxGatewayStoreModel storeModel = new RxGatewayStoreModel( + sessionContainer, + ConsistencyLevel.SESSION, + queryCompatibilityMode, + userAgentContainer, + globalEndpointManager, + httpClient); + + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put("key", "value"); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + Flux resp = storeModel.processMessage(dsr); + validateFailure(resp, FailureValidator.builder() + .instanceOf(CosmosClientException.class) + .causeInstanceOf(ReadTimeoutException.class) + .documentClientExceptionHeaderRequestContainsEntry("key", "value") + .statusCode(0).build()); + } + + public void validateFailure(Flux observable, + FailureValidator validator) { + validateFailure(observable, validator, TIMEOUT); + } + + public static void validateFailure(Flux observable, + FailureValidator validator, + long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionContainerTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionContainerTest.java new file mode 100644 index 0000000000000..170de82b96921 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionContainerTest.java @@ -0,0 +1,640 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.GatewayTestUtils; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.mockito.Mockito; +import org.mockito.internal.util.collections.Sets; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link SessionContainer} + */ +public class SessionContainerTest { + + private final static Random random = new Random(); + + @Test(groups = "unit") + public void sessionContainer() throws Exception { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + + int numCollections = 2; + int numPartitionKeyRangeIds = 5; + + for (int i = 0; i < numCollections; i++) { + String collectionResourceId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId() + i).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls/collName_" + i; + + for (int j = 0; j < numPartitionKeyRangeIds; j++) { + + String partitionKeyRangeId = "range_" + j; + String lsn = "1#" + j + "#4=90#5=2"; + + sessionContainer.setSessionToken( + collectionResourceId, + collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":" + lsn)); + } + } + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.ReadFeed, ResourceType.DocumentCollection, + "dbs/db1/colls/collName_1", IOUtils.toInputStream("content1", "UTF-8"), new HashMap<>()); + + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_1"); + assertThat(sessionToken.getLSN()).isEqualTo(1); + + DocumentServiceRequestContext dsrContext = new DocumentServiceRequestContext(); + PartitionKeyRange resolvedPKRange = new PartitionKeyRange(); + resolvedPKRange.id("range_" + (numPartitionKeyRangeIds + 10)); + GatewayTestUtils.setParent(resolvedPKRange, ImmutableList.of("range_2", "range_x")); + dsrContext.resolvedPartitionKeyRange = resolvedPKRange; + request.requestContext = dsrContext; + + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, resolvedPKRange.id()); + assertThat(sessionToken.getLSN()).isEqualTo(2); + } + + @Test(groups = "unit") + public void setSessionToken_NoSessionTokenForPartitionKeyRangeId() throws Exception { + String collectionRid = "uf4PAK6T-Cw="; + long collectionRidAsLong = ResourceId.parse(collectionRid).getUniqueDocumentCollectionId(); + String partitionKeyRangeId = "test_range_id"; + String sessionToken = "1#100#1=20#2=5#3=30"; + String collectionName = "dbs/db1/colls/collName_1"; + + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + + RxDocumentServiceRequest request1 = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionName + "/docs", IOUtils.toInputStream("content1", "UTF-8"), new HashMap<>()); + + Map respHeaders = new HashMap<>(); + RxDocumentServiceResponse resp = Mockito.mock(RxDocumentServiceResponse.class); + Mockito.doReturn(respHeaders).when(resp).getResponseHeaders(); + respHeaders.put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":" + sessionToken); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_FULL_NAME, collectionName); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_ID, collectionRid); + sessionContainer.setSessionToken(request1, resp.getResponseHeaders()); + + ConcurrentHashMap collectionNameToCollectionResourceId = (ConcurrentHashMap) FieldUtils.readField(sessionContainer, "collectionNameToCollectionResourceId", true); + ConcurrentHashMap> collectionResourceIdToSessionTokens = (ConcurrentHashMap>) FieldUtils.readField(sessionContainer, "collectionResourceIdToSessionTokens", true); + assertThat(collectionNameToCollectionResourceId).hasSize(1); + assertThat(collectionResourceIdToSessionTokens).hasSize(1); + assertThat(collectionNameToCollectionResourceId.get(collectionName)).isEqualTo(collectionRidAsLong); + assertThat(collectionResourceIdToSessionTokens.get(collectionRidAsLong)).isNotNull(); + assertThat(collectionResourceIdToSessionTokens.get(collectionRidAsLong)).hasSize(1); + assertThat(collectionResourceIdToSessionTokens.get(collectionRidAsLong).get(partitionKeyRangeId).convertToString()).isEqualTo(sessionToken); + + RxDocumentServiceRequest request2 = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document, + collectionName + "/docs", IOUtils.toInputStream("", "UTF-8"), new HashMap<>()); + + ISessionToken resolvedSessionToken = sessionContainer.resolvePartitionLocalSessionToken(request2, partitionKeyRangeId); + assertThat(resolvedSessionToken.convertToString()).isEqualTo(sessionToken); + } + + @Test(groups = "unit") + public void setSessionToken_MergeOldWithNew() throws Exception { + String collectionRid = "uf4PAK6T-Cw="; + String collectionName = "dbs/db1/colls/collName_1"; + String initialSessionToken = "1#100#1=20#2=5#3=30"; + String newSessionTokenInServerResponse = "1#100#1=31#2=5#3=21"; + String partitionKeyRangeId = "test_range_id"; + String expectedMergedSessionToken = "1#100#1=31#2=5#3=30"; + + Map respHeaders = new HashMap<>(); + + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + + RxDocumentServiceRequest request1 = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionName + "/docs", IOUtils.toInputStream("content1", "UTF-8"), new HashMap<>()); + + RxDocumentServiceResponse resp = Mockito.mock(RxDocumentServiceResponse.class); + Mockito.doReturn(respHeaders).when(resp).getResponseHeaders(); + respHeaders.put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":" + initialSessionToken); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_FULL_NAME, collectionName); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_ID, collectionRid); + sessionContainer.setSessionToken(request1, resp.getResponseHeaders()); + + resp = Mockito.mock(RxDocumentServiceResponse.class); + Mockito.doReturn(respHeaders).when(resp).getResponseHeaders(); + respHeaders.put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":" + newSessionTokenInServerResponse); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_FULL_NAME, collectionName); + respHeaders.put(HttpConstants.HttpHeaders.OWNER_ID, collectionRid); + sessionContainer.setSessionToken(request1, resp.getResponseHeaders()); + + RxDocumentServiceRequest request2 = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document, + collectionName + "/docs", IOUtils.toInputStream("", "UTF-8"), new HashMap<>()); + + ISessionToken resolvedSessionToken = sessionContainer.resolvePartitionLocalSessionToken(request2, partitionKeyRangeId); + assertThat(resolvedSessionToken.convertToString()).isEqualTo(expectedMergedSessionToken); + } + + + @Test(groups = "unit") + public void resolveGlobalSessionTokenReturnsEmptyStringOnEmptyCache() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document, + "dbs/db1/colls/collName/docs/doc1", new HashMap<>()); + assertThat(StringUtils.EMPTY).isEqualTo(sessionContainer.resolveGlobalSessionToken(request)); + } + + @Test(groups = "unit") + public void resolveGlobalSessionTokenReturnsEmptyStringOnCacheMiss() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String partitionKeyRangeId = "range_0"; + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String initialSessionToken = "1#100#1=20#2=5#3=30"; + sessionContainer.setSessionToken(documentCollectionId, "dbs/db1/colls1/collName", + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":" + initialSessionToken)); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document, + "dbs/db1/colls1/collName2/docs/doc1", new HashMap<>()); + assertThat(StringUtils.EMPTY).isEqualTo(sessionContainer.resolveGlobalSessionToken(request)); + } + + @Test(groups = "unit") + public void resolveGlobalSessionTokenReturnsTokenMapUsingName() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + String sessionToken = sessionContainer.resolveGlobalSessionToken(request); + Set tokens = Sets.newSet(sessionToken.split(",")); + + assertThat(tokens.size()).isEqualTo(2); + assertThat(tokens.contains("range_0:1#100#1=20#2=5#3=30")).isTrue(); + assertThat(tokens.contains("range_1:1#101#1=20#2=5#3=30")).isTrue(); + } + + @Test(groups = "unit") + public void resolveGlobalSessionTokenReturnsTokenMapUsingResourceId() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + String sessionToken = sessionContainer.resolveGlobalSessionToken(request); + + Set tokens = Sets.newSet(sessionToken.split(",")); + assertThat(tokens.size()).isEqualTo(2); + assertThat(tokens.contains("range_0:1#100#1=20#2=5#3=30")).isTrue(); + assertThat(tokens.contains("range_1:1#101#1=20#2=5#3=30")).isTrue(); + } + + + @Test(groups = "unit") + public void resolveLocalSessionTokenReturnsTokenMapUsingName() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_1"); + assertThat(sessionToken.getLSN()).isEqualTo(101); + } + + @Test(groups = "unit") + public void resolveLocalSessionTokenReturnsTokenMapUsingResourceId() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_1"); + assertThat(sessionToken.getLSN()).isEqualTo(101); + } + + @Test(groups = "unit") + public void resolveLocalSessionTokenReturnsNullOnPartitionMiss() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + request.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_2"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void resolveLocalSessionTokenReturnsNullOnCollectionMiss() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + int randomCollectionId = getRandomCollectionId(); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), randomCollectionId).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceId.newDocumentCollectionId(getRandomDbId(), randomCollectionId - 1).getDocumentCollectionId().toString(), + ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + request.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_1"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void resolvePartitionLocalSessionTokenReturnsTokenOnParentMatch() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_1:1#101#1=20#2=5#3=30")); + request.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + GatewayTestUtils.setParent(request.requestContext.resolvedPartitionKeyRange, ImmutableList.of("range_1")); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_2"); + assertThat(sessionToken.getLSN()).isEqualTo(101); + } + + @Test(groups = "unit") + public void clearTokenByCollectionFullNameRemovesToken() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + + // Test resourceId based + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + // Test names based + request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + sessionContainer.clearTokenByCollectionFullName(collectionFullName); + + // Test resourceId based + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + + // Test names based + request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void clearTokenByResourceIdRemovesToken() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + + // Test resourceId based + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + // Test names based + request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + sessionContainer.clearTokenByResourceId(documentCollectionId); + + // Test resourceId based + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + + // Test names based + request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void clearTokenKeepsUnmatchedCollection() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + int randomCollectionId = getRandomCollectionId(); + String documentCollectionId1 = ResourceId.newDocumentCollectionId(getRandomDbId(), randomCollectionId).getDocumentCollectionId().toString(); + String collectionFullName1 = "dbs/db1/colls1/collName1"; + + sessionContainer.setSessionToken(documentCollectionId1, collectionFullName1, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + + // Test resourceId based + RxDocumentServiceRequest request1 = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId1, ResourceType.Document, new HashMap<>()); + String documentCollectionId2 = ResourceId.newDocumentCollectionId(getRandomDbId(), randomCollectionId - 1).getDocumentCollectionId().toString(); + String collectionFullName2 = "dbs/db1/colls1/collName2"; + + // Test resourceId based + RxDocumentServiceRequest request2 = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId2, ResourceType.Document, new HashMap<>()); + + sessionContainer.setSessionToken(documentCollectionId2, collectionFullName2, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#1=20#2=5#3=30")); + + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request1, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request2, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + sessionContainer.clearTokenByResourceId(documentCollectionId2); + + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request1, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request2, "range_0"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void setSessionTokenDoesntFailOnEmptySessionTokenHeader() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + sessionContainer.setSessionToken(null, new HashMap<>()); + } + + @Test(groups = "unit") + public void setSessionTokenSetsTokenWhenRequestIsntNameBased() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + + assertThat(request.getIsNameBased()).isFalse(); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1")); + request = RxDocumentServiceRequest.create(OperationType.Read, documentCollectionId, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + request = RxDocumentServiceRequest.createFromName(OperationType.Read, collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + } + + @Test(groups = "unit") + public void setSessionTokenGivesPriorityToOwnerFullNameOverResourceAddress() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName1 = "dbs/db1/colls1/collName1"; + String collectionFullName2 = "dbs/db1/colls1/collName2"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName1 + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1", + HttpConstants.HttpHeaders.OWNER_FULL_NAME, collectionFullName2)); + + request = RxDocumentServiceRequest.createFromName(OperationType.Read, collectionFullName1 + "/docs/doc1", ResourceType.Document); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + + request = RxDocumentServiceRequest.createFromName(OperationType.Read, collectionFullName2 + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + } + + @Test(groups = "unit") + public void setSessionTokenIgnoresOwnerIdWhenRequestIsntNameBased() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + int randomCollectionId = getRandomCollectionId(); + int randomDbId = getRandomDbId(); + String documentCollectionId1 = ResourceId.newDocumentCollectionId(randomDbId, randomCollectionId).getDocumentCollectionId().toString(); + String documentCollectionId2 = ResourceId.newDocumentCollectionId(randomDbId, randomCollectionId - 1).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName1"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId1); + assertThat(request.getIsNameBased()).isFalse(); + + sessionContainer.setSessionToken(request, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1", + HttpConstants.HttpHeaders.OWNER_ID, documentCollectionId2)); + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId1, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId2, ResourceType.Document, new HashMap<>()); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void setSessionTokenGivesPriorityToOwnerIdOverResourceIdWhenRequestIsNameBased() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + int randomCollectionId = getRandomCollectionId(); + int randomDbId = getRandomDbId(); + String documentCollectionId1 = ResourceId.newDocumentCollectionId(randomDbId, randomCollectionId).getDocumentCollectionId().toString(); + String documentCollectionId2 = ResourceId.newDocumentCollectionId(randomDbId, randomCollectionId - 1).getDocumentCollectionId().toString(); + + String collectionFullName = "dbs/db1/colls1/collName1"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document); + request.setResourceId(documentCollectionId1); + assertThat(request.getIsNameBased()).isTrue(); + + sessionContainer.setSessionToken(request, + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1", + HttpConstants.HttpHeaders.OWNER_ID, documentCollectionId2)); + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId1, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId2, ResourceType.Document, new HashMap<>()); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(100); + } + + @Test(groups = "unit") + public void setSessionTokenDoesntWorkForMasterQueries() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.ReadFeed, + collectionFullName + "/docs/doc1", ResourceType.DocumentCollection, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1")); + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + + request = RxDocumentServiceRequest.createFromName(OperationType.Read, collectionFullName + "/docs/doc1", ResourceType.Document); + sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken).isNull(); + } + + @Test(groups = "unit") + public void setSessionTokenDoesntOverwriteHigherLSN() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#105#4=90#5=1")); + + + request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1")); + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(105); + } + + @Test(groups = "unit") + public void setSessionTokenOverwriteLowerLSN() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1")); + + + request = RxDocumentServiceRequest.create(OperationType.Read, + collectionFullName + "/docs/doc1", ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + sessionContainer.setSessionToken(request, ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#105#4=90#5=1")); + + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + request.setResourceId(documentCollectionId); + ISessionToken sessionToken = sessionContainer.resolvePartitionLocalSessionToken(request, "range_0"); + assertThat(sessionToken.getLSN()).isEqualTo(105); + } + + @Test(groups = "unit") + public void setSessionTokenDoesNothingOnEmptySessionTokenHeader() { + SessionContainer sessionContainer = new SessionContainer("127.0.0.1"); + String documentCollectionId = ResourceId.newDocumentCollectionId(getRandomDbId(), getRandomCollectionId()).getDocumentCollectionId().toString(); + String collectionFullName = "dbs/db1/colls1/collName"; + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName + "/docs/doc1", + ImmutableMap.of(HttpConstants.HttpHeaders.SESSION_TOKEN, "range_0:1#100#4=90#5=1")); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + String sessionToken = sessionContainer.resolveGlobalSessionToken(request); + Set tokens = Sets.newSet(sessionToken.split(",")); + assertThat(tokens.size()).isEqualTo(1); + assertThat(tokens.contains("range_0:1#100#4=90#5=1")).isTrue(); + + sessionContainer.setSessionToken(documentCollectionId, collectionFullName, new HashMap<>()); + request = RxDocumentServiceRequest.create(OperationType.Read, + documentCollectionId, ResourceType.Document, new HashMap<>()); + sessionToken = sessionContainer.resolveGlobalSessionToken(request); + tokens = Sets.newSet(sessionToken.split(",")); + assertThat(tokens.size()).isEqualTo(1); + assertThat(tokens.contains("range_0:1#100#4=90#5=1")).isTrue(); + } + + private static int getRandomCollectionId() { + return random.nextInt(Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2); + } + + private static int getRandomDbId() { + return random.nextInt(Integer.MAX_VALUE / 2); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTest.java new file mode 100644 index 0000000000000..3ec00b7246b68 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTest.java @@ -0,0 +1,211 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.http.HttpRequest; +import io.netty.handler.codec.http.HttpMethod; +import org.apache.commons.lang3.StringUtils; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SessionTest extends TestSuiteBase { + protected static final int TIMEOUT = 20000; + + private Database createdDatabase; + private DocumentCollection createdCollection; + private String collectionId = "+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~"; + private SpyClientUnderTestFactory.SpyBaseClass spyClient; + private AsyncDocumentClient houseKeepingClient; + private ConnectionMode connectionMode; + private RequestOptions options; + + @Factory(dataProvider = "clientBuildersWithDirectSession") + public SessionTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + this.subscriberValidationTimeout = TIMEOUT; + } + + @DataProvider(name = "sessionTestArgProvider") + public Object[] sessionTestArgProvider() { + return new Object[] { + // boolean indicating whether requests should be name based or not + true, + false + }; + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + createdDatabase = SHARED_DATABASE; + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + DocumentCollection collection = new DocumentCollection(); + collection.id(collectionId); + collection.setPartitionKey(partitionKeyDef); + + createdCollection = createCollection(createGatewayHouseKeepingDocumentClient().build(), createdDatabase.id(), + collection, null); + houseKeepingClient = clientBuilder().build(); + connectionMode = houseKeepingClient.getConnectionPolicy().connectionMode(); + + if (connectionMode == ConnectionMode.DIRECT) { + spyClient = SpyClientUnderTestFactory.createDirectHttpsClientUnderTest(clientBuilder()); + } else { + spyClient = SpyClientUnderTestFactory.createClientUnderTest(clientBuilder()); + } + options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteCollection(houseKeepingClient, createdCollection); + safeClose(houseKeepingClient); + safeClose(spyClient); + } + + @BeforeMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeTest(Method method) { + spyClient.clearCapturedRequests(); + } + + private List getSessionTokensInRequests() { + return spyClient.getCapturedRequests().stream() + .map(r -> r.headers().value(HttpConstants.HttpHeaders.SESSION_TOKEN)).collect(Collectors.toList()); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "sessionTestArgProvider") + public void sessionConsistency_ReadYourWrites(boolean isNameBased) { + spyClient.readCollection(getCollectionLink(isNameBased), null).blockFirst(); + spyClient.createDocument(getCollectionLink(isNameBased), new Document(), null, false).blockFirst(); + + spyClient.clearCapturedRequests(); + + for (int i = 0; i < 10; i++) { + Document documentCreated = spyClient.createDocument(getCollectionLink(isNameBased), new Document(), null, false) + .blockFirst().getResource(); + + // We send session tokens on Writes in GATEWAY mode + if (connectionMode == ConnectionMode.GATEWAY) { + assertThat(getSessionTokensInRequests()).hasSize(3 * i + 1); + assertThat(getSessionTokensInRequests().get(3 * i + 0)).isNotEmpty(); + } + + spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), options).blockFirst(); + + assertThat(getSessionTokensInRequests()).hasSize(3 * i + 2); + assertThat(getSessionTokensInRequests().get(3 * i + 1)).isNotEmpty(); + + spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), options).blockFirst(); + + assertThat(getSessionTokensInRequests()).hasSize(3 * i + 3); + assertThat(getSessionTokensInRequests().get(3 * i + 2)).isNotEmpty(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "sessionTestArgProvider") + public void sessionTokenInDocumentRead(boolean isNameBased) throws UnsupportedEncodingException { + Document document = new Document(); + document.id(UUID.randomUUID().toString()); + BridgeInternal.setProperty(document, "pk", "pk"); + document = spyClient.createDocument(getCollectionLink(isNameBased), document, null, false) + .blockFirst() + .getResource(); + + final String documentLink = getDocumentLink(document, isNameBased); + spyClient.readDocument(documentLink, options).blockFirst() + .getResource(); + + List documentReadHttpRequests = spyClient.getCapturedRequests().stream() + .filter(r -> r.httpMethod() == HttpMethod.GET) + .filter(r -> { + try { + return URLDecoder.decode(r.uri().toString().replaceAll("\\+", "%2b"), "UTF-8").contains( + StringUtils.removeEnd(documentLink, "/")); + } catch (UnsupportedEncodingException e) { + return false; + } + }).collect(Collectors.toList()); + + // DIRECT mode may make more than one call (multiple replicas) + assertThat(documentReadHttpRequests.size() >= 1).isTrue(); + assertThat(documentReadHttpRequests.get(0).headers().value(HttpConstants.HttpHeaders.SESSION_TOKEN)).isNotEmpty(); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "sessionTestArgProvider") + public void sessionTokenRemovedForMasterResource(boolean isNameBased) throws UnsupportedEncodingException { + if (connectionMode == ConnectionMode.DIRECT) { + throw new SkipException("Master resource access is only through gateway"); + } + String collectionLink = getCollectionLink(isNameBased); + spyClient.readCollection(collectionLink, null).blockFirst(); + + List collectionReadHttpRequests = spyClient.getCapturedRequests().stream() + .filter(r -> r.httpMethod() == HttpMethod.GET) + .filter(r -> { + try { + return URLDecoder.decode(r.uri().toString().replaceAll("\\+", "%2b"), "UTF-8").contains( + StringUtils.removeEnd(collectionLink, "/")); + } catch (UnsupportedEncodingException e) { + return false; + } + }) + .collect(Collectors.toList()); + + assertThat(collectionReadHttpRequests).hasSize(1); + assertThat(collectionReadHttpRequests.get(0).headers().value(HttpConstants.HttpHeaders.SESSION_TOKEN)).isNull(); + } + + private String getCollectionLink(boolean isNameBased) { + return isNameBased ? "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(): + createdCollection.selfLink(); + } + + private String getDocumentLink(Document doc, boolean isNameBased) { + return isNameBased ? "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id() + "/docs/" + doc.id() : + "dbs/" + createdDatabase.resourceId() + "/colls/" + createdCollection.resourceId() + "/docs/" + doc.resourceId() + "/"; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTokenTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTokenTest.java new file mode 100644 index 0000000000000..13299080d0978 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SessionTokenTest.java @@ -0,0 +1,139 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.InternalServerErrorException; +import org.testng.annotations.Test; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class SessionTokenTest { + + @Test(groups = "unit") + public void validateSuccessfulSessionTokenParsing() { + // valid session token + String sessionToken = "1#100#1=20#2=5#3=30"; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isTrue(); + } + + @Test(groups = "unit") + public void validateSessionTokenParsingWithInvalidVersion() { + String sessionToken = "foo#100#1=20#2=5#3=30"; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isFalse(); + } + + @Test(groups = "unit") + public void validateSessionTokenParsingWithInvalidGlobalLsn() { + String sessionToken = "1#foo#1=20#2=5#3=30"; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isFalse(); + } + + @Test(groups = "unit") + public void validateSessionTokenParsingWithInvalidRegionProgress() { + String sessionToken = "1#100#1=20#2=x#3=30"; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isFalse(); + + } + + @Test(groups = "unit") + public void validateSessionTokenParsingWithInvalidFormat() { + String sessionToken = "1;100#1=20#2=40"; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isFalse(); + } + + @Test(groups = "unit") + public void validateSessionTokenParsingFromEmptyString() { + String sessionToken = ""; + ValueHolder parsedSessionToken = new ValueHolder<>(null); + assertThat(VectorSessionToken.tryCreate(sessionToken, parsedSessionToken)).isFalse(); + } + + @Test(groups = "unit") + public void validateSessionTokenComparison() throws Exception { + // valid session token + ValueHolder sessionToken1 = new ValueHolder<>(null); + ValueHolder sessionToken2 = new ValueHolder<>(null); + ValueHolder sessionTokenMerged = new ValueHolder<>(null); + + assertThat(VectorSessionToken.tryCreate("1#100#1=20#2=5#3=30", sessionToken1)).isTrue(); + assertThat(VectorSessionToken.tryCreate("2#105#4=10#2=5#3=30", sessionToken2)).isTrue(); + + assertThat(sessionToken1.v).isNotEqualTo(sessionToken2.v); + assertThat(sessionToken2.v).isNotEqualTo(sessionToken1.v); + + assertThat(sessionToken1.v.isValid(sessionToken2.v)).isTrue(); + assertThat(sessionToken2.v.isValid(sessionToken1.v)).isFalse(); + + + assertThat(VectorSessionToken.tryCreate("2#105#2=5#3=30#4=10", sessionTokenMerged)).isTrue(); + assertThat(sessionTokenMerged.v).isEqualTo(sessionToken1.v.merge(sessionToken2.v)); + + assertThat(VectorSessionToken.tryCreate("1#100#1=20#2=5#3=30", sessionToken1)).isTrue(); + assertThat(VectorSessionToken.tryCreate("1#100#1=10#2=8#3=30", sessionToken2)).isTrue(); + + assertThat(sessionToken1.v.equals(sessionToken2.v)).isFalse(); + assertThat(sessionToken2.v.equals(sessionToken1.v)).isFalse(); + assertThat(sessionToken1.v.isValid(sessionToken2.v)).isFalse(); + assertThat(sessionToken2.v.isValid(sessionToken1.v)).isFalse(); + + assertThat(VectorSessionToken.tryCreate("1#100#1=20#2=8#3=30", sessionTokenMerged)).isTrue(); + assertThat(sessionTokenMerged.v.equals(sessionToken1.v.merge(sessionToken2.v))).isTrue(); + + assertThat(VectorSessionToken.tryCreate("1#100#1=20#2=5#3=30", sessionToken1)).isTrue(); + assertThat(VectorSessionToken.tryCreate("1#102#1=100#2=8#3=30", sessionToken2)).isTrue(); + + assertThat(sessionToken1.v.equals(sessionToken2.v)).isFalse(); + assertThat(sessionToken2.v.equals(sessionToken1.v)).isFalse(); + assertThat(sessionToken1.v.isValid(sessionToken2.v)).isTrue(); + assertThat(sessionToken2.v.isValid(sessionToken1.v)).isFalse(); + + assertThat(VectorSessionToken.tryCreate("1#102#2=8#3=30#1=100", sessionTokenMerged)).isTrue(); + + assertThat(sessionTokenMerged.v.equals(sessionToken1.v.merge(sessionToken2.v))).isTrue(); + + assertThat(VectorSessionToken.tryCreate("1#101#1=20#2=5#3=30", sessionToken1)).isTrue(); + assertThat(VectorSessionToken.tryCreate("1#100#1=20#2=5#3=30#4=40", sessionToken2)).isTrue(); + + + try { + sessionToken1.v.merge(sessionToken2.v); + fail("Region progress can not be different when version is same"); + } catch (InternalServerErrorException e) { + } + + try { + sessionToken2.v.isValid(sessionToken1.v); + fail("Region progress can not be different when version is same"); + } catch (InternalServerErrorException e) { + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ShouldRetryValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ShouldRetryValidator.java new file mode 100644 index 0000000000000..9416d990abbac --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/ShouldRetryValidator.java @@ -0,0 +1,140 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.FailureValidator; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This is a helper class for validating a partition address for tests. + */ +public interface ShouldRetryValidator { + + void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult); + + static Builder builder() { + return new Builder(); + } + + class Builder { + private List validators = new ArrayList<>(); + + public ShouldRetryValidator build() { + return new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + for (ShouldRetryValidator validator : validators) { + validator.validate(shouldRetryResult); + } + } + }; + } + + public Builder nullException() { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.exception).isNull(); + } + }); + return this; + } + + public Builder hasException() { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.exception).isNotNull(); + } + }); + return this; + } + + public Builder exceptionOfType(Class klass) { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.exception).isNotNull(); + assertThat(shouldRetryResult.exception).isInstanceOf(klass); + } + }); + return this; + } + + public Builder withException(FailureValidator failureValidator) { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.exception).isNotNull(); + failureValidator.validate(shouldRetryResult.exception); + } + }); + return this; + } + + public Builder withException(Exception exception) { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.exception).isNotNull(); + assertThat(shouldRetryResult.exception).isEqualTo(exception); + } + }); + return this; + } + + public Builder shouldRetry(boolean value) { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.shouldRetry).isEqualTo(value); + } + }); + return this; + } + + + public Builder backOfTime(Duration backOfTime) { + validators.add(new ShouldRetryValidator() { + + @Override + public void validate(IRetryPolicy.ShouldRetryResult shouldRetryResult) { + assertThat(shouldRetryResult.backOffTime).isEqualTo(backOfTime); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientBuilder.java new file mode 100644 index 0000000000000..ea0a005922b12 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientBuilder.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +public class SpyClientBuilder extends AsyncDocumentClient.Builder { + + public SpyClientBuilder(AsyncDocumentClient.Builder builder) { + super(); + super.configs = builder.configs; + super.connectionPolicy = builder.connectionPolicy; + super.desiredConsistencyLevel = builder.desiredConsistencyLevel; + super.masterKeyOrResourceToken = builder.masterKeyOrResourceToken; + super.serviceEndpoint = builder.serviceEndpoint; + } + + public SpyClientUnderTestFactory.ClientUnderTest build() { + return SpyClientUnderTestFactory.createClientUnderTest( + serviceEndpoint, + masterKeyOrResourceToken, + connectionPolicy, + desiredConsistencyLevel, + configs); + } + + public SpyClientUnderTestFactory.ClientWithGatewaySpy buildWithGatewaySpy() { + return SpyClientUnderTestFactory.createClientWithGatewaySpy( + serviceEndpoint, + masterKeyOrResourceToken, + connectionPolicy, + desiredConsistencyLevel, + configs); + } + + public SpyClientUnderTestFactory.DirectHttpsClientUnderTest buildWithDirectHttps() { + return SpyClientUnderTestFactory.createDirectHttpsClientUnderTest( + serviceEndpoint, + masterKeyOrResourceToken, + connectionPolicy, + desiredConsistencyLevel); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientUnderTestFactory.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientUnderTestFactory.java new file mode 100644 index 0000000000000..5a7c776721ec8 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/SpyClientUnderTestFactory.java @@ -0,0 +1,300 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.directconnectivity.ReflectionUtils; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +public class SpyClientUnderTestFactory { + + public static abstract class SpyBaseClass extends RxDocumentClientImpl { + + public SpyBaseClass(URI serviceEndpoint, String masterKeyOrResourceToken, ConnectionPolicy connectionPolicy, ConsistencyLevel consistencyLevel, Configs configs) { + super(serviceEndpoint, masterKeyOrResourceToken, connectionPolicy, consistencyLevel, configs); + } + + public abstract List getCapturedRequests(); + + public abstract void clearCapturedRequests(); + + protected static Configs createConfigsSpy(final Protocol protocol) { + final Configs configs = spy(new Configs()); + doAnswer((Answer) invocation -> protocol).when(configs).getProtocol(); + return configs; + } + } + + public static class ClientWithGatewaySpy extends SpyBaseClass { + + private RxGatewayStoreModel origRxGatewayStoreModel; + private RxGatewayStoreModel spyRxGatewayStoreModel; + + private List requests; + + + ClientWithGatewaySpy(URI serviceEndpoint, String masterKey, ConnectionPolicy connectionPolicy, ConsistencyLevel consistencyLevel, Configs configs) { + super(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, configs); + init(); + } + + @Override + public List getCapturedRequests() { + return requests; + } + + @Override + RxGatewayStoreModel createRxGatewayProxy(ISessionContainer sessionContainer, + ConsistencyLevel consistencyLevel, + QueryCompatibilityMode queryCompatibilityMode, + UserAgentContainer userAgentContainer, + GlobalEndpointManager globalEndpointManager, + HttpClient rxClient) { + this.origRxGatewayStoreModel = super.createRxGatewayProxy( + sessionContainer, + consistencyLevel, + queryCompatibilityMode, + userAgentContainer, + globalEndpointManager, + rxClient); + this.requests = Collections.synchronizedList(new ArrayList<>()); + this.spyRxGatewayStoreModel = spy(this.origRxGatewayStoreModel); + this.initRequestCapture(); + return this.spyRxGatewayStoreModel; + } + + protected void initRequestCapture() { + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) { + RxDocumentServiceRequest req = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + requests.add(req); + return ClientWithGatewaySpy.this.origRxGatewayStoreModel.processMessage(req); + } + }).when(ClientWithGatewaySpy.this.spyRxGatewayStoreModel).processMessage(Mockito.any(RxDocumentServiceRequest.class)); + } + + @Override + public void clearCapturedRequests() { + requests.clear(); + } + + public RxGatewayStoreModel getSpyGatewayStoreModel() { + return spyRxGatewayStoreModel; + } + + public RxGatewayStoreModel getOrigGatewayStoreModel() { + return origRxGatewayStoreModel; + } + } + + public static class ClientUnderTest extends SpyBaseClass { + + HttpClient origHttpClient; + HttpClient spyHttpClient; + List>> requestsResponsePairs = + Collections.synchronizedList(new ArrayList<>()); + + ClientUnderTest(URI serviceEndpoint, String masterKey, ConnectionPolicy connectionPolicy, ConsistencyLevel consistencyLevel, Configs configs) { + super(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, configs); + init(); + } + + public List>> capturedRequestResponseHeaderPairs() { + return requestsResponsePairs; + } + + @Override + public List getCapturedRequests() { + return requestsResponsePairs.stream().map(Pair::getLeft).collect(Collectors.toList()); + } + + void initRequestCapture(HttpClient spyClient) { + doAnswer(invocationOnMock -> { + HttpRequest httpRequest = invocationOnMock.getArgumentAt(0, HttpRequest.class); + CompletableFuture f = new CompletableFuture<>(); + requestsResponsePairs.add(Pair.of(httpRequest, f)); + + return origHttpClient + .send(httpRequest) + .doOnNext(httpResponse -> f.complete(httpResponse.headers())) + .doOnError(f::completeExceptionally); + }).when(spyClient).send(Mockito.any(HttpRequest.class)); + } + + @Override + public void clearCapturedRequests() { + requestsResponsePairs.clear(); + } + + public ISessionContainer getSessionContainer() { + try { + return (ISessionContainer) FieldUtils.readField(this, "sessionContainer", true); + } catch (Exception e){ + throw new RuntimeException(e); + } + } + + public HttpClient getSpyHttpClient() { + return spyHttpClient; + } + } + + public static class DirectHttpsClientUnderTest extends SpyBaseClass { + + HttpClient origHttpClient; + HttpClient spyHttpClient; + List>> requestsResponsePairs = + Collections.synchronizedList(new ArrayList<>()); + + DirectHttpsClientUnderTest(URI serviceEndpoint, String masterKey, ConnectionPolicy connectionPolicy, ConsistencyLevel consistencyLevel) { + super(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, createConfigsSpy(Protocol.HTTPS)); + assert connectionPolicy.connectionMode() == ConnectionMode.DIRECT; + init(); + + this.origHttpClient = ReflectionUtils.getDirectHttpsHttpClient(this); + this.spyHttpClient = spy(this.origHttpClient); + ReflectionUtils.setDirectHttpsHttpClient(this, this.spyHttpClient); + this.initRequestCapture(this.spyHttpClient); + } + + public List>> capturedRequestResponseHeaderPairs() { + return requestsResponsePairs; + } + + @Override + public List getCapturedRequests() { + return requestsResponsePairs.stream().map(Pair::getLeft).collect(Collectors.toList()); + } + + void initRequestCapture(HttpClient spyClient) { + doAnswer(invocationOnMock -> { + HttpRequest httpRequest = invocationOnMock.getArgumentAt(0, HttpRequest.class); + CompletableFuture f = new CompletableFuture<>(); + requestsResponsePairs.add(Pair.of(httpRequest, f)); + + return origHttpClient + .send(httpRequest) + .doOnNext(httpResponse -> f.complete(httpResponse.headers())) + .doOnError(f::completeExceptionally); + + }).when(spyClient).send(Mockito.any(HttpRequest.class)); + } + + @Override + public void clearCapturedRequests() { + requestsResponsePairs.clear(); + } + + public ISessionContainer getSessionContainer() { + try { + return (ISessionContainer) FieldUtils.readField(this, "sessionContainer", true); + } catch (Exception e){ + throw new RuntimeException(e); + } + } + + public HttpClient getSpyHttpClient() { + return spyHttpClient; + } + } + + public static ClientWithGatewaySpy createClientWithGatewaySpy(AsyncDocumentClient.Builder builder) { + return new SpyClientBuilder(builder).buildWithGatewaySpy(); + } + + public static ClientWithGatewaySpy createClientWithGatewaySpy(URI serviceEndpoint, + String masterKey, + ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, + Configs configs) { + return new ClientWithGatewaySpy(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, configs); + } + + public static ClientUnderTest createClientUnderTest(AsyncDocumentClient.Builder builder) { + return new SpyClientBuilder(builder).build(); + } + + public static DirectHttpsClientUnderTest createDirectHttpsClientUnderTest(AsyncDocumentClient.Builder builder) { + return new SpyClientBuilder(builder).buildWithDirectHttps(); + } + + public static ClientUnderTest createClientUnderTest(URI serviceEndpoint, + String masterKey, + ConnectionPolicy connectionPolicy, + ConsistencyLevel consistencyLevel, + Configs configs) { + return new ClientUnderTest(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel, configs) { + + @Override + RxGatewayStoreModel createRxGatewayProxy(ISessionContainer sessionContainer, + ConsistencyLevel consistencyLevel, + QueryCompatibilityMode queryCompatibilityMode, + UserAgentContainer userAgentContainer, + GlobalEndpointManager globalEndpointManager, + HttpClient rxClient) { + + HttpClient spy = spy(rxClient); + + this.origHttpClient = rxClient; + this.spyHttpClient = spy; + + this.initRequestCapture(spyHttpClient); + + return super.createRxGatewayProxy( + sessionContainer, + consistencyLevel, + queryCompatibilityMode, + userAgentContainer, + globalEndpointManager, + spy); + } + }; + } + + public static DirectHttpsClientUnderTest createDirectHttpsClientUnderTest(URI serviceEndpoint, String masterKey, + ConnectionPolicy connectionPolicy, ConsistencyLevel consistencyLevel) { + return new DirectHttpsClientUnderTest(serviceEndpoint, masterKey, connectionPolicy, consistencyLevel); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreHeaderTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreHeaderTests.java new file mode 100644 index 0000000000000..f748a4e325fdb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreHeaderTests.java @@ -0,0 +1,83 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.UUID; + +public class StoreHeaderTests extends TestSuiteBase { + + private static Database createdDatabase; + private static DocumentCollection createdCollection; + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public StoreHeaderTests(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void validateStoreHeader() { + Document docDefinition1 = getDocumentDefinition(); + Document responseDoc1 = createDocument(client, createdDatabase.id(), createdCollection.id(), docDefinition1); + Assert.assertNotNull(responseDoc1.selfLink()); + Assert.assertNotNull(responseDoc1.get("_attachments")); + + Document docDefinition2 = getDocumentDefinition(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setHeader("x-ms-exclude-system-properties", "true"); + Document responseDoc2 = createDocument(client, createdDatabase.id(), createdCollection.id(), docDefinition2, requestOptions); + Assert.assertNull(responseDoc2.selfLink()); + Assert.assertNull(responseDoc2.get("_attachments")); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + + createdDatabase = SHARED_DATABASE; + createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreResponseBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreResponseBuilder.java new file mode 100644 index 0000000000000..a42cf98178fcb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/StoreResponseBuilder.java @@ -0,0 +1,116 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; + +import java.math.BigDecimal; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class StoreResponseBuilder { + private int status; + private List> headerEntries; + private String content; + + public static StoreResponseBuilder create() { + return new StoreResponseBuilder(); + } + + public StoreResponseBuilder() { + headerEntries = new ArrayList<>(); + } + + public StoreResponseBuilder withHeader(String key, String value) { + headerEntries.add(new AbstractMap.SimpleEntry(key, value)); + return this; + } + + public StoreResponseBuilder withLSN(long lsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.LSN, Long.toString(lsn))); + return this; + } + + public StoreResponseBuilder withRequestCharge(BigDecimal requestCharge) { + withRequestCharge(requestCharge.doubleValue()); + return this; + } + + public StoreResponseBuilder withRequestCharge(double requestCharge) { + headerEntries.add(new AbstractMap.SimpleEntry(HttpConstants.HttpHeaders.REQUEST_CHARGE, Double.toString(requestCharge))); + return this; + } + + public StoreResponseBuilder withLocalLSN(long localLsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(localLsn))); + return this; + } + + public StoreResponseBuilder withPartitionKeyRangeId(String partitionKeyRangeId) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId)); + return this; + } + + public StoreResponseBuilder withItemLocalLSN(long itemLocalLsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.ITEM_LOCAL_LSN, Long.toString(itemLocalLsn))); + return this; + } + + public StoreResponseBuilder withQuorumAckecdLsn(long quorumAckecdLsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, Long.toString(quorumAckecdLsn))); + return this; + } + + public StoreResponseBuilder withQuorumAckecdLocalLsn(long quorumAckecdLocalLsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(quorumAckecdLocalLsn))); + return this; + } + + public StoreResponseBuilder withGlobalCommittedLsn(long globalCommittedLsn) { + headerEntries.add(new AbstractMap.SimpleEntry(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn))); + return this; + } + + public StoreResponseBuilder withSessionToken(String sessionToken) { + headerEntries.add(new AbstractMap.SimpleEntry(HttpConstants.HttpHeaders.SESSION_TOKEN, sessionToken)); + return this; + } + + public StoreResponseBuilder withStatus(int status) { + this.status = status; + return this; + } + + public StoreResponseBuilder withContent(String content) { + this.content = content; + return this; + } + + public StoreResponse build() { + return new StoreResponse(status, headerEntries, content); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestSuiteBase.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestSuiteBase.java new file mode 100644 index 0000000000000..e353afbdbefa8 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestSuiteBase.java @@ -0,0 +1,988 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.CompositePathSortOrder; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.DocumentClientTest; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.RetryOptions; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.mockito.stubbing.Answer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.DataProvider; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +public class TestSuiteBase extends DocumentClientTest { + + private static final int DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL = 500; + private static final ObjectMapper objectMapper = new ObjectMapper(); + protected static Logger logger = LoggerFactory.getLogger(TestSuiteBase.class.getSimpleName()); + protected static final int TIMEOUT = 40000; + protected static final int FEED_TIMEOUT = 40000; + protected static final int SETUP_TIMEOUT = 60000; + protected static final int SHUTDOWN_TIMEOUT = 12000; + + protected static final int SUITE_SETUP_TIMEOUT = 120000; + protected static final int SUITE_SHUTDOWN_TIMEOUT = 60000; + + protected static final int WAIT_REPLICA_CATCH_UP_IN_MILLIS = 4000; + + protected final static ConsistencyLevel accountConsistency; + protected static final ImmutableList preferredLocations; + private static final ImmutableList desiredConsistencies; + private static final ImmutableList protocols; + + protected int subscriberValidationTimeout = TIMEOUT; + protected static Database SHARED_DATABASE; + protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION; + protected static DocumentCollection SHARED_SINGLE_PARTITION_COLLECTION; + protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; + + private static ImmutableList immutableListOrNull(List list) { + return list != null ? ImmutableList.copyOf(list) : null; + } + + static { + accountConsistency = parseConsistency(TestConfigurations.CONSISTENCY); + desiredConsistencies = immutableListOrNull( + ObjectUtils.defaultIfNull(parseDesiredConsistencies(TestConfigurations.DESIRED_CONSISTENCIES), + allEqualOrLowerConsistencies(accountConsistency))); + preferredLocations = immutableListOrNull(parsePreferredLocation(TestConfigurations.PREFERRED_LOCATIONS)); + protocols = ObjectUtils.defaultIfNull(immutableListOrNull(parseProtocols(TestConfigurations.PROTOCOLS)), + ImmutableList.of(Protocol.HTTPS, Protocol.TCP)); + // Object mapper configuration + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + objectMapper.configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true); + objectMapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + } + + protected TestSuiteBase() { + this(new AsyncDocumentClient.Builder()); + } + + protected TestSuiteBase(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + logger.debug("Initializing {} ...", this.getClass().getSimpleName()); + } + + private static class DatabaseManagerImpl implements DatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(AsyncDocumentClient client) { + return new DatabaseManagerImpl(client); + } + + private final AsyncDocumentClient client; + + private DatabaseManagerImpl(AsyncDocumentClient client) { + this.client = client; + } + + @Override + public Flux> queryDatabases(SqlQuerySpec query) { + return client.queryDatabases(query, null); + } + + @Override + public Flux> createDatabase(Database databaseDefinition) { + return client.createDatabase(databaseDefinition, null); + } + + @Override + public Flux> deleteDatabase(String id) { + return client.deleteDatabase("dbs/" + id, null); + } + } + + @BeforeSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SETUP_TIMEOUT) + public static void beforeSuite() { + logger.info("beforeSuite Started"); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + DatabaseForTest dbForTest = DatabaseForTest.create(DatabaseManagerImpl.getInstance(houseKeepingClient)); + SHARED_DATABASE = dbForTest.createdDatabase; + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10100); + SHARED_MULTI_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.id(), getCollectionDefinitionWithRangeRangeIndex(), options); + SHARED_SINGLE_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.id(), getCollectionDefinition(), null); + SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES = createCollection(houseKeepingClient, SHARED_DATABASE.id(), getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes(), options); + } finally { + houseKeepingClient.close(); + } + } + + @AfterSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SHUTDOWN_TIMEOUT) + public static void afterSuite() { + logger.info("afterSuite Started"); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + safeDeleteDatabase(houseKeepingClient, SHARED_DATABASE); + DatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(houseKeepingClient)); + } finally { + safeClose(houseKeepingClient); + } + } + + protected static void truncateCollection(DocumentCollection collection) { + logger.info("Truncating collection {} ...", collection.id()); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + List paths = collection.getPartitionKey().paths(); + + FeedOptions options = new FeedOptions(); + options.maxDegreeOfParallelism(-1); + options.enableCrossPartitionQuery(true); + options.maxItemCount(100); + + logger.info("Truncating collection {} documents ...", collection.id()); + + houseKeepingClient.queryDocuments(collection.selfLink(), "SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(doc -> { + RequestOptions requestOptions = new RequestOptions(); + + if (paths != null && !paths.isEmpty()) { + List pkPath = PathParser.getPathParts(paths.get(0)); + Object propertyValue = doc.getObjectByPath(pkPath); + if (propertyValue == null) { + propertyValue = Undefined.Value(); + } + + requestOptions.setPartitionKey(new PartitionKey(propertyValue)); + } + + return houseKeepingClient.deleteDocument(doc.selfLink(), requestOptions); + }).then().block(); + + logger.info("Truncating collection {} triggers ...", collection.id()); + + houseKeepingClient.queryTriggers(collection.selfLink(), "SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(trigger -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = trigger.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteTrigger(trigger.selfLink(), requestOptions); + }).then().block(); + + logger.info("Truncating collection {} storedProcedures ...", collection.id()); + + houseKeepingClient.queryStoredProcedures(collection.selfLink(), "SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(storedProcedure -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = storedProcedure.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteStoredProcedure(storedProcedure.selfLink(), requestOptions); + }).then().block(); + + logger.info("Truncating collection {} udfs ...", collection.id()); + + houseKeepingClient.queryUserDefinedFunctions(collection.selfLink(), "SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(udf -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = udf.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteUserDefinedFunction(udf.selfLink(), requestOptions); + }).then().block(); + + } finally { + houseKeepingClient.close(); + } + + logger.info("Finished truncating collection {}.", collection.id()); + } + + protected static void waitIfNeededForReplicasToCatchUp(Builder clientBuilder) { + switch (clientBuilder.getDesiredConsistencyLevel()) { + case EVENTUAL: + case CONSISTENT_PREFIX: + logger.info(" additional wait in EVENTUAL mode so the replica catch up"); + // give times to replicas to catch up after a write + try { + TimeUnit.MILLISECONDS.sleep(WAIT_REPLICA_CATCH_UP_IN_MILLIS); + } catch (Exception e) { + logger.error("unexpected failure", e); + } + + case SESSION: + case BOUNDED_STALENESS: + case STRONG: + default: + break; + } + } + + public static DocumentCollection createCollection(String databaseId, + DocumentCollection collection, + RequestOptions options) { + AsyncDocumentClient client = createGatewayHouseKeepingDocumentClient().build(); + try { + return client.createCollection("dbs/" + databaseId, collection, options).single().block().getResource(); + } finally { + client.close(); + } + } + + public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, + DocumentCollection collection, RequestOptions options) { + return client.createCollection("dbs/" + databaseId, collection, options).single().block().getResource(); + } + + public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, + DocumentCollection collection) { + return client.createCollection("dbs/" + databaseId, collection, null).single().block().getResource(); + } + + private static DocumentCollection getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes() { + final String NUMBER_FIELD = "numberField"; + final String STRING_FIELD = "stringField"; + final String NUMBER_FIELD_2 = "numberField2"; + final String STRING_FIELD_2 = "stringField2"; + final String BOOL_FIELD = "boolField"; + final String NULL_FIELD = "nullField"; + final String OBJECT_FIELD = "objectField"; + final String ARRAY_FIELD = "arrayField"; + final String SHORT_STRING_FIELD = "shortStringField"; + final String MEDIUM_STRING_FIELD = "mediumStringField"; + final String LONG_STRING_FIELD = "longStringField"; + final String PARTITION_KEY = "pk"; + + DocumentCollection documentCollection = new DocumentCollection(); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List> compositeIndexes = new ArrayList<>(); + + //Simple + ArrayList compositeIndexSimple = new ArrayList(); + CompositePath compositePath1 = new CompositePath(); + compositePath1.path("/" + NUMBER_FIELD); + compositePath1.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath2 = new CompositePath(); + compositePath2.path("/" + STRING_FIELD); + compositePath2.order(CompositePathSortOrder.DESCENDING); + + compositeIndexSimple.add(compositePath1); + compositeIndexSimple.add(compositePath2); + + //Max Columns + ArrayList compositeIndexMaxColumns = new ArrayList(); + CompositePath compositePath3 = new CompositePath(); + compositePath3.path("/" + NUMBER_FIELD); + compositePath3.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath4 = new CompositePath(); + compositePath4.path("/" + STRING_FIELD); + compositePath4.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath5 = new CompositePath(); + compositePath5.path("/" + NUMBER_FIELD_2); + compositePath5.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath6 = new CompositePath(); + compositePath6.path("/" + STRING_FIELD_2); + compositePath6.order(CompositePathSortOrder.ASCENDING); + + compositeIndexMaxColumns.add(compositePath3); + compositeIndexMaxColumns.add(compositePath4); + compositeIndexMaxColumns.add(compositePath5); + compositeIndexMaxColumns.add(compositePath6); + + //Primitive Values + ArrayList compositeIndexPrimitiveValues = new ArrayList(); + CompositePath compositePath7 = new CompositePath(); + compositePath7.path("/" + NUMBER_FIELD); + compositePath7.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath8 = new CompositePath(); + compositePath8.path("/" + STRING_FIELD); + compositePath8.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath9 = new CompositePath(); + compositePath9.path("/" + BOOL_FIELD); + compositePath9.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath10 = new CompositePath(); + compositePath10.path("/" + NULL_FIELD); + compositePath10.order(CompositePathSortOrder.ASCENDING); + + compositeIndexPrimitiveValues.add(compositePath7); + compositeIndexPrimitiveValues.add(compositePath8); + compositeIndexPrimitiveValues.add(compositePath9); + compositeIndexPrimitiveValues.add(compositePath10); + + //Long Strings + ArrayList compositeIndexLongStrings = new ArrayList(); + CompositePath compositePath11 = new CompositePath(); + compositePath11.path("/" + STRING_FIELD); + + CompositePath compositePath12 = new CompositePath(); + compositePath12.path("/" + SHORT_STRING_FIELD); + + CompositePath compositePath13 = new CompositePath(); + compositePath13.path("/" + MEDIUM_STRING_FIELD); + + CompositePath compositePath14 = new CompositePath(); + compositePath14.path("/" + LONG_STRING_FIELD); + + compositeIndexLongStrings.add(compositePath11); + compositeIndexLongStrings.add(compositePath12); + compositeIndexLongStrings.add(compositePath13); + compositeIndexLongStrings.add(compositePath14); + + compositeIndexes.add(compositeIndexSimple); + compositeIndexes.add(compositeIndexMaxColumns); + compositeIndexes.add(compositeIndexPrimitiveValues); + compositeIndexes.add(compositeIndexLongStrings); + + indexingPolicy.compositeIndexes(compositeIndexes); + documentCollection.setIndexingPolicy(indexingPolicy); + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + ArrayList partitionKeyPaths = new ArrayList(); + partitionKeyPaths.add("/" + PARTITION_KEY); + partitionKeyDefinition.paths(partitionKeyPaths); + documentCollection.setPartitionKey(partitionKeyDefinition); + + documentCollection.id(UUID.randomUUID().toString()); + + return documentCollection; + } + + public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document) { + return createDocument(client, databaseId, collectionId, document, null); + } + + public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document, RequestOptions options) { + return client.createDocument(TestUtils.getCollectionNameLink(databaseId, collectionId), document, options, false).single().block().getResource(); + } + + public Flux> bulkInsert(AsyncDocumentClient client, + String collectionLink, + List documentDefinitionList, + int concurrencyLevel) { + ArrayList>> result = new ArrayList<>(documentDefinitionList.size()); + for (Document docDef : documentDefinitionList) { + result.add(client.createDocument(collectionLink, docDef, null, false)); + } + + return Flux.merge(Flux.fromIterable(result), concurrencyLevel).publishOn(Schedulers.parallel()); + } + + public Flux> bulkInsert(AsyncDocumentClient client, + String collectionLink, + List documentDefinitionList) { + return bulkInsert(client, collectionLink, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL); + } + + public static ConsistencyLevel getAccountDefaultConsistencyLevel(AsyncDocumentClient client) { + return client.getDatabaseAccount().single().block().getConsistencyPolicy().defaultConsistencyLevel(); + } + + public static User createUser(AsyncDocumentClient client, String databaseId, User user) { + return client.createUser("dbs/" + databaseId, user, null).single().block().getResource(); + } + + public static User safeCreateUser(AsyncDocumentClient client, String databaseId, User user) { + deleteUserIfExists(client, databaseId, user.id()); + return createUser(client, databaseId, user); + } + + private static DocumentCollection safeCreateCollection(AsyncDocumentClient client, String databaseId, DocumentCollection collection, RequestOptions options) { + deleteCollectionIfExists(client, databaseId, collection.id()); + return createCollection(client, databaseId, collection, options); + } + + public static String getCollectionLink(DocumentCollection collection) { + return collection.selfLink(); + } + + static protected DocumentCollection getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + static protected DocumentCollection getCollectionDefinitionWithRangeRangeIndex() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.setIndexingPolicy(indexingPolicy); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + public static void deleteCollectionIfExists(AsyncDocumentClient client, String databaseId, String collectionId) { + List res = client.queryCollections("dbs/" + databaseId, + String.format("SELECT * FROM root r where r.id = '%s'", collectionId), null).single().block() + .results(); + if (!res.isEmpty()) { + deleteCollection(client, TestUtils.getCollectionNameLink(databaseId, collectionId)); + } + } + + public static void deleteCollection(AsyncDocumentClient client, String collectionLink) { + client.deleteCollection(collectionLink, null).single().block(); + } + + public static void deleteDocumentIfExists(AsyncDocumentClient client, String databaseId, String collectionId, String docId) { + FeedOptions options = new FeedOptions(); + options.partitionKey(new PartitionKey(docId)); + List res = client + .queryDocuments(TestUtils.getCollectionNameLink(databaseId, collectionId), String.format("SELECT * FROM root r where r.id = '%s'", docId), options) + .single().block().results(); + if (!res.isEmpty()) { + deleteDocument(client, TestUtils.getDocumentNameLink(databaseId, collectionId, docId)); + } + } + + public static void safeDeleteDocument(AsyncDocumentClient client, String documentLink, RequestOptions options) { + if (client != null && documentLink != null) { + try { + client.deleteDocument(documentLink, options).single().block(); + } catch (Exception e) { + CosmosClientException dce = Utils.as(e, CosmosClientException.class); + if (dce == null || dce.statusCode() != 404) { + throw e; + } + } + } + } + + public static void deleteDocument(AsyncDocumentClient client, String documentLink) { + client.deleteDocument(documentLink, null).single().block(); + } + + public static void deleteUserIfExists(AsyncDocumentClient client, String databaseId, String userId) { + List res = client + .queryUsers("dbs/" + databaseId, String.format("SELECT * FROM root r where r.id = '%s'", userId), null) + .single().block().results(); + if (!res.isEmpty()) { + deleteUser(client, TestUtils.getUserNameLink(databaseId, userId)); + } + } + + public static void deleteUser(AsyncDocumentClient client, String userLink) { + client.deleteUser(userLink, null).single().block(); + } + + public static String getDatabaseLink(Database database) { + return database.selfLink(); + } + + static private Database safeCreateDatabase(AsyncDocumentClient client, Database database) { + safeDeleteDatabase(client, database.id()); + return createDatabase(client, database); + } + + static protected Database createDatabase(AsyncDocumentClient client, Database database) { + Flux> databaseObservable = client.createDatabase(database, null); + return databaseObservable.single().block().getResource(); + } + + static protected Database createDatabase(AsyncDocumentClient client, String databaseId) { + Database databaseDefinition = new Database(); + databaseDefinition.id(databaseId); + return createDatabase(client, databaseDefinition); + } + + static protected Database createDatabaseIfNotExists(AsyncDocumentClient client, String databaseId) { + return client.queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseId), null).flatMap(p -> Flux.fromIterable(p.results())).switchIfEmpty( + Flux.defer(() -> { + + Database databaseDefinition = new Database(); + databaseDefinition.id(databaseId); + + return client.createDatabase(databaseDefinition, null).map(ResourceResponse::getResource); + }) + ).single().block(); + } + + static protected void safeDeleteDatabase(AsyncDocumentClient client, Database database) { + if (database != null) { + safeDeleteDatabase(client, database.id()); + } + } + + static protected void safeDeleteDatabase(AsyncDocumentClient client, String databaseId) { + if (client != null) { + try { + client.deleteDatabase(TestUtils.getDatabaseNameLink(databaseId), null).single().block(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteAllCollections(AsyncDocumentClient client, Database database) { + if (database != null) { + List collections = client.readCollections(database.selfLink(), null) + .flatMap(p -> Flux.fromIterable(p.results())) + .collectList() + .single() + .block(); + + for (DocumentCollection collection : collections) { + client.deleteCollection(collection.selfLink(), null).single().block().getResource(); + } + } + } + + static protected void safeDeleteCollection(AsyncDocumentClient client, DocumentCollection collection) { + if (client != null && collection != null) { + try { + client.deleteCollection(collection.selfLink(), null).single().block(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteCollection(AsyncDocumentClient client, String databaseId, String collectionId) { + if (client != null && databaseId != null && collectionId != null) { + try { + client.deleteCollection("/dbs/" + databaseId + "/colls/" + collectionId, null).single().block(); + } catch (Exception e) { + } + } + } + + static protected void safeCloseAsync(AsyncDocumentClient client) { + if (client != null) { + new Thread(() -> { + try { + client.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + } + + static protected void safeClose(AsyncDocumentClient client) { + if (client != null) { + try { + client.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void validateSuccess(Flux> observable, + ResourceResponseValidator validator) { + validateSuccess(observable, validator, subscriberValidationTimeout); + } + + public static void validateSuccess(Flux> observable, + ResourceResponseValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public void validateFailure(Flux> observable, + FailureValidator validator) { + validateFailure(observable, validator, subscriberValidationTimeout); + } + + public static void validateFailure(Flux> observable, + FailureValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + public void validateQuerySuccess(Flux> observable, + FeedResponseListValidator validator) { + validateQuerySuccess(observable, validator, subscriberValidationTimeout); + } + + public static void validateQuerySuccess(Flux> observable, + FeedResponseListValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + validator.validate(testSubscriber.values()); + } + + public void validateQueryFailure(Flux> observable, + FailureValidator validator) { + validateQueryFailure(observable, validator, subscriberValidationTimeout); + } + + public static void validateQueryFailure(Flux> observable, + FailureValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + @DataProvider + public static Object[][] clientBuilders() { + return new Object[][]{{createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)}}; + } + + @DataProvider + public static Object[][] clientBuildersWithSessionConsistency() { + return new Object[][]{ + {createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)}, + {createDirectRxDocumentClient(ConsistencyLevel.SESSION, Protocol.HTTPS, false, null)}, + {createDirectRxDocumentClient(ConsistencyLevel.SESSION, Protocol.TCP, false, null)} + }; + } + + private static ConsistencyLevel parseConsistency(String consistency) { + if (consistency != null) { + consistency = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, consistency).trim(); + return ConsistencyLevel.valueOf(consistency); + } + + logger.error("INVALID configured test consistency [{}].", consistency); + throw new IllegalStateException("INVALID configured test consistency " + consistency); + } + + static List parsePreferredLocation(String preferredLocations) { + if (StringUtils.isEmpty(preferredLocations)) { + return null; + } + + try { + return objectMapper.readValue(preferredLocations, new TypeReference>() { + }); + } catch (Exception e) { + logger.error("INVALID configured test preferredLocations [{}].", preferredLocations); + throw new IllegalStateException("INVALID configured test preferredLocations " + preferredLocations); + } + } + + static List parseProtocols(String protocols) { + if (StringUtils.isEmpty(protocols)) { + return null; + } + List protocolList = new ArrayList<>(); + try { + List protocolStrings = objectMapper.readValue(protocols, new TypeReference>() { + }); + for(String protocol : protocolStrings) { + protocolList.add(Protocol.valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, protocol))); + } + return protocolList; + } catch (Exception e) { + logger.error("INVALID configured test protocols [{}].", protocols); + throw new IllegalStateException("INVALID configured test protocols " + protocols); + } + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirect() { + return simpleClientBuildersWithDirect(toArray(protocols)); + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirectHttps() { + return simpleClientBuildersWithDirect(Protocol.HTTPS); + } + + private static Object[][] simpleClientBuildersWithDirect(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + List testConsistencies = ImmutableList.of(ConsistencyLevel.EVENTUAL); + + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.SESSION; + + List builders = new ArrayList<>(); + builders.add(createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + b.getConnectionPolicy().connectionMode(), + b.getDesiredConsistencyLevel(), + b.getConfigs().getProtocol() + )); + + return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + @DataProvider + public static Object[][] clientBuildersWithDirect() { + return clientBuildersWithDirectAllConsistencies(toArray(protocols)); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectHttps() { + return clientBuildersWithDirectAllConsistencies(Protocol.HTTPS); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectSession() { + return clientBuildersWithDirectSession(toArray(protocols)); + } + + static Protocol[] toArray(List protocols) { + return protocols.toArray(new Protocol[0]); + } + + private static Object[][] clientBuildersWithDirectSession(Protocol... protocols) { + return clientBuildersWithDirect(new ArrayList() {{ + add(ConsistencyLevel.SESSION); + }}, protocols); + } + + private static Object[][] clientBuildersWithDirectAllConsistencies(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + return clientBuildersWithDirect(desiredConsistencies, protocols); + } + + static List parseDesiredConsistencies(String consistencies) { + if (StringUtils.isEmpty(consistencies)) { + return null; + } + List consistencyLevels = new ArrayList<>(); + try { + List consistencyStrings = objectMapper.readValue(consistencies, new TypeReference>() {}); + for(String consistency : consistencyStrings) { + consistencyLevels.add(ConsistencyLevel.valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, consistency))); + } + return consistencyLevels; + } catch (Exception e) { + logger.error("INVALID consistency test desiredConsistencies [{}].", consistencies); + throw new IllegalStateException("INVALID configured test desiredConsistencies " + consistencies); + } + } + + static List allEqualOrLowerConsistencies(ConsistencyLevel accountConsistency) { + List testConsistencies = new ArrayList<>(); + switch (accountConsistency) { + case STRONG: + testConsistencies.add(ConsistencyLevel.STRONG); + case BOUNDED_STALENESS: + testConsistencies.add(ConsistencyLevel.BOUNDED_STALENESS); + case SESSION: + testConsistencies.add(ConsistencyLevel.SESSION); + case CONSISTENT_PREFIX: + testConsistencies.add(ConsistencyLevel.CONSISTENT_PREFIX); + case EVENTUAL: + testConsistencies.add(ConsistencyLevel.EVENTUAL); + break; + default: + throw new IllegalStateException("INVALID configured test consistency " + accountConsistency); + } + return testConsistencies; + } + + private static Object[][] clientBuildersWithDirect(List testConsistencies, Protocol... protocols) { + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.SESSION; + + List builders = new ArrayList<>(); + builders.add(createGatewayRxDocumentClient(ConsistencyLevel.SESSION, isMultiMasterEnabled, preferredLocations)); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + b.getConnectionPolicy().connectionMode(), + b.getDesiredConsistencyLevel(), + b.getConfigs().getProtocol() + )); + + return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + static protected Builder createGatewayHouseKeepingDocumentClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + RetryOptions options = new RetryOptions(); + options.maxRetryWaitTimeInSeconds(SUITE_SETUP_TIMEOUT); + connectionPolicy.retryOptions(options); + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION); + } + + static protected Builder createGatewayRxDocumentClient(ConsistencyLevel consistencyLevel, boolean multiMasterEnabled, List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + connectionPolicy.usingMultipleWriteLocations(multiMasterEnabled); + connectionPolicy.preferredLocations(preferredLocations); + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(consistencyLevel); + } + + static protected Builder createGatewayRxDocumentClient() { + return createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null); + } + + static protected Builder createDirectRxDocumentClient(ConsistencyLevel consistencyLevel, + Protocol protocol, + boolean multiMasterEnabled, + List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + + if (preferredLocations != null) { + connectionPolicy.preferredLocations(preferredLocations); + } + + if (multiMasterEnabled && consistencyLevel == ConsistencyLevel.SESSION) { + connectionPolicy.usingMultipleWriteLocations(true); + } + + Configs configs = spy(new Configs()); + doAnswer((Answer)invocation -> protocol).when(configs).getProtocol(); + + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(consistencyLevel) + .withConfigs(configs); + } + + protected int expectedNumberOfPages(int totalExpectedResult, int maxPageSize) { + return Math.max((totalExpectedResult + maxPageSize - 1 ) / maxPageSize, 1); + } + + @DataProvider(name = "queryMetricsArgProvider") + public Object[][] queryMetricsArgProvider() { + return new Object[][]{ + {true}, + {false}, + }; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestUtils.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestUtils.java new file mode 100644 index 0000000000000..1c8ef3590d025 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TestUtils.java @@ -0,0 +1,60 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal; + +public class TestUtils { + private static final String DATABASES_PATH_SEGMENT = "dbs"; + private static final String COLLECTIONS_PATH_SEGMENT = "colls"; + private static final String DOCUMENTS_PATH_SEGMENT = "docs"; + private static final String USERS_PATH_SEGMENT = "users"; + + public static String getDatabaseLink(Database database, boolean isNameBased) { + if (isNameBased) { + return getDatabaseNameLink(database.id()); + } else { + return database.selfLink(); + } + } + + public static String getDatabaseNameLink(String databaseId) { + return DATABASES_PATH_SEGMENT + "/" + databaseId; + } + + public static String getCollectionNameLink(String databaseId, String collectionId) { + + return DATABASES_PATH_SEGMENT + "/" + databaseId + "/" + COLLECTIONS_PATH_SEGMENT + "/" + collectionId; + } + + public static String getDocumentNameLink(String databaseId, String collectionId, String docId) { + + return DATABASES_PATH_SEGMENT + "/" + databaseId + "/" + COLLECTIONS_PATH_SEGMENT + "/" +collectionId + "/" + DOCUMENTS_PATH_SEGMENT + "/" + docId; + } + + public static String getUserNameLink(String databaseId, String userId) { + + return DATABASES_PATH_SEGMENT + "/" + databaseId + "/" + USERS_PATH_SEGMENT + "/" + userId; + } + + private TestUtils() { + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TimeTokenTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TimeTokenTest.java new file mode 100644 index 0000000000000..8cc1477868426 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/TimeTokenTest.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal; + +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +public class TimeTokenTest { + + private Locale defaultLocale; + + @BeforeTest(groups = { "unit" }) + public void beforeMethod() { + defaultLocale = Locale.getDefault(); + } + + @Test(groups = { "unit" }) + public void nonLocaleUS() { + Locale.setDefault(Locale.ITALIAN); + DateTimeFormatter RFC_1123_DATE_TIME = + DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + String time = Utils.nowAsRFC1123(); + Locale.setDefault(Locale.US); + RFC_1123_DATE_TIME.parse(time); + } + + @AfterTest(groups = { "unit" }) + public void afterMethod() { + // set back default locale before test + if (defaultLocale != null) { + Locale.setDefault(defaultLocale); + } else { + Locale.setDefault(Locale.US); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/caches/AsyncCacheTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/caches/AsyncCacheTest.java new file mode 100644 index 0000000000000..1df2b6547073c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/caches/AsyncCacheTest.java @@ -0,0 +1,89 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.caches; + +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AsyncCacheTest { + + private static final int TIMEOUT = 2000; + + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void getAsync() { + AtomicInteger numberOfCacheRefreshes = new AtomicInteger(0); + final Function> refreshFunc = key -> { + numberOfCacheRefreshes.incrementAndGet(); + return Mono.just(key*2); + }; + + AsyncCache cache = new AsyncCache<>(); + + List> tasks = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + int key = j; + tasks.add(cache.getAsync(key, -1, () -> refreshFunc.apply(key))); + } + } + + Flux o = Flux.merge(tasks.stream().map(Mono::flux).collect(Collectors.toList())); + o.collectList().single().block(); + + assertThat(numberOfCacheRefreshes.get()).isEqualTo(10); + assertThat(cache.getAsync(2, -1, () -> refreshFunc.apply(2)).block()).isEqualTo(4); + + Function> refreshFunc1 = key -> { + numberOfCacheRefreshes.incrementAndGet(); + return Mono.just(key * 2 + 1); + }; + + List> tasks1 = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + int key = j; + tasks1.add(cache.getAsync(key, key * 2, () -> refreshFunc1.apply(key))); + } + + for (int j = 0; j < 10; j++) { + int key = j; + tasks1.add(cache.getAsync(key, key * 2 , () -> refreshFunc1.apply(key))); + } + } + + Flux o1 = Flux.merge(tasks1.stream().map(Mono::flux).collect(Collectors.toList())); + o1.collectList().single().block(); + + assertThat(numberOfCacheRefreshes.get()).isEqualTo(20); + assertThat(cache.getAsync(2, -1, () -> refreshFunc.apply(2)).block()).isEqualTo(5); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolverTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolverTest.java new file mode 100644 index 0000000000000..64676e488db0b --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressResolverTest.java @@ -0,0 +1,993 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + + +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.ICollectionRoutingMapCache; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.IServerIdentity; +import com.azure.data.cosmos.internal.routing.InMemoryCollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.mutable.MutableObject; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.fail; + +/** + * Tests that partition manager correctly resolves addresses for requests and does appropriate number of cache refreshes. + */ +public class AddressResolverTest { + + private static final Logger logger = LoggerFactory.getLogger(AddressResolverTest.class); + private static final String DOCUMENT_TEST_URL = "dbs/IXYFAA==/colls/IXYFAOHEBPM=/docs/IXYFAOHEBPMBAAAAAAAAAA==/"; + private AddressResolver addressResolver; + private RxCollectionCache collectionCache; + private ICollectionRoutingMapCache collectionRoutingMapCache; + private IAddressCache fabricAddressCache; + + private int collectionCacheRefreshedCount; + private Map routingMapRefreshCount; + private Map addressesRefreshCount; + + @BeforeClass(groups = "unit") + public void setup() throws Exception { + this.addressResolver = new AddressResolver(); + this.collectionCache = Mockito.mock(RxCollectionCache.class); + this.collectionRoutingMapCache = Mockito.mock(ICollectionRoutingMapCache.class); + this.fabricAddressCache = Mockito.mock(IAddressCache.class); + this.addressResolver.initializeCaches(this.collectionCache, this.collectionRoutingMapCache, this.fabricAddressCache); + + this.collection1 = new DocumentCollection(); + this.collection1.id("coll"); + this.collection1.resourceId("rid1"); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + partitionKeyDef.paths(ImmutableList.of("/field1")); + this.collection1.setPartitionKey(partitionKeyDef); + + this.collection2 = new DocumentCollection(); + this.collection2.id("coll"); + this.collection2.resourceId("rid2"); + new PartitionKeyDefinition(); + partitionKeyDef.paths(ImmutableList.of("/field1")); + this.collection2.setPartitionKey(partitionKeyDef); + + Function>, Void> addPartitionKeyRangeFunc = listArg -> { + listArg.forEach(tuple -> ((ServiceIdentity) tuple.right).partitionKeyRangeIds.add(new PartitionKeyRangeIdentity(collection1.resourceId(), tuple.left.id()))); + return null; + }; + + List> rangesBeforeSplit1 = + new ArrayList<>(); + ServiceIdentity serverServiceIdentity = new ServiceIdentity("federation1", new URI("fabric://serverservice1"), false); + + rangesBeforeSplit1.add( + ImmutablePair.of(new PartitionKeyRange("0", PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, + PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey), serverServiceIdentity)); + + addPartitionKeyRangeFunc.apply(rangesBeforeSplit1); + + + this.routingMapCollection1BeforeSplit = + InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap( + rangesBeforeSplit1, + collection1.resourceId()); + + List> rangesAfterSplit1 = + new ArrayList<>(); + ServiceIdentity serverServiceIdentity2 = new ServiceIdentity("federation1", new URI("fabric://serverservice2"), false); + ServiceIdentity serverServiceIdentity3 = new ServiceIdentity("federation1", new URI("fabric://serverservice3"), false); + + rangesAfterSplit1.add( + ImmutablePair.of( + new PartitionKeyRange("1", PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, "5E", ImmutableList.of("0")), + serverServiceIdentity2)); + + rangesAfterSplit1.add( + ImmutablePair.of( + new PartitionKeyRange("2", "5E", PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey, ImmutableList.of("0")), + serverServiceIdentity3)); + + addPartitionKeyRangeFunc.apply(rangesAfterSplit1); + + this.routingMapCollection1AfterSplit = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(rangesAfterSplit1, collection1.resourceId()); + + List> rangesBeforeSplit2 = + new ArrayList<>(); + ServiceIdentity serverServiceIdentity4 = new ServiceIdentity("federation1", new URI("fabric://serverservice4"), false); + + rangesBeforeSplit2.add( + ImmutablePair.of( + new PartitionKeyRange("0", PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey), + serverServiceIdentity4)); + + addPartitionKeyRangeFunc.apply(rangesBeforeSplit2); + + + this.routingMapCollection2BeforeSplit = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(rangesBeforeSplit2, collection2.resourceId()); + + List> rangesAfterSplit2 = + new ArrayList<>(); + + ServiceIdentity serverServiceIdentity5 = new ServiceIdentity("federation1", new URI("fabric://serverservice5"), false); + ServiceIdentity serverServiceIdentity6 = new ServiceIdentity("federation1", new URI("fabric://serverservice6"), false); + rangesAfterSplit2.add( + ImmutablePair.of( + new PartitionKeyRange("1", PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, "5E", ImmutableList.of("0")), + serverServiceIdentity5)); + + rangesAfterSplit2.add( + ImmutablePair.of( + new PartitionKeyRange("2", "5E", PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey, ImmutableList.of("0")), + serverServiceIdentity6)); + + + addPartitionKeyRangeFunc.apply(rangesAfterSplit2); + + + this.routingMapCollection2AfterSplit = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(rangesAfterSplit2, collection2.resourceId()); + } + + private void TestCacheRefreshWhileRouteByPartitionKey( + DocumentCollection collectionBeforeRefresh, + DocumentCollection collectionAfterRefresh, + Map routingMapBeforeRefresh, + Map routingMapAfterRefresh, + Map addressesBeforeRefresh, + Map addressesAfterRefresh, + AddressInformation[] targetAddresses, + ServiceIdentity targetServiceIdentity, + PartitionKeyRange targetPartitionKeyRange, + boolean forceNameCacheRefresh, + boolean forceRoutingMapRefresh, + boolean forceAddressRefresh, + int collectionCacheRefreshed, + int routingMapCacheRefreshed, + int addressCacheRefreshed, + boolean nameBased) throws Exception { + + if (targetServiceIdentity != null && targetPartitionKeyRange != null) { + targetServiceIdentity.partitionKeyRangeIds.add(new PartitionKeyRangeIdentity(collectionAfterRefresh != null ? collectionAfterRefresh.resourceId() : collectionBeforeRefresh.resourceId(), targetPartitionKeyRange.id())); + } + + this.initializeMocks( + collectionBeforeRefresh, + collectionAfterRefresh, + routingMapBeforeRefresh, + routingMapAfterRefresh, + addressesBeforeRefresh, + addressesAfterRefresh); + + RxDocumentServiceRequest request; + if (nameBased) { + request = RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.Document, + "dbs/db/colls/coll/docs/doc1", + new HashMap<>()); + } else { + request = RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.Document, + DOCUMENT_TEST_URL, + new HashMap<>()); + } + + request.forceNameCacheRefresh = forceNameCacheRefresh; + request.forcePartitionKeyRangeRefresh = forceRoutingMapRefresh; + request.getHeaders().put(HttpConstants.HttpHeaders.PARTITION_KEY, new PartitionKey("foo").toString()); + AddressInformation[] resolvedAddresses; + try { + resolvedAddresses = this.addressResolver.resolveAsync(request, forceAddressRefresh).block(); + } catch (RuntimeException e) { + throw (Exception) e.getCause(); + } finally { + assertThat(collectionCacheRefreshed).isEqualTo(collectionCacheRefreshedCount).describedAs("collection cache refresh count mismath"); + + assertThat(routingMapCacheRefreshed).isEqualTo(routingMapRefreshCount.values().stream().mapToInt(v -> v).sum()).describedAs("routing map cache refresh count mismath"); + assertThat(addressCacheRefreshed).isEqualTo(addressesRefreshCount.values().stream().mapToInt(v -> v).sum()).describedAs("address cache refresh count mismatch"); + assertThat(routingMapRefreshCount.entrySet().stream().filter(pair -> pair.getValue() > 1).count()).isEqualTo(0); + assertThat(addressesRefreshCount.entrySet().stream().filter(pair -> pair.getValue() > 1).count()).isEqualTo(0); + } + + assertThat(targetAddresses[0].getPhysicalUri()).isEqualTo(resolvedAddresses[0].getPhysicalUri()); + // Assert.AreEqual(targetServiceIdentity, request.requestContext.TargetIdentity); + assertThat(targetPartitionKeyRange.id()).isEqualTo(request.requestContext.resolvedPartitionKeyRange.id()); + } + + private void TestCacheRefreshWhileRouteByPartitionKeyRangeId( + DocumentCollection collectionBeforeRefresh, + DocumentCollection collectionAfterRefresh, + Map routingMapBeforeRefresh, + Map routingMapAfterRefresh, + Map addressesBeforeRefresh, + Map addressesAfterRefresh, + PartitionKeyRangeIdentity rangeIdentity, + AddressInformation[] targetAddresses, + ServiceIdentity targetServiceIdentity, + PartitionKeyRange targetPartitionKeyRange, + boolean forceNameCacheRefresh, + boolean forceRoutingMapRefresh, + boolean forceAddressRefresh, + int collectionCacheRefreshed, + int routingMapCacheRefreshed, + int addressCacheRefreshed, + boolean nameBased) throws Exception { + + if (targetServiceIdentity != null && targetPartitionKeyRange != null) { + targetServiceIdentity.partitionKeyRangeIds.add(new PartitionKeyRangeIdentity(collectionAfterRefresh != null ? collectionAfterRefresh.resourceId() : collectionBeforeRefresh.resourceId(), targetPartitionKeyRange.id())); + } + + this.initializeMocks( + collectionBeforeRefresh, + collectionAfterRefresh, + routingMapBeforeRefresh, + routingMapAfterRefresh, + addressesBeforeRefresh, + addressesAfterRefresh); + + RxDocumentServiceRequest request; + if (nameBased) { + request = RxDocumentServiceRequest.createFromName( + OperationType.Read, + "dbs/db/colls/coll/docs/doc1", + ResourceType.Document); + } else { + request = RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.Document, + DOCUMENT_TEST_URL, + new HashMap<>()); + } + + request.forceNameCacheRefresh = forceNameCacheRefresh; + request.forcePartitionKeyRangeRefresh = forceRoutingMapRefresh; + request.routeTo(rangeIdentity); + AddressInformation[] resolvedAddresses; + try { + resolvedAddresses = this.addressResolver.resolveAsync(request, forceAddressRefresh).block(); + } catch (RuntimeException e) { + throw (Exception) e.getCause(); + } finally { + assertThat(collectionCacheRefreshed).isEqualTo(collectionCacheRefreshedCount).describedAs("collection cache refresh count mismath"); + + assertThat(routingMapCacheRefreshed).isEqualTo(routingMapRefreshCount.values().stream().mapToInt(v -> v).sum()).describedAs("routing map cache refresh count mismath"); + assertThat(addressCacheRefreshed).isEqualTo(addressesRefreshCount.values().stream().mapToInt(v -> v).sum()).describedAs("address cache refresh count mismatch"); + + + assertThat(routingMapRefreshCount.entrySet().stream().filter(pair -> pair.getValue() > 1).count()).isEqualTo(0); + assertThat(addressesRefreshCount.entrySet().stream().filter(pair -> pair.getValue() > 1).count()).isEqualTo(0); + } + + assertThat(targetAddresses[0].getPhysicalUri()).isEqualTo(resolvedAddresses[0].getPhysicalUri()); + // Assert.AreEqual(targetServiceIdentity, request.requestContext.TargetIdentity); + assertThat(targetPartitionKeyRange.id()).isEqualTo(request.requestContext.resolvedPartitionKeyRange.id()); + } + + private void initializeMocks( + DocumentCollection collectionBeforeRefresh, + DocumentCollection collectionAfterRefresh, + Map routingMapBeforeRefresh, + Map routingMapAfterRefreshInitial, + Map addressesBeforeRefresh, + Map addressesAfterRefreshInitial) { + final Map routingMapAfterRefresh = ObjectUtils.defaultIfNull(routingMapAfterRefreshInitial, routingMapBeforeRefresh); + final Map addressesAfterRefresh = ObjectUtils.defaultIfNull(addressesAfterRefreshInitial, addressesBeforeRefresh); + + // Collection cache + MutableObject currentCollection = new MutableObject(collectionBeforeRefresh); + this.collectionCacheRefreshedCount = 0; + + Mockito.doAnswer(invocationOnMock -> { + RxDocumentServiceRequest request = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + if (request.forceNameCacheRefresh && collectionAfterRefresh != null) { + currentCollection.setValue(collectionAfterRefresh); + AddressResolverTest.this.collectionCacheRefreshedCount++; + request.forceNameCacheRefresh = false; + return Mono.just(currentCollection.getValue()); + } + + if (request.forceNameCacheRefresh && collectionAfterRefresh == null) { + currentCollection.setValue(null); + AddressResolverTest.this.collectionCacheRefreshedCount++; + request.forceNameCacheRefresh = false; + return Mono.error(new NotFoundException()); + } + + if (!request.forceNameCacheRefresh && currentCollection.getValue() == null) { + return Mono.error(new NotFoundException()); + + } + + if (!request.forceNameCacheRefresh && currentCollection.getValue() != null) { + return Mono.just(currentCollection.getValue()); + } + + return Mono.empty(); + }).when(this.collectionCache).resolveCollectionAsync(Mockito.any(RxDocumentServiceRequest.class)); + + // Routing map cache + Map currentRoutingMap = + new HashMap<>(routingMapBeforeRefresh); + this.routingMapRefreshCount = new HashMap<>(); + + Mockito.doAnswer(invocationOnMock -> { + String collectionRid = invocationOnMock.getArgumentAt(0, String.class); + CollectionRoutingMap previousValue = invocationOnMock.getArgumentAt(1, CollectionRoutingMap.class); + + return collectionRoutingMapCache.tryLookupAsync(collectionRid, previousValue, false, null); + }).when(this.collectionRoutingMapCache).tryLookupAsync(Mockito.anyString(), Mockito.any(CollectionRoutingMap.class), Mockito.anyMap()); + + // Refresh case + Mockito.doAnswer(invocationOnMock -> { + String collectionRid = invocationOnMock.getArgumentAt(0, String.class); + CollectionRoutingMap previousValue = invocationOnMock.getArgumentAt(1, CollectionRoutingMap.class); + + if (previousValue == null) { + return Mono.justOrEmpty(currentRoutingMap.get(collectionRid)); + } + + if (previousValue != null && currentRoutingMap.containsKey(previousValue.getCollectionUniqueId()) && + currentRoutingMap.get(previousValue.getCollectionUniqueId()) == previousValue) { + + + if (previousValue != null && previousValue.getCollectionUniqueId() != collectionRid) { + throw new RuntimeException("InvalidOperation"); + } + + if (routingMapAfterRefresh.containsKey(collectionRid)) { + currentRoutingMap.put(collectionRid, routingMapAfterRefresh.get(collectionRid)); + } else { + currentRoutingMap.remove(collectionRid); + } + + if (!routingMapRefreshCount.containsKey(collectionRid)) { + routingMapRefreshCount.put(collectionRid, 1); + } else { + routingMapRefreshCount.put(collectionRid, routingMapRefreshCount.get(collectionRid) + 1); + } + + + return Mono.justOrEmpty(currentRoutingMap.get(collectionRid)); + } + + return Mono.error(new NotImplementedException("not mocked")); + }).when(this.collectionRoutingMapCache).tryLookupAsync(Mockito.anyString(), Mockito.any(CollectionRoutingMap.class), Mockito.anyBoolean(), Mockito.anyMap()); + + + // Fabric Address Cache + Map currentAddresses = + new HashMap<>(addressesBeforeRefresh); + this.addressesRefreshCount = new HashMap<>(); + + // No refresh case + // + Mockito.doAnswer(invocationOnMock -> { + RxDocumentServiceRequest request = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + PartitionKeyRangeIdentity pkri = invocationOnMock.getArgumentAt(1, PartitionKeyRangeIdentity.class); + Boolean forceRefresh = invocationOnMock.getArgumentAt(2, Boolean.class); + + if (!forceRefresh) { + return Mono.justOrEmpty(currentAddresses.get(findMatchingServiceIdentity(currentAddresses, pkri))); + } else { + + ServiceIdentity si; + + if ((si = findMatchingServiceIdentity(addressesAfterRefresh, pkri)) != null) { + currentAddresses.put(si, addressesAfterRefresh.get(si)); + } else { + + si = findMatchingServiceIdentity(currentAddresses, pkri); + currentAddresses.remove(si); + } + + if (si == null) { + si = ServiceIdentity.dummyInstance; + } + + if (!addressesRefreshCount.containsKey(si)) { + addressesRefreshCount.put(si, 1); + } else { + addressesRefreshCount.put(si, addressesRefreshCount.get(si) + 1); + } + + // TODO: what to return in this case if it is null!! + return Mono.justOrEmpty(currentAddresses.get(si)); + } + }).when(fabricAddressCache).tryGetAddresses(Mockito.any(RxDocumentServiceRequest.class), Mockito.any(PartitionKeyRangeIdentity.class), Mockito.anyBoolean()); + } + + private static ServiceIdentity findMatchingServiceIdentity(Map map, PartitionKeyRangeIdentity pkri) { + for (ServiceIdentity si : map.keySet()) { + if (si.partitionKeyRangeIds.contains(pkri)) { + return si; + } + + } + return null; + } + + private final AddressInformation[] addresses1 = {new AddressInformation(true, true, "tcp://host/partition1", Protocol.HTTPS)}; + private final AddressInformation[] addresses2 = {new AddressInformation(true, true, "tcp://host/partition2", Protocol.HTTPS)}; + private final AddressInformation[] addresses3 = {new AddressInformation(true, true, "tcp://host/partition3", Protocol.HTTPS)}; + + private DocumentCollection collection1; + private DocumentCollection collection2; + private CollectionRoutingMap routingMapCollection1BeforeSplit; + private CollectionRoutingMap routingMapCollection1AfterSplit; + private CollectionRoutingMap routingMapCollection2BeforeSplit; + private CollectionRoutingMap routingMapCollection2AfterSplit; + + @Test(groups = "unit") + public void testCacheRefreshesWhileRoutingByPartitionKey() throws Exception { + logger.info("ALL caches are up to date. Name Based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 0, + 0, + 0, + true); + + logger.info("ALL caches are up to date. Rid Based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 0, + 0, + 0, + true); + + logger.info("Address cache is stale. Force Refresh. Name Based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses2), + this.addresses2, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + this.routingMapCollection1BeforeSplit.getOrderedPartitionKeyRanges().get(0), + false, + false, + true, + 0, + 0, + 1, + true); + + logger.info("Address cache is stale. Force Refresh. Rid Based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses2), + this.addresses2, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + true, + 0, + 0, + 1, + false); + + logger.info("Routing map cache is stale. Force Refresh. Name based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + ImmutableMap.of( + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses2, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 1), this.addresses3), + null, + this.addresses2, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + true, + false, + 0, + 1, + 0, + true); + + logger.info("Routing map cache is stale. Force Refresh. Rid based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + ImmutableMap.of( + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses2, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 1), this.addresses3), + null, + this.addresses2, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + true, + false, + 0, + 1, + 0, + false); + + logger.info("Name cache is stale. Force Refresh. Name based"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection2, + ImmutableMap.of(this.collection2.resourceId(), this.routingMapCollection2BeforeSplit), + null, + ImmutableMap.of( + getServiceIdentityAt(this.routingMapCollection2BeforeSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection2BeforeSplit, 0), + getRangeAt(this.routingMapCollection2BeforeSplit, 0), + true, + false, + false, + 1, + 0, + 0, + true); + + logger.info("Name cache is stale (collection deleted new one created same name). Routing Map Cache returns null"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection2, + ImmutableMap.of(this.collection2.resourceId(), this.routingMapCollection2BeforeSplit), + null, + ImmutableMap.of( + getServiceIdentityAt(this.routingMapCollection2BeforeSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection2BeforeSplit, 0), + getRangeAt(this.routingMapCollection2BeforeSplit, 0), + false, + false, + false, + 1, + 0, + 0, + true); + + logger.info("Routing map cache is stale (split happened). Address Cache returns null"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 1, + 1, + 0, + true); + + + logger.info("Collection cache is stale (deleted created same name). Routing map cache is stale for new collection (split happened). Address Cache returns null"); + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + this.collection2, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit, + this.collection2.resourceId(), this.routingMapCollection2BeforeSplit), + ImmutableMap.of(this.collection2.resourceId(), this.routingMapCollection2AfterSplit), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection2AfterSplit, 0), this.addresses1), + null, + this.addresses1, + getServiceIdentityAt(this.routingMapCollection2AfterSplit, 0), + getRangeAt(this.routingMapCollection2AfterSplit, 0), + false, + false, + false, + 1, + 1, + 0, + true); + + logger.info("Collection cache is stale (collection deleted). Routing map cache is stale (collection deleted). Address Cache returns null"); + try { + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + null, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(), + ImmutableMap.of(), + null, + null, + null, + null, + false, + false, + false, + 1, + 0, + 0, + true); + + fail("Expected NotFoundException"); + } catch (NotFoundException e) { + } + + logger.info("Collection cache is stale (collection deleted). Routing map cache returns null."); + try { + this.TestCacheRefreshWhileRouteByPartitionKey( + this.collection1, + null, + ImmutableMap.of(), + null, + ImmutableMap.of(), + null, + null, + null, + null, + false, + false, + false, + 1, + 0, + 0, + true); + + fail("Expected NotFoundException"); + } catch (NotFoundException e) { + } + } + + private static PartitionKeyRange getRangeAt(CollectionRoutingMap routingMap, int index) { + return routingMap.getOrderedPartitionKeyRanges().get(index); + } + + private static ServiceIdentity getServiceIdentityAt(CollectionRoutingMap routingMap, int index) { + return (ServiceIdentity) routingMap.tryGetInfoByPartitionKeyRangeId(routingMap.getOrderedPartitionKeyRanges().get(index).id()); + } + + @Test(groups = "unit") + public void testCacheRefreshesWhileRoutingByPartitionKeyRangeId() throws Exception { + logger.info("ALL caches are up to date. Name Based"); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(this.collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 0, + 0, + 0, + true); + + logger.info("ALL caches are up to date. Name Based. Non existent range with collection rid"); + try { + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(this.collection1.resourceId(), "1"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 0, + 1, + 0, + true); + + fail("Should have gotten PartitionKeyRangeGoneException"); + } catch (PartitionKeyRangeGoneException e) { + } + + logger.info("ALL caches are up to date. Name Based. Non existent range withOUT collection rid"); + try { + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity("1"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 1, + 1, + 0, + true); + + fail("Should have gotten PartitionKeyRangeGoneException"); + } catch (PartitionKeyRangeGoneException e) { + } + + logger.info("ALL caches are up to date. Name Based.RANGE doesn't exist in routing map because split happened."); + try { + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + null, + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1BeforeSplit, 0), + getRangeAt(this.routingMapCollection1BeforeSplit, 0), + false, + false, + false, + 0, + 0, + 0, + true); + + fail("Should have gotten PartitionKeyRangeGoneException"); + } catch (PartitionKeyRangeGoneException e) { + } + + try { + logger.info("Name Based.Routing map cache is outdated because split happened. Address cache returns null."); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 0, + 1, + 0, + true); + + fail("Should have gotten PartitionKeyRangeGoneException"); + } catch (PartitionKeyRangeGoneException e) { + } + + logger.info("Name Based.Routing map cache is outdated because split happened."); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection1, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1AfterSplit), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(collection1.resourceId(), "1"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 0, + 1, + 0, + true); + + try { + logger.info("Collection cache is outdated. Routing map cache returns null. Collection is deleted. RANGE with collection rid."); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + null, + ImmutableMap.of(), + ImmutableMap.of(), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 0, + 0, + 0, + true); + + fail("Should have gotten InvalidPartitionException"); + } catch (InvalidPartitionException e) { + } + + try { + logger.info("Collection cache is outdated. Routing map cache returns null. Collection is deleted. RANGE without collection rid"); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + null, + ImmutableMap.of(), + ImmutableMap.of(), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity("0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 1, + 0, + 0, + true); + + fail("Should have gotten NotFoundException"); + } catch (NotFoundException e) { + } + + try { + logger.info("Collection cache is outdated. Routing map cache returns null. Collection is deleted. RANGE with collection rid. Rid based."); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + null, + ImmutableMap.of(), + ImmutableMap.of(), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + null, + new PartitionKeyRangeIdentity(collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + false, + 0, + 0, + 0, + false); + + fail("Should have gotten NotFoundException"); + } catch (NotFoundException e) { + } + + try { + logger.info("Collection cache is outdated. Routing map cache is outdated. Address cache is outdated. ForceAddressRefresh. RANGE with collection rid. Name based."); + this.TestCacheRefreshWhileRouteByPartitionKeyRangeId( + this.collection1, + this.collection2, + ImmutableMap.of(this.collection1.resourceId(), this.routingMapCollection1BeforeSplit), + ImmutableMap.of(this.collection2.resourceId(), this.routingMapCollection2BeforeSplit), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), this.addresses1), + ImmutableMap.of(getServiceIdentityAt(this.routingMapCollection2AfterSplit, 0), this.addresses2), + new PartitionKeyRangeIdentity(collection1.resourceId(), "0"), + this.addresses1, + getServiceIdentityAt(this.routingMapCollection1AfterSplit, 0), + getRangeAt(this.routingMapCollection1AfterSplit, 0), + false, + false, + true, + 0, + 1, + 1, + true); + + fail("Should have gotten InvalidPartitionException"); + } catch (InvalidPartitionException e) { + } + } + + static class ServiceIdentity implements IServerIdentity { + final boolean IsMasterService; + final URI ServiceName; + final String FederationId; + final Set partitionKeyRangeIds; + final static ServiceIdentity dummyInstance = new ServiceIdentity(null, null, true); + + public ServiceIdentity(String federationId, URI serviceName, boolean isMasterService, PartitionKeyRangeIdentity... partitionKeyRangeIdentities) { + this.FederationId = federationId; + this.ServiceName = serviceName; + this.IsMasterService = isMasterService; + this.partitionKeyRangeIds = new HashSet<>(Arrays.stream(partitionKeyRangeIdentities).collect(Collectors.toList())); + } + } +} + diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorTest.java new file mode 100644 index 0000000000000..c9b786e5246c5 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorTest.java @@ -0,0 +1,198 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.AddressSelector; +import com.azure.data.cosmos.internal.directconnectivity.IAddressResolver; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.AddressSelector; +import com.azure.data.cosmos.internal.directconnectivity.IAddressResolver; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.google.common.collect.ImmutableList; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class AddressSelectorTest { + + @Test(groups = "unit", expectedExceptions = GoneException.class) + public void getPrimaryUri_NoAddress() throws Exception { + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + List replicaAddresses = new ArrayList<>(); + + AddressSelector.getPrimaryUri(request, replicaAddresses); + } + + @Test(groups = "unit", expectedExceptions = GoneException.class, expectedExceptionsMessageRegExp = + "The requested resource is no longer available at the server. Returned addresses are \\{https://cosmos1,https://cosmos2\\}") + public void getPrimaryUri_NoPrimaryAddress() throws Exception { + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos2", Protocol.HTTPS)); + + AddressSelector.getPrimaryUri(request, replicaAddresses); + } + + @Test(groups = "unit") + public void getPrimaryUri() throws Exception { + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + URI res = AddressSelector.getPrimaryUri(request, replicaAddresses); + + assertThat(res).isEqualTo(URI.create("https://cosmos2")); + } + + @Test(groups = "unit") + public void getPrimaryUri_WithRequestReplicaIndex() throws Exception { + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(1).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + URI res = AddressSelector.getPrimaryUri(request, replicaAddresses); + + assertThat(res).isEqualTo(URI.create("https://cosmos2")); + } + + @Test(groups = "unit") + public void resolvePrimaryUriAsync() { + IAddressResolver addressResolver = Mockito.mock(IAddressResolver.class); + AddressSelector selector = new AddressSelector(addressResolver, Protocol.HTTPS); + + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos4", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos5", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + Mockito.doReturn(Mono.just(replicaAddresses.toArray(new AddressInformation[0]))).when(addressResolver).resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Matchers.eq(false)); + + URI res = selector.resolvePrimaryUriAsync(request, false).block(); + + assertThat(res).isEqualTo(URI.create("https://cosmos2")); + } + + @Test(groups = "unit") + public void resolveAllUriAsync() { + IAddressResolver addressResolver = Mockito.mock(IAddressResolver.class); + AddressSelector selector = new AddressSelector(addressResolver, Protocol.HTTPS); + + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos4", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos5", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + Mockito.doReturn(Mono.just(replicaAddresses.toArray(new AddressInformation[0]))).when(addressResolver).resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Matchers.eq(false)); + + List res = selector.resolveAllUriAsync(request, true, false).block(); + + assertThat(res).isEqualTo(ImmutableList.of(URI.create("https://cosmos1"), URI.create("https://cosmos2"), URI.create("https://cosmos3"))); + } + + @Test(groups = "unit") + public void resolveAddressesAsync() { + IAddressResolver addressResolver = Mockito.mock(IAddressResolver.class); + AddressSelector selector = new AddressSelector(addressResolver, Protocol.HTTPS); + + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos4", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos5", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + Mockito.doReturn(Mono.just(replicaAddresses.toArray(new AddressInformation[0]))).when(addressResolver).resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Matchers.eq(false)); + + List res = selector.resolveAddressesAsync(request, false).block(); + + assertThat(res).isEqualTo(replicaAddresses.stream().filter(a -> a.getProtocolName().equals(Protocol.HTTPS.toString())).collect(Collectors.toList())); + } + + @Test(groups = "unit") + public void resolveAllUriAsync_RNTBD() { + IAddressResolver addressResolver = Mockito.mock(IAddressResolver.class); + AddressSelector selector = new AddressSelector(addressResolver, Protocol.TCP); + + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + Mockito.doReturn(null).when(request).getDefaultReplicaIndex(); + + List replicaAddresses = new ArrayList<>(); + + replicaAddresses.add(new AddressInformation(true, false, "rntbd://cosmos1", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, true, "rntbd://cosmos2", Protocol.TCP)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos1", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, true, "https://cosmos2", Protocol.HTTPS)); + replicaAddresses.add(new AddressInformation(true, false, "https://cosmos3", Protocol.HTTPS)); + + Mockito.doReturn(Mono.just(replicaAddresses.toArray(new AddressInformation[0]))).when(addressResolver).resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Matchers.eq(false)); + + List res = selector.resolveAllUriAsync(request, true, false).block(); + + assertThat(res).isEqualTo(ImmutableList.of(URI.create("rntbd://cosmos1"), URI.create("rntbd://cosmos2"))); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorWrapper.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorWrapper.java new file mode 100644 index 0000000000000..6bd4741c34195 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressSelectorWrapper.java @@ -0,0 +1,533 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.AddressSelector; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.AddressSelector; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.google.common.base.Predicates; +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.assertj.core.api.Condition; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AddressSelectorWrapper { + + private static String resolveAllUriAsync = "resolveAllUriAsync"; + private static String resolvePrimaryUriAsync = "resolvePrimaryUriAsync"; + private static String resolveAddressesAsync = "resolveAddressesAsync"; + private final List invocationOnMockList; + + public final AddressSelector addressSelector; + + public static class InOrderVerificationBuilder { + private List> actions = new ArrayList<>(); + + public static InOrderVerificationBuilder create() { + return new InOrderVerificationBuilder(); + } + + public InOrderVerificationBuilder verify(InOrderVerification.Verifier v, int index) { + actions.add(verification -> { + verification.verify(v, index); + return null; + }); + return this; + } + + public InOrderVerificationBuilder verifyOnAll(InOrderVerification.Verifier v) { + actions.add(verification -> { + verification.verifyOnAll(v); + return null; + }); + return this; + } + + public InOrderVerificationBuilder verifyNext(InOrderVerification.Verifier v) { + actions.add(verification -> { + verification.verifyNext(v); + return null; + }); + return this; + } + + public InOrderVerificationBuilder verifyNumberOfInvocations(int expected) { + actions.add(verification -> { + verification.verifyNumberOfInvocations(expected); + return null; + }); + return this; + } + + public void execute(AddressSelectorWrapper addressSelectorWrapper) { + InOrderVerification v = new InOrderVerification(addressSelectorWrapper.invocationOnMockList); + for(Function action: actions) { + action.apply(v); + } + } + } + + public InOrderVerification getInOrderVerification() { + return new InOrderVerification(invocationOnMockList); + } + + public static class InOrderVerification { + private final List invocations; + private int internalIndex = 0; + + InOrderVerification(List invocationOnMockList) { + invocations = invocationOnMockList; + } + + public InOrderVerification verify(Verifier v, int index) { + v.verify(invocations.get(index)); + return this; + } + + public InOrderVerification verifyOnAll(Verifier v) { + for(InvocationOnMock i: invocations) { + v.verify(i); + } + return this; + } + + public InOrderVerification verifyNext(Verifier v) { + v.verify(invocations.get(internalIndex++)); + return this; + } + + public InOrderVerification verifyNumberOfInvocations(int expected) { + assertThat(invocations).hasSize(expected); + return this; + } + + interface Verifier { + + void verify(InvocationOnMock invocation); + + public static VerifierBuilder builder() { + return new VerifierBuilder(); + } + + public static class VerifierBuilder { + + public Verifier build() { + return new Verifier() { + @Override + public void verify(InvocationOnMock invocation) { + for(Verifier v: verifiers) { + v.verify(invocation); + } + } + }; + } + + List verifiers = new ArrayList<>(); + + VerifierBuilder add(Verifier verifier) { + verifiers.add(verifier); + return this; + } + + VerifierBuilder methodName(String methodName) { + add(new Verifier() { + @Override + public void verify(InvocationOnMock invocation) { + assertThat(invocation.getMethod().getName()).isEqualTo(methodName); + } + }); + return this; + } + + VerifierBuilder resolveAllUriAsync() { + methodName(resolveAllUriAsync); + return this; + } + + VerifierBuilder resolvePrimaryUriAsync() { + methodName(resolvePrimaryUriAsync); + return this; + } + + VerifierBuilder resolveAddressesAsync() { + methodName(resolveAddressesAsync); + return this; + } + + VerifierBuilder resolveAllUriAsync(Condition requestMatcher, Condition includePrimaryMatcher, Condition forceRefreshMatcher) { + methodName(resolveAllUriAsync); + add(new Verifier() { + @Override + public void verify(InvocationOnMock invocation) { + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean includePrimary = invocation.getArgumentAt(1, Boolean.class); + boolean forceRefresh = invocation.getArgumentAt(2, Boolean.class); + + assertThat(request).is(requestMatcher); + + assertThat(includePrimary).is(includePrimaryMatcher); + assertThat(forceRefresh).is(forceRefreshMatcher); + } + }); + return this; + } + + VerifierBuilder resolveAllUriAsync_IncludePrimary(boolean primaryIncluded) { + methodName(resolveAllUriAsync); + + Condition alwaysTrue = new Condition(Predicates.alwaysTrue(), "no condition"); + Condition primaryIncludedCond = new Condition(Predicates.equalTo(primaryIncluded), String.format("%b (primaryIncluded)", primaryIncluded)); + + resolveAllUriAsync(alwaysTrue, primaryIncludedCond, alwaysTrue); + return this; + } + + VerifierBuilder resolveAllUriAsync_ForceRefresh(boolean forceRefresh) { + methodName(resolveAllUriAsync); + + Condition alwaysTrue = new Condition(Predicates.alwaysTrue(), "no condition"); + Condition forceRefreshCond = new Condition(Predicates.equalTo(forceRefresh), String.format("%b (forceRefresh)", forceRefresh)); + + resolveAllUriAsync(alwaysTrue, alwaysTrue, forceRefreshCond); + return this; + } + } + } + } + + public AddressSelectorWrapper(AddressSelector addressSelector, List invocationOnMockList) { + this.addressSelector = addressSelector; + this.invocationOnMockList = invocationOnMockList; + } + + public AddressSelectorWrapper verifyNumberOfForceCachRefresh(int expectedNumber) { + int count = 0; + for (InvocationOnMock invocationOnMock : invocationOnMockList) { + boolean forceRefresh; + if (invocationOnMock.getMethod().getName().endsWith("resolveAllUriAsync")) { + forceRefresh = invocationOnMock.getArgumentAt(2, Boolean.class); + } else { + forceRefresh = invocationOnMock.getArgumentAt(1, Boolean.class); + } + if (forceRefresh) { + count++; + } + } + assertThat(count).isEqualTo(expectedNumber); + return this; + } + + public AddressSelectorWrapper verifyNumberOfForceCacheRefreshGreaterThanOrEqualTo(int minimum) { + int count = 0; + for (InvocationOnMock invocationOnMock : invocationOnMockList) { + boolean forceRefresh; + if (invocationOnMock.getMethod().getName().endsWith("resolveAllUriAsync")) { + forceRefresh = invocationOnMock.getArgumentAt(2, Boolean.class); + } else { + forceRefresh = invocationOnMock.getArgumentAt(1, Boolean.class); + } + if (forceRefresh) { + count++; + } + } + assertThat(count).isGreaterThanOrEqualTo(minimum); + return this; + } + + public AddressSelectorWrapper validate() { + // for now do nothing; + return this; + } + + public AddressSelectorWrapper verifyVesolvePrimaryUriAsyncCount(int count) { + Mockito.verify(addressSelector, Mockito.times(count)).resolvePrimaryUriAsync(Mockito.any(), Mockito.anyBoolean()); + return this; + } + + public AddressSelectorWrapper verifyResolveAddressesAsync(int count) { + Mockito.verify(addressSelector, Mockito.times(count)).resolveAddressesAsync(Mockito.any(), Mockito.anyBoolean()); + return this; + } + + public AddressSelectorWrapper verifyResolveAllUriAsync(int count) { + Mockito.verify(addressSelector, Mockito.times(count)).resolveAllUriAsync(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean()); + return this; + } + + public AddressSelectorWrapper verifyTotalInvocations(int count) { + assertThat(invocationOnMockList).hasSize(count); + return this; + } + + public static class Builder { + final Protocol protocol; + AddressSelector addressSelector; + List invocationOnMockList = Collections.synchronizedList(new ArrayList<>()); + + + public Builder(Protocol protocol) { + this.protocol = protocol; + } + + public static class PrimaryReplicaMoveBuilder extends Builder { + static PrimaryReplicaMoveBuilder create(Protocol protocol) { + return new PrimaryReplicaMoveBuilder(protocol); + } + + public PrimaryReplicaMoveBuilder(Protocol protocol) { + super(protocol); + addressSelector = Mockito.mock(AddressSelector.class); + } + + public PrimaryReplicaMoveBuilder withPrimaryReplicaMove(URI primaryURIBeforeForceRefresh, URI primaryURIAfterForceRefresh) { + AtomicBoolean refreshed = new AtomicBoolean(false); + Mockito.doAnswer((invocation) -> { + capture(invocation); + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean forceRefresh = invocation.getArgumentAt(1, Boolean.class); + + if (forceRefresh || refreshed.get()) { + refreshed.set(true); + return Mono.just(primaryURIAfterForceRefresh); + } + + return Mono.just(primaryURIBeforeForceRefresh); + }).when(addressSelector).resolvePrimaryUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + return null; + })).when(addressSelector).resolveAllUriAsync(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + return null; + })).when(addressSelector).resolveAddressesAsync(Mockito.any(), Mockito.anyBoolean()); + + return this; + } + + public AddressSelectorWrapper build() { + return new AddressSelectorWrapper(this.addressSelector, this.invocationOnMockList); + } + } + + public static class ReplicaMoveBuilder extends Builder { + + List> secondary = new ArrayList<>(); + Pair primary; + private Function partitionKeyRangeFunction; + + static ReplicaMoveBuilder create(Protocol protocol) { + return new ReplicaMoveBuilder(protocol); + } + + public ReplicaMoveBuilder(Protocol protocol) { + super(protocol); + addressSelector = Mockito.mock(AddressSelector.class); + } + + public ReplicaMoveBuilder withPrimaryMove(URI uriBeforeForceRefresh, URI uriAfterForceRefresh) { + withReplicaMove(uriBeforeForceRefresh, uriAfterForceRefresh, true); + return this; + } + + public ReplicaMoveBuilder withSecondaryMove(URI uriBeforeForceRefresh, URI uriAfterForceRefresh) { + withReplicaMove(uriBeforeForceRefresh, uriAfterForceRefresh, false); + return this; + } + + public ReplicaMoveBuilder newPartitionKeyRangeIdOnRefresh(Function partitionKeyRangeFunction) { + this.partitionKeyRangeFunction = partitionKeyRangeFunction; + return this; + } + + public ReplicaMoveBuilder withReplicaMove(URI uriBeforeForceRefresh, URI uriAfterForceRefresh, boolean isPrimary) { + if (isPrimary) { + primary = ImmutablePair.of(uriBeforeForceRefresh, uriAfterForceRefresh); + } else { + secondary.add(ImmutablePair.of(uriBeforeForceRefresh, uriAfterForceRefresh)); + } + return this; + } + + + public AddressSelectorWrapper build() { + AtomicBoolean refreshed = new AtomicBoolean(false); + Mockito.doAnswer((invocation) -> { + capture(invocation); + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean forceRefresh = invocation.getArgumentAt(1, Boolean.class); + if (partitionKeyRangeFunction != null) { + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeFunction.apply(request); + } + if (forceRefresh || refreshed.get()) { + refreshed.set(true); + return Mono.just(primary.getRight()); + } else { + return Mono.just(primary.getLeft()); + } + + }).when(addressSelector).resolvePrimaryUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean includePrimary = invocation.getArgumentAt(1, Boolean.class); + boolean forceRefresh = invocation.getArgumentAt(2, Boolean.class); + + ImmutableList.Builder b = ImmutableList.builder(); + + if (forceRefresh || refreshed.get()) { + if (partitionKeyRangeFunction != null) { + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeFunction.apply(request); + } + refreshed.set(true); + if (includePrimary) { + b.add(primary.getRight()); + } + b.addAll(secondary.stream().map(s -> s.getRight()).collect(Collectors.toList())); + return Mono.just(b.build()); + } else { + // old + if (includePrimary) { + b.add(primary.getLeft()); + } + b.addAll(secondary.stream().map(s -> s.getLeft()).collect(Collectors.toList())); + return Mono.just(b.build()); + } + + })).when(addressSelector).resolveAllUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean(), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean forceRefresh = invocation.getArgumentAt(1, Boolean.class); + + ImmutableList.Builder b = ImmutableList.builder(); + + if (forceRefresh || refreshed.get()) { + if (partitionKeyRangeFunction != null) { + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeFunction.apply(request); + } + + refreshed.set(true); + b.add(primary.getRight()); + b.addAll(secondary.stream().map(s -> s.getRight()).collect(Collectors.toList())); + return Mono.just(b.build()); + } else { + // old + b.add(primary.getLeft()); + b.addAll(secondary.stream().map(s -> s.getLeft()).collect(Collectors.toList())); + return Mono.just(b.build()); + } + })).when(addressSelector).resolveAddressesAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean()); + + return new AddressSelectorWrapper(addressSelector, invocationOnMockList); + } + } + + public static class Simple extends Builder { + private URI primaryAddress; + private List secondaryAddresses; + static Simple create() { + return new Simple(Protocol.HTTPS); + } + + public Simple(Protocol protocol) { + super(protocol); + addressSelector = Mockito.mock(AddressSelector.class); + } + + public Simple withPrimary(URI primaryAddress) { + this.primaryAddress = primaryAddress; + return this; + } + + public Simple withSecondary(List secondaryAddresses) { + this.secondaryAddresses = secondaryAddresses; + return this; + } + + public AddressSelectorWrapper build() { + Mockito.doAnswer((invocation) -> { + capture(invocation); + return Mono.just(primaryAddress); + }).when(addressSelector).resolvePrimaryUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + RxDocumentServiceRequest request = invocation.getArgumentAt(0, RxDocumentServiceRequest.class); + boolean includePrimary = invocation.getArgumentAt(1, Boolean.class); + boolean forceRefresh = invocation.getArgumentAt(2, Boolean.class); + + if (includePrimary) { + return Mono.just(ImmutableList.builder().addAll(secondaryAddresses).add(primaryAddress).build()); + } else { + return Mono.just(secondaryAddresses); + } + })).when(addressSelector).resolveAllUriAsync(Mockito.any(), Mockito.anyBoolean(), Mockito.anyBoolean()); + + Mockito.doAnswer((invocation -> { + capture(invocation); + return Mono.just(ImmutableList.builder() + .addAll(secondaryAddresses.stream() + .map(uri -> toAddressInformation(uri, false, protocol)) + .collect(Collectors.toList())) + .add(toAddressInformation(primaryAddress, true, protocol)) + .build()); + })).when(addressSelector).resolveAddressesAsync(Mockito.any(), Mockito.anyBoolean()); + + + return new AddressSelectorWrapper(this.addressSelector, this.invocationOnMockList); + } + + private AddressInformation toAddressInformation(URI uri, boolean isPrimary, Protocol protocol) { + return new AddressInformation(true, isPrimary, uri.toString(), protocol); + } + } + + protected void capture(InvocationOnMock invocationOnMock) { + invocationOnMockList.add(invocationOnMock); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressValidator.java new file mode 100644 index 0000000000000..92578c444c7a6 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/AddressValidator.java @@ -0,0 +1,154 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.Address; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.directconnectivity.Address; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.assertj.core.api.Condition; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This is a helper class for validating a partition address for tests. + */ +public interface AddressValidator { + + void validate(Address address); + + class Builder { + private List validators = new ArrayList<>(); + + public AddressValidator build() { + return new AddressValidator() { + + @Override + public void validate(Address address) { + for (AddressValidator validator : validators) { + validator.validate(address); + } + } + }; + } + + public Builder withId(final String resourceId) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.id()).as("check Resource Id").isEqualTo(resourceId); + } + }); + return this; + } + + + + public Builder withProperty(String propertyName, Condition validatingCondition) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.get(propertyName)).is(validatingCondition); + + } + }); + return this; + } + + public Builder withProperty(String propertyName, Object value) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.get(propertyName)).isEqualTo(value); + + } + }); + return this; + } + + public Builder isPrimary(boolean isPrimary) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.IsPrimary()).isTrue(); + } + }); + return this; + } + + public Builder httpsProtocol() { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.getProtocolScheme()).isEqualTo("https"); + } + }); + return this; + } + + public Builder protocol(Protocol protocol) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + if (protocol == Protocol.HTTPS) { + assertThat(address.getProtocolScheme()).isEqualTo("https"); + } else if (protocol == Protocol.TCP){ + assertThat(address.getProtocolScheme()).isEqualTo("rntbd"); + } + } + }); + return this; + } + + public Builder withRid(String rid) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.resourceId()).isEqualTo(rid); + } + }); + return this; + } + + public Builder withPartitionKeyRangeId(String partitionKeyRangeId) { + validators.add(new AddressValidator() { + + @Override + public void validate(Address address) { + assertThat(address.getParitionKeyRangeId()).isEqualTo(partitionKeyRangeId); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelperTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelperTest.java new file mode 100644 index 0000000000000..ce6f3a44a13fb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/BarrierRequestHelperTest.java @@ -0,0 +1,237 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentClientImpl; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import com.azure.data.cosmos.internal.TestConfigurations; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; + +public class BarrierRequestHelperTest { + @Test(groups = "direct") + public void barrierBasic() { + IAuthorizationTokenProvider authTokenProvider = getIAuthorizationTokenProvider(); + + for (ResourceType resourceType : ResourceType.values()) { + + for (OperationType operationType : OperationType.values()) { + Document randomResource = new Document(); + randomResource.id(UUID.randomUUID().toString()); + RxDocumentServiceRequest request = + RxDocumentServiceRequest.create(operationType, resourceType, "/dbs/7mVFAA==/colls/7mVFAP1jpeU=", randomResource, (Map) null); + + BarrierRequestHelper.createAsync(request, authTokenProvider, 10l, 10l).block(); + request = + RxDocumentServiceRequest.create(operationType, resourceType, "/dbs/7mVFAA==", randomResource, null); + + request.setResourceId("3"); + try { + BarrierRequestHelper.createAsync(request, authTokenProvider, 10l, 10l).block(); + } catch (Exception e) { + if (!BarrierRequestHelper.isCollectionHeadBarrierRequest(resourceType, operationType)) { + fail("Should not fail for non-collection head combinations"); + } + } + } + } + } + + @Test(groups = "direct") + public void barrierDBFeed() { + IAuthorizationTokenProvider authTokenProvider = getIAuthorizationTokenProvider(); + + ResourceType resourceType = ResourceType.DocumentCollection; + OperationType operationType = OperationType.Query; + + Document randomResource = new Document(); + randomResource.id(UUID.randomUUID().toString()); + RxDocumentServiceRequest request = + RxDocumentServiceRequest.create(operationType, resourceType, "/dbs/7mVFAA==/colls/7mVFAP1jpeU=", randomResource, (Map) null); + + RxDocumentServiceRequest barrierRequest = BarrierRequestHelper.createAsync(request, authTokenProvider, 11l, 10l).block(); + + assertThat(barrierRequest.getOperationType()).isEqualTo(OperationType.HeadFeed); + assertThat(barrierRequest.getResourceType()).isEqualTo(ResourceType.Database); + + + assertThat(getTargetGlobalLsn(barrierRequest)).isEqualTo(10l); + assertThat(getTargetLsn(barrierRequest)).isEqualTo(11l); + } + + @Test(groups = "direct") + public void barrierDocumentQueryNameBasedRequest() { + IAuthorizationTokenProvider authTokenProvider = getIAuthorizationTokenProvider(); + + ResourceType resourceType = ResourceType.Document; + OperationType operationType = OperationType.Query; + + Document randomResource = new Document(); + randomResource.id(UUID.randomUUID().toString()); + RxDocumentServiceRequest request = + RxDocumentServiceRequest.create(operationType, resourceType, "/dbs/dbname/colls/collname", randomResource, (Map) null); + + RxDocumentServiceRequest barrierRequest = BarrierRequestHelper.createAsync(request, authTokenProvider, 11l, 10l).block(); + + assertThat(barrierRequest.getOperationType()).isEqualTo(OperationType.Head); + assertThat(barrierRequest.getResourceType()).isEqualTo(ResourceType.DocumentCollection); + assertThat(barrierRequest.getResourceAddress()).isEqualTo("dbs/dbname/colls/collname"); + + assertThat(getTargetGlobalLsn(barrierRequest)).isEqualTo(10l); + assertThat(getTargetLsn(barrierRequest)).isEqualTo(11l); + } + + @Test(groups = "direct") + public void barrierDocumentReadNameBasedRequest() { + IAuthorizationTokenProvider authTokenProvider = getIAuthorizationTokenProvider(); + + ResourceType resourceType = ResourceType.Document; + OperationType operationType = OperationType.Read; + + Document randomResource = new Document(); + randomResource.id(UUID.randomUUID().toString()); + RxDocumentServiceRequest request = + RxDocumentServiceRequest.create(operationType, resourceType, "/dbs/dbname/colls/collname", randomResource, (Map) null); + + RxDocumentServiceRequest barrierRequest = BarrierRequestHelper.createAsync(request, authTokenProvider, 11l, 10l).block(); + + assertThat(barrierRequest.getOperationType()).isEqualTo(OperationType.Head); + assertThat(barrierRequest.getResourceType()).isEqualTo(ResourceType.DocumentCollection); + assertThat(barrierRequest.getResourceAddress()).isEqualTo("dbs/dbname/colls/collname"); + + assertThat(getTargetGlobalLsn(barrierRequest)).isEqualTo(10l); + assertThat(getTargetLsn(barrierRequest)).isEqualTo(11l); + assertThat(barrierRequest.getIsNameBased()).isEqualTo(true); + + } + + @Test(groups = "direct") + public void barrierDocumentReadRidBasedRequest() { + IAuthorizationTokenProvider authTokenProvider = getIAuthorizationTokenProvider(); + + ResourceType resourceType = ResourceType.Document; + OperationType operationType = OperationType.Read; + + Document randomResource = new Document(); + randomResource.id(UUID.randomUUID().toString()); + RxDocumentServiceRequest request = + RxDocumentServiceRequest.create(operationType, "7mVFAA==", resourceType, (Map) null); + + RxDocumentServiceRequest barrierRequest = BarrierRequestHelper.createAsync(request, authTokenProvider, 11l, 10l).block(); + + assertThat(barrierRequest.getOperationType()).isEqualTo(OperationType.Head); + assertThat(barrierRequest.getResourceType()).isEqualTo(ResourceType.DocumentCollection); + assertThat(barrierRequest.getResourceAddress()).isEqualTo("7mVFAA=="); + + assertThat(getTargetGlobalLsn(barrierRequest)).isEqualTo(10l); + assertThat(getTargetLsn(barrierRequest)).isEqualTo(11l); + assertThat(barrierRequest.getIsNameBased()).isEqualTo(false); + } + + @DataProvider(name = "isCollectionHeadBarrierRequestArgProvider") + public Object[][] isCollectionHeadBarrierRequestArgProvider() { + return new Object[][]{ + // resourceType, operationType, isCollectionHeadBarrierRequest + + {ResourceType.Attachment, null, true}, + {ResourceType.Document, null, true}, + {ResourceType.Conflict, null, true}, + {ResourceType.StoredProcedure, null, true}, + {ResourceType.Attachment, null, true}, + {ResourceType.Trigger, null, true}, + + {ResourceType.DocumentCollection, OperationType.ReadFeed, false}, + {ResourceType.DocumentCollection, OperationType.Query, false}, + {ResourceType.DocumentCollection, OperationType.SqlQuery, false}, + + {ResourceType.DocumentCollection, OperationType.Create, true}, + {ResourceType.DocumentCollection, OperationType.Read, true}, + {ResourceType.DocumentCollection, OperationType.Replace, true}, + {ResourceType.DocumentCollection, OperationType.ExecuteJavaScript, true}, + + {ResourceType.PartitionKeyRange, null, false}, + }; + } + + @Test(groups = "direct", dataProvider = "isCollectionHeadBarrierRequestArgProvider") + public void isCollectionHeadBarrierRequest(ResourceType resourceType, + OperationType operationType, + boolean expectedResult) { + if (operationType != null) { + boolean actual = BarrierRequestHelper.isCollectionHeadBarrierRequest(resourceType, operationType); + assertThat(actual).isEqualTo(expectedResult); + } else { + for (OperationType type : OperationType.values()) { + boolean actual = BarrierRequestHelper.isCollectionHeadBarrierRequest(resourceType, type); + assertThat(actual).isEqualTo(expectedResult); + } + } + } + + private IAuthorizationTokenProvider getIAuthorizationTokenProvider() { + return (RxDocumentClientImpl) + new AsyncDocumentClient.Builder() + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withServiceEndpoint(TestConfigurations.HOST) + .build(); + } + + private String getHeaderValue(RxDocumentServiceRequest req, String name) { + return req.getHeaders().get(name); + } + + private String getPartitionKey(RxDocumentServiceRequest req) { + return getHeaderValue(req, HttpConstants.HttpHeaders.PARTITION_KEY); + } + + private String getCollectionRid(RxDocumentServiceRequest req) { + return getHeaderValue(req, WFConstants.BackendHeaders.COLLECTION_RID); + } + + private PartitionKeyRangeIdentity getPartitionKeyRangeIdentity(RxDocumentServiceRequest req) { + return req.getPartitionKeyRangeIdentity(); + } + + private Long getTargetLsn(RxDocumentServiceRequest req) { + return Long.parseLong(getHeaderValue(req, HttpConstants.HttpHeaders.TARGET_LSN)); + } + + private Long getTargetGlobalLsn(RxDocumentServiceRequest req) { + return Long.parseLong(getHeaderValue(req, HttpConstants.HttpHeaders.TARGET_GLOBAL_COMMITTED_LSN)); + } +} + diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderTest.java new file mode 100644 index 0000000000000..f73b6db88a505 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderTest.java @@ -0,0 +1,771 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.NotFoundException; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.URI; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static com.azure.data.cosmos.internal.Utils.ValueHolder; +import static org.assertj.core.api.Assertions.assertThat; + +public class ConsistencyReaderTest { + private final Configs configs = new Configs(); + private static final int TIMEOUT = 30000; + @DataProvider(name = "deduceReadModeArgProvider") + public Object[][] deduceReadModeArgProvider() { + return new Object[][]{ + // account consistency, request consistency, expected readmode, expected consistency to use, whether use session + { ConsistencyLevel.STRONG, null, ReadMode.Strong, ConsistencyLevel.STRONG, false}, + { ConsistencyLevel.STRONG, ConsistencyLevel.EVENTUAL, ReadMode.Any, ConsistencyLevel.EVENTUAL, false}, + { ConsistencyLevel.STRONG, ConsistencyLevel.SESSION, ReadMode.Any, ConsistencyLevel.SESSION, true}, + { ConsistencyLevel.SESSION, ConsistencyLevel.EVENTUAL, ReadMode.Any, ConsistencyLevel.EVENTUAL, false}, + { ConsistencyLevel.SESSION, ConsistencyLevel.SESSION, ReadMode.Any, ConsistencyLevel.SESSION, true}, + { ConsistencyLevel.SESSION, ConsistencyLevel.EVENTUAL, ReadMode.Any, ConsistencyLevel.EVENTUAL, false}, + { ConsistencyLevel.SESSION, null, ReadMode.Any, ConsistencyLevel.SESSION, true}, + { ConsistencyLevel.EVENTUAL, ConsistencyLevel.EVENTUAL, ReadMode.Any, ConsistencyLevel.EVENTUAL, false}, + { ConsistencyLevel.EVENTUAL, null, ReadMode.Any, ConsistencyLevel.EVENTUAL, false}, + }; + } + + @Test(groups = "unit", dataProvider = "deduceReadModeArgProvider") + public void deduceReadMode(ConsistencyLevel accountConsistencyLevel, ConsistencyLevel requestConsistency, ReadMode expectedReadMode, + ConsistencyLevel expectedConsistencyToUse, boolean expectedToUseSession) throws CosmosClientException { + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + TransportClient transportClient = Mockito.mock(TransportClient.class); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(accountConsistencyLevel); + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelector, + sessionContainer, + transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authorizationTokenProvider); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + if (requestConsistency != null) { + request.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, requestConsistency.toString()); + } + + ValueHolder consistencyLevel = ValueHolder.initialize(null); + ValueHolder useSession = ValueHolder.initialize(null); + + ReadMode readMode = consistencyReader.deduceReadMode(request, consistencyLevel, useSession); + + assertThat(readMode).isEqualTo(expectedReadMode); + assertThat(consistencyLevel.v).isEqualTo(expectedConsistencyToUse); + assertThat(useSession.v).isEqualTo(expectedToUseSession); + } + + @DataProvider(name = "getMaxReplicaSetSizeArgProvider") + public Object[][] getMaxReplicaSetSizeArgProvider() { + return new Object[][]{ + // system max replica count, system min replica count, user max replica count, user min replica, is reading from master operation + { 4, 3, 4, 3, false }, + { 4, 3, 4, 3, true }, + + { 4, 3, 3, 2, false }, + { 4, 3, 3, 2, true } + }; + } + + @Test(groups = "unit", dataProvider = "getMaxReplicaSetSizeArgProvider") + public void replicaSizes(int systemMaxReplicaCount, + int systemMinReplicaCount, + int userMaxReplicaCount, + int userMinReplicaCount, + boolean isReadingFromMasterOperation) { + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + TransportClient transportClient = Mockito.mock(TransportClient.class); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + systemMaxReplicaCount, + systemMinReplicaCount, + userMaxReplicaCount, + userMinReplicaCount); + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelector, + sessionContainer, + transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authorizationTokenProvider); + + RxDocumentServiceRequest request; + if (isReadingFromMasterOperation) { + request = RxDocumentServiceRequest.createFromName( + OperationType.ReadFeed, "/dbs/db/colls/col", ResourceType.DocumentCollection); + } else { + request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + } + + assertThat(consistencyReader.getMaxReplicaSetSize(request)).isEqualTo(isReadingFromMasterOperation? systemMaxReplicaCount : userMaxReplicaCount); + assertThat(consistencyReader.getMinReplicaSetSize(request)).isEqualTo(isReadingFromMasterOperation? systemMinReplicaCount : userMinReplicaCount); + } + + @Test(groups = "unit") + public void readAny() { + List secondaries = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2"), URI.create("secondary3")); + URI primaryAddress = URI.create("primary"); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryAddress) + .withSecondary(secondaries) + .build(); + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withLSN(54) + .withLocalLSN(18) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse1 = StoreResponseBuilder.create() + .withLSN(53) + .withLocalLSN(17) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse2 = StoreResponseBuilder.create() + .withLSN(52) + .withLocalLSN(16) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse3 = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(15) + .withRequestCharge(1.1) + .build(); + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryAddress, OperationType.Read, ResourceType.Document, primaryResponse, true) + .storeResponseOn(secondaries.get(0), OperationType.Read, ResourceType.Document, secondaryResponse1, true) + .storeResponseOn(secondaries.get(1), OperationType.Read, ResourceType.Document, secondaryResponse2, true) + .storeResponseOn(secondaries.get(2), OperationType.Read, ResourceType.Document, secondaryResponse3, true) + .build(); + + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReaderUnderTest consistencyReader = new ConsistencyReaderUnderTest(addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authorizationTokenProvider); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.EVENTUAL.toString()); + + TimeoutHelper timeout = Mockito.mock(TimeoutHelper.class); + boolean forceRefresh = false; + boolean isInRetry = false; + Mono storeResponseSingle = consistencyReader.readAsync(request, timeout, isInRetry, forceRefresh); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSNGreaterThanOrEqualTo(51) + .withRequestCharge(1.1) + .in(primaryResponse, secondaryResponse1, secondaryResponse2, secondaryResponse3) + .build(); + validateSuccess(storeResponseSingle, validator); + + Mockito.verifyZeroInteractions(consistencyReader.getSpyQuorumReader()); + + + Mockito.verify(consistencyReader.getSpyStoreReader(), Mockito.times(1)) + .readMultipleReplicaAsync(Mockito.any(RxDocumentServiceRequest.class), + Mockito.anyBoolean(), + Mockito.anyInt(), + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.any(), + Mockito.anyBoolean(), + Mockito.anyBoolean()); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(1); + + addressSelectorWrapper.validate() + .verifyTotalInvocations(1) + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyResolveAllUriAsync(1); + } + + @Test(groups = "unit") + public void readSessionConsistency_SomeReplicasLagBehindAndReturningResponseWithLowerLSN_FindAnotherReplica() { + long slowReplicaLSN = 651176; + String partitionKeyRangeId = "1"; + long fasterReplicaLSN = 651177; + + List secondaries = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2"), URI.create("secondary3")); + URI primaryAddress = URI.create("primary"); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryAddress) + .withSecondary(secondaries) + .build(); + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + slowReplicaLSN) + .withLSN(slowReplicaLSN) + .withLocalLSN(slowReplicaLSN) + .withQuorumAckecdLsn(slowReplicaLSN) + .withQuorumAckecdLocalLsn(slowReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(slowReplicaLSN) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse1 = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + slowReplicaLSN) + .withLSN(slowReplicaLSN) + .withLocalLSN(slowReplicaLSN) + .withQuorumAckecdLsn(slowReplicaLSN) + .withQuorumAckecdLocalLsn(slowReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(slowReplicaLSN) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse2 = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + fasterReplicaLSN) + .withLSN(fasterReplicaLSN) + .withLocalLSN(fasterReplicaLSN) + .withQuorumAckecdLsn(fasterReplicaLSN) + .withQuorumAckecdLocalLsn(fasterReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(fasterReplicaLSN) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse3 = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + slowReplicaLSN) + .withLSN(slowReplicaLSN) + .withLocalLSN(slowReplicaLSN) + .withQuorumAckecdLsn(slowReplicaLSN) + .withQuorumAckecdLocalLsn(slowReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(slowReplicaLSN) + .withRequestCharge(1.1) + .build(); + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryAddress, OperationType.Read, ResourceType.Document, primaryResponse, true) + .storeResponseOn(secondaries.get(0), OperationType.Read, ResourceType.Document, secondaryResponse1, true) + .storeResponseOn(secondaries.get(1), OperationType.Read, ResourceType.Document, secondaryResponse2, true) + .storeResponseOn(secondaries.get(2), OperationType.Read, ResourceType.Document, secondaryResponse3, true) + .build(); + + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReaderUnderTest consistencyReader = new ConsistencyReaderUnderTest(addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authorizationTokenProvider); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + request.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + assertThat(VectorSessionToken.tryCreate("-1#" + fasterReplicaLSN , sessionToken)).isTrue(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(request), Mockito.anyString()); + + + TimeoutHelper timeout = Mockito.mock(TimeoutHelper.class); + boolean forceRefresh = false; + boolean isInRetry = false; + Mono storeResponseSingle = consistencyReader.readAsync(request, timeout, isInRetry, forceRefresh); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(fasterReplicaLSN) + .withRequestChargeGreaterThanOrEqualTo(1.1) + .in(primaryResponse, secondaryResponse1, secondaryResponse2, secondaryResponse3) + .build(); + validateSuccess(storeResponseSingle, validator); + + Mockito.verifyZeroInteractions(consistencyReader.getSpyQuorumReader()); + + + Mockito.verify(consistencyReader.getSpyStoreReader(), Mockito.times(1)) + .readMultipleReplicaAsync(Mockito.any(RxDocumentServiceRequest.class), + Mockito.anyBoolean(), + Mockito.anyInt(), + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.any(), + Mockito.anyBoolean(), + Mockito.anyBoolean()); + + assertThat(transportClientWrapper.validate() + .getNumberOfInvocations()) + .isGreaterThanOrEqualTo(1) + .isLessThanOrEqualTo(4); + + addressSelectorWrapper.validate() + .verifyTotalInvocations(1) + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyResolveAllUriAsync(1); + } + + /** + * reading in session consistency, if the requested session token cannot be supported by some replicas + * tries others till we find a replica which can support the given session token + */ + @Test(groups = "unit") + public void sessionNotAvailableFromSomeReplicasThrowingNotFound_FindReplicaSatisfyingRequestedSession() { + long slowReplicaLSN = 651175; + long globalCommittedLsn = 651174; + + long fasterReplicaLSN = 651176; + String partitionKeyRangeId = "1"; + + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + slowReplicaLSN); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(slowReplicaLSN)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(slowReplicaLSN)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + StoreResponse storeResponse = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + fasterReplicaLSN) + .withLSN(fasterReplicaLSN) + .withLocalLSN(fasterReplicaLSN) + .withQuorumAckecdLsn(fasterReplicaLSN) + .withQuorumAckecdLocalLsn(fasterReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(fasterReplicaLSN) + .withRequestCharge(1.1) + .build(); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read returns not found + .then(foundException) // 2nd replica read returns not found + .then(foundException) // 3rd replica read returns not found + .then(storeResponse) // 4th replica read returns storeResponse satisfying requested session token + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + Configs configs = new Configs(); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + 4, + 3, + 4, + 3); + + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authTokenProvider); + + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + assertThat(VectorSessionToken.tryCreate("-1#" + fasterReplicaLSN , sessionToken)).isTrue(); + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Mono storeResponseSingle = consistencyReader.readAsync(dsr, timeoutHelper, false, false); + + StoreResponseValidator validator = StoreResponseValidator.create().isSameAs(storeResponse).isSameAs(storeResponse).build(); + validateSuccess(storeResponseSingle, validator); + } + + /** + * Reading with session consistency, replicas have session token with higher than requested and return not found + */ + @Test(groups = "unit") + public void sessionRead_LegitimateNotFound() { + long lsn = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read returns not found lsn(response) >= lsn(request) + .then(foundException) // 2nd replica read returns not found lsn(response) >= lsn(request) + .then(foundException) // 3rd replica read returns not found lsn(response) >= lsn(request) + .then(foundException) // 4th replica read returns not found lsn(response) >= lsn(request) + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + assertThat(VectorSessionToken.tryCreate("-1#" + lsn , sessionToken)).isTrue(); + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Configs configs = new Configs(); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + 4, + 3, + 4, + 3); + + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authTokenProvider); + + Mono storeResponseSingle = consistencyReader.readAsync(dsr, timeoutHelper, false, false); + + FailureValidator failureValidator = FailureValidator.builder().resourceNotFound().instanceOf(NotFoundException.class).unknownSubStatusCode().build(); + validateException(storeResponseSingle, failureValidator); + } + + /** + * reading in session consistency, no replica support requested lsn + */ + @Test(groups = "unit") + public void sessionRead_ReplicasDoNotHaveTheRequestedLSN() { + long lsn = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(651175)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(651175)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read lsn lags behind the request lsn + .then(foundException) // 2nd replica read lsn lags behind the request lsn + .then(foundException) // 3rd replica read lsn lags behind the request lsn + .then(foundException) // 4th replica read lsn lags behind the request lsn + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + assertThat(VectorSessionToken.tryCreate("-1#" + (lsn + 1) , sessionToken)).isTrue(); + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Configs configs = new Configs(); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + 4, + 3, + 4, + 3); + + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authTokenProvider); + + Mono storeResponseSingle = consistencyReader.readAsync(dsr, timeoutHelper, false, false); + + FailureValidator failureValidator = FailureValidator.builder().resourceNotFound().instanceOf(NotFoundException.class).subStatusCode(HttpConstants.SubStatusCodes.READ_SESSION_NOT_AVAILABLE).build(); + validateException(storeResponseSingle, failureValidator); + } + + @Test(groups = "unit") + public void requestRateTooLarge_BubbleUp() { + long lsn = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + + RequestRateTooLargeException requestTooLargeException = new RequestRateTooLargeException(); + requestTooLargeException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + requestTooLargeException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(651175)); + requestTooLargeException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(651175)); + requestTooLargeException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(requestTooLargeException) // 1st replica read result in throttling + .then(requestTooLargeException) // 2nd replica read result in throttling + .then(requestTooLargeException) // 3rd replica read result in throttling + .then(requestTooLargeException) // 4th replica read result in throttling + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + assertThat(VectorSessionToken.tryCreate("-1#" + lsn , sessionToken)).isTrue(); + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Configs configs = new Configs(); + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + 4, + 3, + 4, + 3); + + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ConsistencyReader consistencyReader = new ConsistencyReader(configs, + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authTokenProvider); + + Mono storeResponseSingle = consistencyReader.readAsync(dsr, timeoutHelper, false, false); + + + FailureValidator failureValidator = FailureValidator.builder().instanceOf(RequestRateTooLargeException.class).unknownSubStatusCode().build(); + validateException(storeResponseSingle, failureValidator); + } + + @DataProvider(name = "simpleReadStrongArgProvider") + public Object[][] simpleReadStrongArgProvider() { + return new Object[][]{ + { 1, ReadMode.Strong }, + { 2, ReadMode.Strong }, + { 3, ReadMode.Strong }, + }; + } + + @Test(groups = "unit", dataProvider = "simpleReadStrongArgProvider") + public void basicReadStrong_AllReplicasSameLSN(int replicaCountToRead, ReadMode readMode) { + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2"), URI.create("secondary3")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + BigDecimal requestChargePerRead = new BigDecimal(1.1); + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(18) + .withRequestCharge(requestChargePerRead.doubleValue()) + .build(); + StoreResponse secondaryResponse1 = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(18) + .withRequestCharge(requestChargePerRead.doubleValue()) + .build(); + StoreResponse secondaryResponse2 = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(18) + .withRequestCharge(requestChargePerRead.doubleValue()) + .build(); + StoreResponse secondaryResponse3 = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(18) + .withRequestCharge(requestChargePerRead.doubleValue()) + .build(); + + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryReplicaURI, OperationType.Read, ResourceType.Document, primaryResponse, false) + .storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, secondaryResponse1, false) + .storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, secondaryResponse2, false) + .storeResponseOn(secondaryReplicaURIs.get(2), OperationType.Read, ResourceType.Document, secondaryResponse3, false) + .build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider); + + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(51) + .withRequestCharge(requestChargePerRead.multiply(BigDecimal.valueOf(replicaCountToRead)).setScale(2, RoundingMode.FLOOR).doubleValue()) + .build(); + validateSuccess(storeResponseSingle, validator); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(replicaCountToRead); + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1); + } + + // TODO: add more mocking tests for when one replica lags behind and we need to do barrier request. + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator, + long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator, + long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + + public static void validateException(Mono single, + FailureValidator validator, + long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } + + public static void validateException(Mono single, + FailureValidator validator) { + validateException(single, validator, TIMEOUT); + } + + private PartitionKeyRange partitionKeyRangeWithId(String id) { + PartitionKeyRange partitionKeyRange = Mockito.mock(PartitionKeyRange.class); + Mockito.doReturn(id).when(partitionKeyRange).id(); + return partitionKeyRange; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderUnderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderUnderTest.java new file mode 100644 index 0000000000000..3087a4e2cca0e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyReaderUnderTest.java @@ -0,0 +1,86 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import org.mockito.Mockito; + +public class ConsistencyReaderUnderTest extends ConsistencyReader { + private QuorumReader origQuorumReader; + private QuorumReader spyQuorumReader; + + private StoreReaderUnderTest origStoreReader; + private StoreReaderUnderTest spyStoreReader; + + public ConsistencyReaderUnderTest(AddressSelector addressSelector, + ISessionContainer sessionContainer, + TransportClient transportClient, + GatewayServiceConfigurationReader serviceConfigReader, + IAuthorizationTokenProvider authorizationTokenProvider) { + super(new Configs(), addressSelector, sessionContainer, transportClient, serviceConfigReader, authorizationTokenProvider); + + } + + public QuorumReader getOrigQuorumReader() { + return origQuorumReader; + } + + public QuorumReader getSpyQuorumReader() { + return spyQuorumReader; + } + + public StoreReaderUnderTest getOrigStoreReader() { + return origStoreReader; + } + + public StoreReaderUnderTest getSpyStoreReader() { + return spyStoreReader; + } + + @Override + public QuorumReader createQuorumReader(TransportClient transportClient, + AddressSelector addressSelector, + StoreReader storeReader, + GatewayServiceConfigurationReader serviceConfigurationReader, + IAuthorizationTokenProvider authorizationTokenProvider) { + this.origQuorumReader = super.createQuorumReader(transportClient, + addressSelector, + storeReader, + serviceConfigurationReader, + authorizationTokenProvider); + this.spyQuorumReader = Mockito.spy(this.origQuorumReader); + return this.spyQuorumReader; + } + + @Override + public StoreReader createStoreReader(TransportClient transportClient, + AddressSelector addressSelector, + ISessionContainer sessionContainer) { + this.origStoreReader = new StoreReaderUnderTest(transportClient, addressSelector, sessionContainer); + this.spyStoreReader = Mockito.spy(this.origStoreReader); + return this.spyStoreReader; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriterTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriterTest.java new file mode 100644 index 0000000000000..46148fd7214c4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ConsistencyWriterTest.java @@ -0,0 +1,287 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.DirectProcessor; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; + +import static com.azure.data.cosmos.internal.HttpConstants.StatusCodes.GONE; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.COMPLETING_SPLIT; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE; +import static org.assertj.core.api.Assertions.assertThat; + +public class ConsistencyWriterTest { + + private AddressSelector addressSelector; + private ISessionContainer sessionContainer; + private TransportClient transportClient; + private GatewayServiceConfigurationReader serviceConfigReader; + private ConsistencyWriter consistencyWriter; + + @DataProvider(name = "exceptionArgProvider") + public Object[][] exceptionArgProvider() { + return new Object[][]{ + // exception to be thrown from transportClient, expected (exception type, status, subStatus) + { new PartitionKeyRangeGoneException(), PartitionKeyRangeGoneException.class, GONE, PARTITION_KEY_RANGE_GONE, }, + { new PartitionKeyRangeIsSplittingException() , PartitionKeyRangeIsSplittingException.class, GONE, COMPLETING_SPLIT, }, + { new PartitionIsMigratingException(), PartitionIsMigratingException.class, GONE, COMPLETING_PARTITION_MIGRATION, }, + }; + } + + @Test(groups = "unit", dataProvider = "exceptionArgProvider") + public void exception(Exception ex, Class klass, int expectedStatusCode, Integer expectedSubStatusCode) { + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(ex) + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + sessionContainer = Mockito.mock(ISessionContainer.class); + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + serviceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + + consistencyWriter = new ConsistencyWriter( + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + authorizationTokenProvider, + serviceConfigReader, + false); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = Mockito.mock(RxDocumentServiceRequest.class); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + + Mono res = consistencyWriter.writeAsync(dsr, timeoutHelper, false); + + FailureValidator failureValidator = FailureValidator.builder() + .instanceOf(klass) + .statusCode(expectedStatusCode) + .subStatusCode(expectedSubStatusCode) + .build(); + + TestSubscriber subscriber = new TestSubscriber<>(); + res.subscribe(subscriber); + subscriber.awaitTerminalEvent(); + subscriber.assertNotComplete(); + assertThat(subscriber.errorCount()).isEqualTo(1); + failureValidator.validate(subscriber.errors().get(0)); + } + + @Test(groups = "unit") + public void startBackgroundAddressRefresh() throws Exception { + initializeConsistencyWriter(false); + + CyclicBarrier b = new CyclicBarrier(2); + DirectProcessor directProcessor = DirectProcessor.create(); + CountDownLatch c = new CountDownLatch(1); + + URI uri = URI.create("https://localhost:5050"); + + List invocationOnMocks = Collections.synchronizedList(new ArrayList<>()); + Mockito.doAnswer(invocationOnMock -> { + invocationOnMocks.add(invocationOnMock); + return directProcessor.single().doOnSuccess(x -> c.countDown()).doAfterTerminate(() -> new Thread() { + @Override + public void run() { + try { + b.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start()); + }).when(addressSelector).resolvePrimaryUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.anyBoolean()); + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + consistencyWriter.startBackgroundAddressRefresh(request); + + directProcessor.onNext(uri); + directProcessor.onComplete(); + + TimeUnit.MILLISECONDS.sleep(1000); + assertThat(c.getCount()).isEqualTo(0); + assertThat(b.getNumberWaiting()).isEqualTo(1); + b.await(1000, TimeUnit.MILLISECONDS); + assertThat(invocationOnMocks).hasSize(1); + assertThat(invocationOnMocks.get(0).getArgumentAt(1, Boolean.class)).isTrue(); + } + + @Test(groups = "unit") + public void getLsnAndGlobalCommittedLsn() { + ImmutableList.Builder> builder = new ImmutableList.Builder<>(); + builder.add(new AbstractMap.SimpleEntry<>(WFConstants.BackendHeaders.LSN, "3")); + builder.add(new AbstractMap.SimpleEntry<>(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "2")); + ImmutableList> headers = builder.build(); + + StoreResponse sr = new StoreResponse(0, headers, (String) null); + Utils.ValueHolder lsn = Utils.ValueHolder.initialize(-2l); + Utils.ValueHolder globalCommittedLsn = Utils.ValueHolder.initialize(-2l); + ConsistencyWriter.getLsnAndGlobalCommittedLsn(sr, lsn, globalCommittedLsn); + assertThat(lsn.v).isEqualTo(3); + assertThat(globalCommittedLsn.v).isEqualTo(2); + } + + + @Test(groups = "unit") + public void timeout1() throws Exception { + initializeConsistencyWriter(false); + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + Mockito.doReturn(true).when(timeoutHelper).isElapsed(); + ConsistencyWriter spyConsistencyWriter = Mockito.spy(this.consistencyWriter); + TestSubscriber subscriber = new TestSubscriber(); + + spyConsistencyWriter.writeAsync(Mockito.mock(RxDocumentServiceRequest.class), timeoutHelper, false) + .subscribe(subscriber); + + subscriber.awaitTerminalEvent(10, TimeUnit.MILLISECONDS); + subscriber.assertNoValues(); + + subscriber.assertError(RequestTimeoutException.class); + } + + @Test(groups = "unit") + public void timeout2() throws Exception { + initializeConsistencyWriter(false); + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + Mockito.doReturn(false).doReturn(true).when(timeoutHelper).isElapsed(); + ConsistencyWriter spyConsistencyWriter = Mockito.spy(this.consistencyWriter); + TestSubscriber subscriber = new TestSubscriber(); + + spyConsistencyWriter.writeAsync(Mockito.mock(RxDocumentServiceRequest.class), timeoutHelper, false) + .subscribe(subscriber); + + subscriber.awaitTerminalEvent(10, TimeUnit.MILLISECONDS); + subscriber.assertError(RequestTimeoutException.class); + } + + @DataProvider(name = "globalStrongArgProvider") + public Object[][] globalStrongArgProvider() { + return new Object[][]{ + { + ConsistencyLevel.SESSION, + Mockito.mock(RxDocumentServiceRequest.class), + Mockito.mock(StoreResponse.class), + + false, + }, + { + ConsistencyLevel.EVENTUAL, + Mockito.mock(RxDocumentServiceRequest.class), + Mockito.mock(StoreResponse.class), + + false, + }, + { + + ConsistencyLevel.EVENTUAL, + Mockito.mock(RxDocumentServiceRequest.class), + StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, Integer.toString(5)) + .build(), + false, + }, + { + + ConsistencyLevel.STRONG, + Mockito.mock(RxDocumentServiceRequest.class), + StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, Integer.toString(5)) + .build(), + true, + }, + { + + ConsistencyLevel.STRONG, + Mockito.mock(RxDocumentServiceRequest.class), + StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, Integer.toString(0)) + .build(), + false, + } + }; + } + + @Test(groups = "unit", dataProvider = "globalStrongArgProvider") + public void isGlobalStrongRequest(ConsistencyLevel defaultConsistencyLevel, RxDocumentServiceRequest req, StoreResponse storeResponse, boolean isGlobalStrongExpected) { + initializeConsistencyWriter(false); + Mockito.doReturn(defaultConsistencyLevel).when(this.serviceConfigReader).getDefaultConsistencyLevel(); + + + assertThat(consistencyWriter.isGlobalStrongRequest(req, storeResponse)).isEqualTo(isGlobalStrongExpected); + } + + private void initializeConsistencyWriter(boolean useMultipleWriteLocation) { + addressSelector = Mockito.mock(AddressSelector.class); + sessionContainer = Mockito.mock(ISessionContainer.class); + transportClient = Mockito.mock(TransportClient.class); + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + serviceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + + consistencyWriter = new ConsistencyWriter( + addressSelector, + sessionContainer, + transportClient, + authorizationTokenProvider, + serviceConfigReader, + useMultipleWriteLocation); + } + + // TODO: add more mocking unit tests for Global STRONG (mocking unit tests) + // TODO: add more tests for SESSION behaviour (mocking unit tests) + // TODO: add more tests for error handling behaviour (mocking unit tests) + // TODO: add tests for replica catch up (request barrier while loop) (mocking unit tests) + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/320977 +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/DCDocumentCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/DCDocumentCrudTest.java new file mode 100644 index 0000000000000..0ae3b193740dd --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/DCDocumentCrudTest.java @@ -0,0 +1,340 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.RequestOptions; +import com.azure.data.cosmos.internal.ResourceResponse; +import com.azure.data.cosmos.internal.StoredProcedure; +import com.azure.data.cosmos.internal.StoredProcedureResponse; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.SpyClientUnderTestFactory; +import com.azure.data.cosmos.internal.TestSuiteBase; +import com.azure.data.cosmos.internal.DocumentServiceRequestValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.ResourceResponseValidator; +import com.azure.data.cosmos.internal.TestConfigurations; +import org.mockito.stubbing.Answer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +/** + * The purpose of the tests in this class is to ensure the request are routed through direct connectivity stack. + * The tests in other test classes validate the actual behaviour and different scenarios. + */ +public class DCDocumentCrudTest extends TestSuiteBase { + + private final static int QUERY_TIMEOUT = 40000; + private final static String PARTITION_KEY_FIELD_NAME = "mypk"; + + private static Database createdDatabase; + private static DocumentCollection createdCollection; + + private SpyClientUnderTestFactory.ClientWithGatewaySpy client; + + @DataProvider + public static Object[][] directClientBuilder() { + return new Object[][] { { createDCBuilder(Protocol.HTTPS) }, { createDCBuilder(Protocol.TCP) } }; + } + + static Builder createDCBuilder(Protocol protocol) { + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + + Configs configs = spy(new Configs()); + doAnswer((Answer) invocation -> protocol).when(configs).getProtocol(); + + return new Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConfigs(configs) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY); + } + + @Factory(dataProvider = "directClientBuilder") + public DCDocumentCrudTest(Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void executeStoredProc() { + StoredProcedure storedProcedure = new StoredProcedure(); + storedProcedure.id(UUID.randomUUID().toString()); + storedProcedure.setBody("function() {var x = 10;}"); + + Flux> createObservable = client + .createStoredProcedure(getCollectionLink(), storedProcedure, null); + + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(storedProcedure.id()) + .build(); + + validateSuccess(createObservable, validator, TIMEOUT); + + // creating a stored proc will go through gateway so clearing captured requests + + client.getCapturedRequests().clear(); + + // execute the created storedProc and ensure it goes through direct connectivity stack + String storedProcLink = "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id() + "/sprocs/" + storedProcedure.id(); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey("dummy")); + StoredProcedureResponse storedProcedureResponse = client + .executeStoredProcedure(storedProcLink, options, null).single().block(); + + assertThat(storedProcedureResponse.getStatusCode()).isEqualTo(200); + + // validate the request routed through direct stack + validateNoStoredProcExecutionOperationThroughGateway(); + } + + /** + * Tests document creation through direct mode + */ + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void create() { + final Document docDefinition = getDocumentDefinition(); + + Flux> createObservable = client.createDocument( + this.getCollectionLink(), docDefinition, null, false); + + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(docDefinition.id()) + .build(); + + validateSuccess(createObservable, validator, TIMEOUT); + validateNoDocumentOperationThroughGateway(); + } + + /** + * Tests document read through direct https. + * @throws Exception + */ + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void read() throws Exception { + Document docDefinition = this.getDocumentDefinition(); + Document document = client.createDocument(getCollectionLink(), docDefinition, null, false).single().block().getResource(); + + // give times to replicas to catch up after a write + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + String pkValue = document.getString(PARTITION_KEY_FIELD_NAME); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(pkValue)); + + String docLink = + String.format("dbs/%s/colls/%s/docs/%s", createdDatabase.id(), createdCollection.id(), document.id()); + + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(docDefinition.id()) + .build(); + + validateSuccess(client.readDocument(docLink, options), validator, TIMEOUT); + + validateNoDocumentOperationThroughGateway(); + } + + /** + * Tests document upsert through direct https. + * @throws Exception + */ + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void upsert() throws Exception { + + final Document docDefinition = getDocumentDefinition(); + + final Document document = client.createDocument(getCollectionLink(), docDefinition, null, false) + .single() + .block() + .getResource(); + + // give times to replicas to catch up after a write + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + String pkValue = document.getString(PARTITION_KEY_FIELD_NAME); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(pkValue)); + + String propName = "newProp"; + String propValue = "hello"; + BridgeInternal.setProperty(document, propName, propValue); + + ResourceResponseValidator validator = ResourceResponseValidator.builder() + .withProperty(propName, propValue) + .build(); + validateSuccess(client.upsertDocument(getCollectionLink(), document, options, false), validator, TIMEOUT); + + validateNoDocumentOperationThroughGateway(); + } + + @Test(groups = { "direct" }, timeOut = QUERY_TIMEOUT) + public void crossPartitionQuery() { + + truncateCollection(createdCollection); + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + client.getCapturedRequests().clear(); + + int cnt = 1000; + List documentList = new ArrayList<>(); + for(int i = 0; i < cnt; i++) { + Document docDefinition = getDocumentDefinition(); + documentList.add(docDefinition); + } + + documentList = bulkInsert(client, getCollectionLink(), documentList).map(ResourceResponse::getResource).collectList().single().block(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(-1); + options.maxItemCount(100); + Flux> results = client.queryDocuments(getCollectionLink(), "SELECT * FROM r", options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(documentList.size()) + .exactlyContainsInAnyOrder(documentList.stream().map(Document::resourceId).collect(Collectors.toList())).build(); + + validateQuerySuccess(results, validator, QUERY_TIMEOUT); + validateNoDocumentQueryOperationThroughGateway(); + // validates only the first query for fetching query plan goes to gateway. + assertThat(client.getCapturedRequests().stream().filter(r -> r.getResourceType() == ResourceType.Document)).hasSize(1); + } + + private void validateNoStoredProcExecutionOperationThroughGateway() { + // this validates that Document related requests don't go through gateway + DocumentServiceRequestValidator validateResourceTypesSentToGateway = DocumentServiceRequestValidator.builder() + .resourceTypeIn(ResourceType.DatabaseAccount, + ResourceType.Database, + ResourceType.DocumentCollection, + ResourceType.PartitionKeyRange) + .build(); + + // validate that all gateway captured requests are non document resources + for(RxDocumentServiceRequest request: client.getCapturedRequests()) { + validateResourceTypesSentToGateway.validate(request); + } + } + + private void validateNoDocumentOperationThroughGateway() { + // this validates that Document related requests don't go through gateway + DocumentServiceRequestValidator validateResourceTypesSentToGateway = DocumentServiceRequestValidator.builder() + .resourceTypeIn(ResourceType.DatabaseAccount, + ResourceType.Database, + ResourceType.DocumentCollection, + ResourceType.PartitionKeyRange) + .build(); + + // validate that all gateway captured requests are non document resources + for(RxDocumentServiceRequest request: client.getCapturedRequests()) { + validateResourceTypesSentToGateway.validate(request); + } + } + + private void validateNoDocumentQueryOperationThroughGateway() { + // this validates that Document related requests don't go through gateway + DocumentServiceRequestValidator validateResourceTypesSentToGateway = DocumentServiceRequestValidator.builder() + .resourceTypeIn(ResourceType.DatabaseAccount, + ResourceType.Database, + ResourceType.DocumentCollection, + ResourceType.PartitionKeyRange) + .build(); + + // validate that all gateway captured requests are non document resources + for(RxDocumentServiceRequest request: client.getCapturedRequests()) { + if (request.getOperationType() == OperationType.Query) { + assertThat(request.getPartitionKeyRangeIdentity()).isNull(); + } else { + validateResourceTypesSentToGateway.validate(request); + } + } + } + + @BeforeClass(groups = { "direct" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10100); + createdDatabase = SHARED_DATABASE; + createdCollection = createCollection(createdDatabase.id(), getCollectionDefinition(), options); + client = SpyClientUnderTestFactory.createClientWithGatewaySpy(clientBuilder()); + + assertThat(client.getCapturedRequests()).isNotEmpty(); + } + + @AfterClass(groups = { "direct" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeMethod(groups = { "direct" }) + public void beforeMethod(Method method) { + client.getCapturedRequests().clear(); + } + + private String getCollectionLink() { + return String.format("/dbs/%s/colls/%s", createdDatabase.id(), createdCollection.id()); + } + + private Document getDocumentDefinition() { + Document doc = new Document(); + doc.id(UUID.randomUUID().toString()); + BridgeInternal.setProperty(doc, PARTITION_KEY_FIELD_NAME, UUID.randomUUID().toString()); + BridgeInternal.setProperty(doc, "name", "Hafez"); + return doc; + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/EndpointMock.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/EndpointMock.java new file mode 100644 index 0000000000000..0fba8367fc990 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/EndpointMock.java @@ -0,0 +1,282 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.StoreResponseBuilder; +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.google.common.collect.ImmutableList; +import org.apache.commons.collections.map.HashedMap; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +abstract public class EndpointMock { + + TransportClientWrapper transportClientWrapper; + AddressSelectorWrapper addressSelectorWrapper; + + public EndpointMock(AddressSelectorWrapper addressSelectorWrapper, TransportClientWrapper transportClientWrapper) { + this.addressSelectorWrapper = addressSelectorWrapper; + this.transportClientWrapper = transportClientWrapper; + } + + public static class EndpointMockVerificationBuilder { + public static EndpointMockVerificationBuilder builder() { + return new EndpointMockVerificationBuilder(); + } + + private AddressSelectorWrapper.InOrderVerificationBuilder addressSelectorVerificationBuilder; + private TransportClientWrapper.TransportClientWrapperVerificationBuilder transportClientValidation; + + public EndpointMockVerificationBuilder withAddressSelectorValidation(AddressSelectorWrapper.InOrderVerificationBuilder addressSelectorBuilder) { + addressSelectorVerificationBuilder = addressSelectorBuilder; + return this; + } + + public EndpointMockVerificationBuilder withTransportClientValidation(TransportClientWrapper.TransportClientWrapperVerificationBuilder transportClientValidation) { + this.transportClientValidation = transportClientValidation; + return this; + } + + public void execute(EndpointMock endpointMock) { + this.addressSelectorVerificationBuilder.execute(endpointMock.addressSelectorWrapper); + this.transportClientValidation.execute(endpointMock.transportClientWrapper); + } + } + + + public void validate(EndpointMockVerificationBuilder verificationBuilder) { + this.addressSelectorWrapper.validate(); + this.transportClientWrapper.validate(); + if (verificationBuilder != null) { + verificationBuilder.execute(this); + } + } + + public static Builder.NoSecondaryReplica noSecondaryReplicaBuilder() { + return new Builder.NoSecondaryReplica(); + } + + abstract static class Builder { + + class ReplicasWithSameSpeed extends Builder { + + URI primary; + List secondaries = new ArrayList<>(); + StoreResponse headStoreResponse; + StoreResponse readStoreResponse; + + ReplicasWithSameSpeed addPrimary(URI replicaAddress) { + primary = replicaAddress; + return this; + } + + ReplicasWithSameSpeed addSecondary(URI replicaAddress) { + secondaries.add(replicaAddress); + return this; + } + + ReplicasWithSameSpeed storeResponseOnRead(StoreResponse storeResponse) { + this.readStoreResponse = storeResponse; + return this; + } + + ReplicasWithSameSpeed storeResponseOnHead(StoreResponse storeResponse) { + this.headStoreResponse = storeResponse; + return this; + } + + public EndpointMock build() { + TransportClientWrapper.Builder.ReplicaResponseBuilder transportClientWrapperBuilder = TransportClientWrapper.Builder.replicaResponseBuilder(); + + ImmutableList replicas = ImmutableList.builder().add(primary).addAll(secondaries).build(); + + for(URI replica: replicas) { + transportClientWrapperBuilder.addReplica(replica, (i, request) -> { + if (request.getOperationType() == OperationType.Head || request.getOperationType() == OperationType.HeadFeed) { + return headStoreResponse; + } else { + return readStoreResponse; + } + }); + } + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create().withPrimary(primary) + .withSecondary(secondaries).build(); + + return new EndpointMock(addressSelectorWrapper, transportClientWrapperBuilder.build()) {}; + } + } + + class QuorumNotMetSecondaryReplicasDisappear { + URI primary; + Map> disappearDictionary = new HashedMap(); + public QuorumNotMetSecondaryReplicasDisappear primaryReplica(URI primaryReplica) { + this.primary = primaryReplica; + return this; + } + + public QuorumNotMetSecondaryReplicasDisappear secondaryReplicasDisappearWhen(URI secondary, + Function2WithCheckedException disappearPredicate) { + disappearDictionary.put(secondary, disappearPredicate); + return this; + } + + public QuorumNotMetSecondaryReplicasDisappear secondaryReplicasDisappearAfter(URI secondary, int attempt) { + disappearDictionary.put(secondary, (i, r) -> i >= attempt); + return this; + } + } + + static public class NoSecondaryReplica extends Builder { + private long LOCAL_LSN = 19; + private long LSN = 52; + private URI defaultPrimaryURI = URI.create("primary"); + private URI primary = defaultPrimaryURI; + private StoreResponse defaultResponse = StoreResponseBuilder.create() + .withLSN(LSN) + .withLocalLSN(LOCAL_LSN) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, "1") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, Long.toString(LSN)) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(LOCAL_LSN)) + .withRequestCharge(0) + .build(); + + private StoreResponse headStoreResponse = defaultResponse; + private StoreResponse readStoreResponse = defaultResponse; + private Function1WithCheckedException storeResponseFunc; + + public NoSecondaryReplica primaryReplica(URI primaryReplica) { + this.primary = primaryReplica; + return this; + } + + public NoSecondaryReplica response(StoreResponse storeResponse) { + this.readStoreResponse = storeResponse; + this.headStoreResponse = storeResponse; + return this; + } + + public NoSecondaryReplica response(Function1WithCheckedException storeResponseFunc) { + this.storeResponseFunc = storeResponseFunc; + return this; + } + + public EndpointMock build() { + + TransportClientWrapper.Builder.ReplicaResponseBuilder transportClientWrapperBuilder = TransportClientWrapper.Builder.replicaResponseBuilder(); + + ImmutableList replicas = ImmutableList.builder().add(primary).build(); + + for(URI replica: replicas) { + transportClientWrapperBuilder.addReplica(replica, (i, request) -> { + + if (storeResponseFunc != null) { + return storeResponseFunc.apply(request); + } + + if (request.getOperationType() == OperationType.Head || request.getOperationType() == OperationType.HeadFeed) { + return headStoreResponse; + } else { + return readStoreResponse; + } + }); + } + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create().withPrimary(primary) + .withSecondary(ImmutableList.of()).build(); + + return new EndpointMock(addressSelectorWrapper, transportClientWrapperBuilder.build()) {}; + } + } + + static public class NoSecondaryReplica_TwoSecondaryReplicasGoLiveAfterFirstHitOnPrimary extends Builder { + private long LOCAL_LSN = 19; + private long LSN = 52; + private URI primary = URI.create("primary"); + private ImmutableList secondaryReplicas = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2")); + private StoreResponse primaryDefaultResponse = StoreResponseBuilder.create() + .withLSN(LSN) + .withLocalLSN(LOCAL_LSN) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, "3") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, Long.toString(LSN)) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(LOCAL_LSN)) + .withRequestCharge(0) + .build(); + + private StoreResponse secondaryDefaultResponse = StoreResponseBuilder.create() + .withLSN(LSN) + .withLocalLSN(LOCAL_LSN) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, Long.toString(LSN)) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(LOCAL_LSN)) + .withRequestCharge(0) + .build(); + Map> secondaryResponseFunc = + new HashMap<>(); + + + public NoSecondaryReplica_TwoSecondaryReplicasGoLiveAfterFirstHitOnPrimary primaryReplica(URI primaryReplica) { + this.primary = primaryReplica; + return this; + } + + public NoSecondaryReplica_TwoSecondaryReplicasGoLiveAfterFirstHitOnPrimary responseFromSecondary( + URI replica, + Function1WithCheckedException func) { + secondaryResponseFunc.put(replica, func); + return this; + } + + public EndpointMock build() { + + TransportClientWrapper.Builder.ReplicaResponseBuilder transportClientWrapperBuilder = TransportClientWrapper.Builder.replicaResponseBuilder(); + + transportClientWrapperBuilder.addReplica(primary, (i, request) -> { + return primaryDefaultResponse; + }); + + transportClientWrapperBuilder.addReplica(secondaryReplicas.get(0), (i, request) -> { + return secondaryDefaultResponse; + }); + + transportClientWrapperBuilder.addReplica(secondaryReplicas.get(1), (i, request) -> { + return secondaryDefaultResponse; + }); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create().withPrimary(primary) + .withSecondary(ImmutableList.of()).build(); + + return new EndpointMock(addressSelectorWrapper, transportClientWrapperBuilder.build()){}; + } + } + + public abstract EndpointMock build() ; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ExceptionBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ExceptionBuilder.java new file mode 100644 index 0000000000000..e76abf34edbc4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ExceptionBuilder.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ExceptionBuilder { + private Integer status; + private List> headerEntries; + private String message; + + public static ExceptionBuilder create() { + return new ExceptionBuilder(); + } + + public ExceptionBuilder() { + headerEntries = new ArrayList<>(); + } + + public ExceptionBuilder withHeader(String key, String value) { + headerEntries.add(new AbstractMap.SimpleEntry(key, value)); + return this; + } + + public ExceptionBuilder withStatus(int status) { + this.status = status; + return this; + } + + public ExceptionBuilder withMessage(String message) { + this.message = message; + return this; + } + + public GoneException asGoneException() { + assert status == null; + GoneException dce = new GoneException(); + dce.responseHeaders().putAll(headerEntries.stream().collect(Collectors.toMap(i -> i.getKey(), i -> i.getValue()))); + return dce; + } + + public InvalidPartitionException asInvalidPartitionException() { + assert status == null; + InvalidPartitionException dce = new InvalidPartitionException(); + dce.responseHeaders().putAll(headerEntries.stream().collect(Collectors.toMap(i -> i.getKey(), i -> i.getValue()))); + return dce; + } + + public PartitionKeyRangeGoneException asPartitionKeyRangeGoneException() { + assert status == null; + PartitionKeyRangeGoneException dce = new PartitionKeyRangeGoneException(); + dce.responseHeaders().putAll(headerEntries.stream().collect(Collectors.toMap(i -> i.getKey(), i -> i.getValue()))); + return dce; + } + + + public PartitionKeyRangeIsSplittingException asPartitionKeyRangeIsSplittingException() { + assert status == null; + PartitionKeyRangeIsSplittingException dce = new PartitionKeyRangeIsSplittingException(); + dce.responseHeaders().putAll(headerEntries.stream().collect(Collectors.toMap(i -> i.getKey(), i -> i.getValue()))); + return dce; + } + + public PartitionIsMigratingException asPartitionIsMigratingException() { + assert status == null; + PartitionIsMigratingException dce = new PartitionIsMigratingException(); + dce.responseHeaders().putAll(headerEntries.stream().collect(Collectors.toMap(i -> i.getKey(), i -> i.getValue()))); + return dce; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function1WithCheckedException.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function1WithCheckedException.java new file mode 100644 index 0000000000000..f84b0cf704b74 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function1WithCheckedException.java @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +@FunctionalInterface +public interface Function1WithCheckedException{ + + R apply(T t) throws Exception; + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function2WithCheckedException.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function2WithCheckedException.java new file mode 100644 index 0000000000000..b0e7b6cc0019c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/Function2WithCheckedException.java @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +@FunctionalInterface +public interface Function2WithCheckedException{ + R apply(T1 t1, T2 t2) throws Exception; + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCacheTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCacheTest.java new file mode 100644 index 0000000000000..c6e7fc457f412 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayAddressCacheTest.java @@ -0,0 +1,868 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpClientConfig; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class GatewayAddressCacheTest extends TestSuiteBase { + private Database createdDatabase; + private DocumentCollection createdCollection; + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public GatewayAddressCacheTest(Builder clientBuilder) { + super(clientBuilder); + } + + @DataProvider(name = "targetPartitionsKeyRangeListAndCollectionLinkParams") + public Object[][] partitionsKeyRangeListAndCollectionLinkParams() { + return new Object[][] { + // target partition key range ids, collection link + { ImmutableList.of("0"), getNameBasedCollectionLink(), Protocol.TCP}, + { ImmutableList.of("0"), getNameBasedCollectionLink(), Protocol.HTTPS}, + + { ImmutableList.of("1"), getNameBasedCollectionLink(), Protocol.HTTPS}, + { ImmutableList.of("1"), getCollectionSelfLink(), Protocol.HTTPS}, + { ImmutableList.of("3"), getNameBasedCollectionLink(), Protocol.HTTPS}, + + { ImmutableList.of("0", "1"), getNameBasedCollectionLink(), Protocol.HTTPS}, + { ImmutableList.of("1", "3"), getNameBasedCollectionLink(), Protocol.HTTPS}, + }; + } + + @DataProvider(name = "protocolProvider") + public Object[][] protocolProvider() { + return new Object[][]{ + { Protocol.HTTPS}, + { Protocol.TCP}, + }; + } + + @Test(groups = { "direct" }, dataProvider = "targetPartitionsKeyRangeListAndCollectionLinkParams", timeOut = TIMEOUT) + public void getServerAddressesViaGateway(List partitionKeyRangeIds, + String collectionLink, + Protocol protocol) throws Exception { + Configs configs = ConfigsBuilder.instance().withProtocol(protocol).build(); + // ask gateway for the addresses + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + protocol, + authorizationTokenProvider, + null, + getHttpClient(configs)); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionLink + "/docs/", + getDocumentDefinition(), new HashMap<>()); + + Mono> addresses = cache.getServerAddressesViaGatewayAsync( + req, createdCollection.resourceId(), partitionKeyRangeIds, false); + + PartitionReplicasAddressesValidator validator = new PartitionReplicasAddressesValidator.Builder() + .withProtocol(protocol) + .replicasOfPartitions(partitionKeyRangeIds) + .build(); + + validateSuccess(addresses, validator, TIMEOUT); + } + + @Test(groups = { "direct" }, dataProvider = "protocolProvider", timeOut = TIMEOUT) + public void getMasterAddressesViaGatewayAsync(Protocol protocol) throws Exception { + Configs configs = ConfigsBuilder.instance().withProtocol(protocol).build(); + // ask gateway for the addresses + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + protocol, + authorizationTokenProvider, + null, + getHttpClient(configs)); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + Mono> addresses = cache.getMasterAddressesViaGatewayAsync(req, ResourceType.Database, + null, "/dbs/", false, false, null); + + PartitionReplicasAddressesValidator validator = new PartitionReplicasAddressesValidator.Builder() + .withProtocol(protocol) + .replicasOfSamePartition() + .build(); + + validateSuccess(addresses, validator, TIMEOUT); + } + + @DataProvider(name = "targetPartitionsKeyRangeAndCollectionLinkParams") + public Object[][] partitionsKeyRangeAndCollectionLinkParams() { + return new Object[][] { + // target partition key range ids, collection link, protocol + { "0", getNameBasedCollectionLink(), Protocol.TCP}, + { "0", getNameBasedCollectionLink(), Protocol.HTTPS}, + + { "1", getNameBasedCollectionLink(), Protocol.HTTPS} , + { "1", getCollectionSelfLink(), Protocol.HTTPS}, + { "3", getNameBasedCollectionLink(), Protocol.HTTPS}, + }; + } + + @Test(groups = { "direct" }, dataProvider = "targetPartitionsKeyRangeAndCollectionLinkParams", timeOut = TIMEOUT) + public void tryGetAddresses_ForDataPartitions(String partitionKeyRangeId, String collectionLink, Protocol protocol) throws Exception { + Configs configs = ConfigsBuilder.instance().withProtocol(protocol).build(); + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + protocol, + authorizationTokenProvider, + null, + getHttpClient(configs)); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionLink, + new Database(), new HashMap<>()); + + String collectionRid = createdCollection.resourceId(); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(collectionRid, partitionKeyRangeId); + boolean forceRefreshPartitionAddresses = false; + Mono addressesInfosFromCacheObs = cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses); + + ArrayList addressInfosFromCache = Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT)); + + Mono> masterAddressFromGatewayObs = cache.getServerAddressesViaGatewayAsync(req, + collectionRid, ImmutableList.of(partitionKeyRangeId), false); + List
    expectedAddresses = getSuccessResult(masterAddressFromGatewayObs, TIMEOUT); + + assertSameAs(addressInfosFromCache, expectedAddresses); + } + + @DataProvider(name = "openAsyncTargetAndTargetPartitionsKeyRangeAndCollectionLinkParams") + public Object[][] openAsyncTargetAndPartitionsKeyRangeTargetAndCollectionLinkParams() { + return new Object[][] { + // openAsync target partition key range ids, target partition key range id, collection link + { ImmutableList.of("0", "1"), "0", getNameBasedCollectionLink() }, + { ImmutableList.of("0", "1"), "1", getNameBasedCollectionLink() }, + { ImmutableList.of("0", "1"), "1", getCollectionSelfLink() }, + }; + } + + @Test(groups = { "direct" }, + dataProvider = "openAsyncTargetAndTargetPartitionsKeyRangeAndCollectionLinkParams", + timeOut = TIMEOUT) + public void tryGetAddresses_ForDataPartitions_AddressCachedByOpenAsync_NoHttpRequest( + List allPartitionKeyRangeIds, + String partitionKeyRangeId, String collectionLink) throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper httpClientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + httpClientWrapper.getSpyHttpClient()); + + String collectionRid = createdCollection.resourceId(); + + List pkriList = allPartitionKeyRangeIds.stream().map( + pkri -> new PartitionKeyRangeIdentity(collectionRid, pkri)).collect(Collectors.toList()); + + cache.openAsync(createdCollection, pkriList).block(); + + assertThat(httpClientWrapper.capturedRequests).asList().hasSize(1); + httpClientWrapper.capturedRequests.clear(); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionLink, + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(collectionRid, partitionKeyRangeId); + boolean forceRefreshPartitionAddresses = false; + Mono addressesInfosFromCacheObs = cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses); + ArrayList addressInfosFromCache = Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT)); + + // no new request is made + assertThat(httpClientWrapper.capturedRequests) + .describedAs("no http request: addresses already cached by openAsync") + .asList().hasSize(0); + + Mono> masterAddressFromGatewayObs = cache.getServerAddressesViaGatewayAsync(req, + collectionRid, ImmutableList.of(partitionKeyRangeId), false); + List
    expectedAddresses = getSuccessResult(masterAddressFromGatewayObs, TIMEOUT); + + assertThat(httpClientWrapper.capturedRequests) + .describedAs("getServerAddressesViaGatewayAsync will read addresses from gateway") + .asList().hasSize(1); + + assertSameAs(addressInfosFromCache, expectedAddresses); + } + + @Test(groups = { "direct" }, + dataProvider = "openAsyncTargetAndTargetPartitionsKeyRangeAndCollectionLinkParams", + timeOut = TIMEOUT) + public void tryGetAddresses_ForDataPartitions_ForceRefresh( + List allPartitionKeyRangeIds, + String partitionKeyRangeId, + String collectionLink) throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper httpClientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + httpClientWrapper.getSpyHttpClient()); + + String collectionRid = createdCollection.resourceId(); + + List pkriList = allPartitionKeyRangeIds.stream().map( + pkri -> new PartitionKeyRangeIdentity(collectionRid, pkri)).collect(Collectors.toList()); + + cache.openAsync(createdCollection, pkriList).block(); + + assertThat(httpClientWrapper.capturedRequests).asList().hasSize(1); + httpClientWrapper.capturedRequests.clear(); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionLink, + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(collectionRid, partitionKeyRangeId); + Mono addressesInfosFromCacheObs = cache.tryGetAddresses(req, partitionKeyRangeIdentity, true); + ArrayList addressInfosFromCache = Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT)); + + // no new request is made + assertThat(httpClientWrapper.capturedRequests) + .describedAs("force refresh fetched from gateway") + .asList().hasSize(1); + + Mono> masterAddressFromGatewayObs = cache.getServerAddressesViaGatewayAsync(req, + collectionRid, ImmutableList.of(partitionKeyRangeId), false); + List
    expectedAddresses = getSuccessResult(masterAddressFromGatewayObs, TIMEOUT); + + assertThat(httpClientWrapper.capturedRequests) + .describedAs("getServerAddressesViaGatewayAsync will read addresses from gateway") + .asList().hasSize(2); + + assertSameAs(addressInfosFromCache, expectedAddresses); + } + + @Test(groups = { "direct" }, + dataProvider = "openAsyncTargetAndTargetPartitionsKeyRangeAndCollectionLinkParams", + timeOut = TIMEOUT) + public void tryGetAddresses_ForDataPartitions_Suboptimal_Refresh( + List allPartitionKeyRangeIds, + String partitionKeyRangeId, + String collectionLink) throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper httpClientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + int suboptimalRefreshTime = 2; + + GatewayAddressCache origCache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + httpClientWrapper.getSpyHttpClient(), + suboptimalRefreshTime); + + String collectionRid = createdCollection.resourceId(); + + List pkriList = allPartitionKeyRangeIds.stream().map( + pkri -> new PartitionKeyRangeIdentity(collectionRid, pkri)).collect(Collectors.toList()); + + origCache.openAsync(createdCollection, pkriList).block(); + + assertThat(httpClientWrapper.capturedRequests).asList().hasSize(1); + httpClientWrapper.capturedRequests.clear(); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, + collectionLink, + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(collectionRid, partitionKeyRangeId); + Mono addressesInfosFromCacheObs = origCache.tryGetAddresses(req, partitionKeyRangeIdentity, true); + ArrayList addressInfosFromCache = Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT)); + + // no new request is made + assertThat(httpClientWrapper.capturedRequests) + .describedAs("force refresh fetched from gateway") + .asList().hasSize(1); + + GatewayAddressCache spyCache = Mockito.spy(origCache); + + final AtomicInteger fetchCounter = new AtomicInteger(0); + Mockito.doAnswer(new Answer() { + @Override + public Mono> answer(InvocationOnMock invocationOnMock) throws Throwable { + + RxDocumentServiceRequest req = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + String collectionRid = invocationOnMock.getArgumentAt(1, String.class); + List partitionKeyRangeIds = invocationOnMock.getArgumentAt(2, List.class); + boolean forceRefresh = invocationOnMock.getArgumentAt(3, Boolean.class); + + int cnt = fetchCounter.getAndIncrement(); + + if (cnt == 0) { + Mono> res = origCache.getServerAddressesViaGatewayAsync(req, + collectionRid, + partitionKeyRangeIds, + forceRefresh); + + // remove one replica + return res.map(list -> removeOneReplica(list)); + } + + return origCache.getServerAddressesViaGatewayAsync(req, + collectionRid, + partitionKeyRangeIds, + forceRefresh); + } + }).when(spyCache).getServerAddressesViaGatewayAsync(Matchers.any(RxDocumentServiceRequest.class), Matchers.anyString(), + Matchers.anyList(), Matchers.anyBoolean()); + + httpClientWrapper.capturedRequests.clear(); + + // force refresh to replace existing with sub-optimal addresses + addressesInfosFromCacheObs = spyCache.tryGetAddresses(req, partitionKeyRangeIdentity, true); + AddressInformation[] suboptimalAddresses = getSuccessResult(addressesInfosFromCacheObs, TIMEOUT); + assertThat(httpClientWrapper.capturedRequests) + .describedAs("getServerAddressesViaGatewayAsync will read addresses from gateway") + .asList().hasSize(1); + httpClientWrapper.capturedRequests.clear(); + assertThat(suboptimalAddresses).hasSize(ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize - 1); + assertThat(fetchCounter.get()).isEqualTo(1); + + // no refresh, use cache + addressesInfosFromCacheObs = spyCache.tryGetAddresses(req, partitionKeyRangeIdentity, false); + suboptimalAddresses = getSuccessResult(addressesInfosFromCacheObs, TIMEOUT); + assertThat(httpClientWrapper.capturedRequests) + .describedAs("getServerAddressesViaGatewayAsync will read addresses from gateway") + .asList().hasSize(0); + assertThat(suboptimalAddresses).hasSize(ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize - 1); + assertThat(fetchCounter.get()).isEqualTo(1); + + // wait for refresh time + TimeUnit.SECONDS.sleep(suboptimalRefreshTime + 1); + + addressesInfosFromCacheObs = spyCache.tryGetAddresses(req, partitionKeyRangeIdentity, false); + AddressInformation[] addresses = getSuccessResult(addressesInfosFromCacheObs, TIMEOUT); + assertThat(addresses).hasSize(ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize); + assertThat(httpClientWrapper.capturedRequests) + .describedAs("getServerAddressesViaGatewayAsync will read addresses from gateway") + .asList().hasSize(1); + assertThat(fetchCounter.get()).isEqualTo(2); + } + + @Test(groups = { "direct" }, dataProvider = "protocolProvider",timeOut = TIMEOUT) + public void tryGetAddresses_ForMasterPartition(Protocol protocol) throws Exception { + Configs configs = ConfigsBuilder.instance().withProtocol(protocol).build(); + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + protocol, + authorizationTokenProvider, + null, + getHttpClient(configs)); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity("M"); + boolean forceRefreshPartitionAddresses = false; + Mono addressesInfosFromCacheObs = cache.tryGetAddresses(req, partitionKeyRangeIdentity, forceRefreshPartitionAddresses); + + ArrayList addressInfosFromCache = Lists.newArrayList(getSuccessResult(addressesInfosFromCacheObs, TIMEOUT)); + + Mono> masterAddressFromGatewayObs = cache.getMasterAddressesViaGatewayAsync(req, ResourceType.Database, + null, "/dbs/", false, false, null); + List
    expectedAddresses = getSuccessResult(masterAddressFromGatewayObs, TIMEOUT); + + assertSameAs(addressInfosFromCache, expectedAddresses); + } + + @DataProvider(name = "refreshTime") + public Object[][] refreshTime() { + return new Object[][] { + // refresh time, wait before doing tryGetAddresses + { 60, 1 }, + { 1, 2 }, + }; + } + + @Test(groups = { "direct" }, timeOut = TIMEOUT, dataProvider = "refreshTime") + public void tryGetAddresses_ForMasterPartition_MasterPartitionAddressAlreadyCached_NoNewHttpRequest( + int suboptimalPartitionForceRefreshIntervalInSeconds, + int waitTimeInBetweenAttemptsInSeconds + ) throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper clientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + clientWrapper.getSpyHttpClient(), + suboptimalPartitionForceRefreshIntervalInSeconds); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity("M"); + boolean forceRefreshPartitionAddresses = false; + + // request master partition info to ensure it is cached. + AddressInformation[] expectedAddresses = cache.tryGetAddresses(req, + partitionKeyRangeIdentity, + forceRefreshPartitionAddresses) + .block(); + + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + clientWrapper.capturedRequests.clear(); + + + TimeUnit.SECONDS.sleep(waitTimeInBetweenAttemptsInSeconds); + + Mono addressesObs = cache.tryGetAddresses(req, + partitionKeyRangeIdentity, + forceRefreshPartitionAddresses); + + AddressInformation[] actualAddresses = getSuccessResult(addressesObs, TIMEOUT); + + assertExactlyEqual(actualAddresses, expectedAddresses); + + // the cache address is used. no new http request is sent + assertThat(clientWrapper.capturedRequests).asList().hasSize(0); + } + + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void tryGetAddresses_ForMasterPartition_ForceRefresh() throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper clientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + GatewayAddressCache cache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + clientWrapper.getSpyHttpClient()); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity("M"); + + // request master partition info to ensure it is cached. + AddressInformation[] expectedAddresses = cache.tryGetAddresses(req, + partitionKeyRangeIdentity, + false) + .block(); + + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + clientWrapper.capturedRequests.clear(); + + Mono addressesObs = cache.tryGetAddresses(req, + partitionKeyRangeIdentity, + true); + + AddressInformation[] actualAddresses = getSuccessResult(addressesObs, TIMEOUT); + + assertExactlyEqual(actualAddresses, expectedAddresses); + + // the cache address is used. no new http request is sent + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + } + + private static List
    removeOneReplica(List
    addresses) { + addresses.remove(0); + return addresses; + } + + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void tryGetAddresses_SuboptimalMasterPartition_NotStaleEnough_NoRefresh() throws Exception { + Configs configs = new Configs(); + Instant start = Instant.now(); + HttpClientUnderTestWrapper clientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + int refreshPeriodInSeconds = 10; + + GatewayAddressCache origCache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + clientWrapper.getSpyHttpClient(), refreshPeriodInSeconds); + + GatewayAddressCache spyCache = Mockito.spy(origCache); + + final AtomicInteger getMasterAddressesViaGatewayAsyncInvocation = new AtomicInteger(0); + Mockito.doAnswer(new Answer() { + @Override + public Mono> answer(InvocationOnMock invocationOnMock) throws Throwable { + + RxDocumentServiceRequest request = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + ResourceType resourceType = invocationOnMock.getArgumentAt(1, ResourceType.class); + String resourceAddress = invocationOnMock.getArgumentAt(2, String.class); + String entryUrl = invocationOnMock.getArgumentAt(3, String.class); + boolean forceRefresh = invocationOnMock.getArgumentAt(4, Boolean.class); + boolean useMasterCollectionResolver = invocationOnMock.getArgumentAt(5, Boolean.class); + + int cnt = getMasterAddressesViaGatewayAsyncInvocation.getAndIncrement(); + + if (cnt == 0) { + Mono> res = origCache.getMasterAddressesViaGatewayAsync( + request, + resourceType, + resourceAddress, + entryUrl, + forceRefresh, + useMasterCollectionResolver, + null); + + // remove one replica + return res.map(list -> removeOneReplica(list)); + } + + return origCache.getMasterAddressesViaGatewayAsync( + request, + resourceType, + resourceAddress, + entryUrl, + forceRefresh, + useMasterCollectionResolver, + null); + } + }).when(spyCache).getMasterAddressesViaGatewayAsync(Matchers.any(RxDocumentServiceRequest.class), Matchers.any(ResourceType.class), Matchers.anyString(), + Matchers.anyString(), Matchers.anyBoolean(), Matchers.anyBoolean(), Matchers.anyMap()); + + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity("M"); + + // request master partition info to ensure it is cached. + AddressInformation[] expectedAddresses = spyCache.tryGetAddresses(req, + partitionKeyRangeIdentity, + false) + .block(); + + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + clientWrapper.capturedRequests.clear(); + + Mono addressesObs = spyCache.tryGetAddresses(req, + partitionKeyRangeIdentity, + false); + + AddressInformation[] actualAddresses = getSuccessResult(addressesObs, TIMEOUT); + + assertExactlyEqual(actualAddresses, expectedAddresses); + + // the cache address is used. no new http request is sent + assertThat(clientWrapper.capturedRequests).asList().hasSize(0); + + Instant end = Instant.now(); + assertThat(end.minusSeconds(refreshPeriodInSeconds)).isBefore(start); + } + + @Test(groups = { "direct" }, timeOut = TIMEOUT) + public void tryGetAddresses_SuboptimalMasterPartition_Stale_DoRefresh() throws Exception { + Configs configs = new Configs(); + HttpClientUnderTestWrapper clientWrapper = getHttpClientUnderTestWrapper(configs); + + URL serviceEndpoint = new URL(TestConfigurations.HOST); + IAuthorizationTokenProvider authorizationTokenProvider = (RxDocumentClientImpl) client; + + int refreshPeriodInSeconds = 1; + + GatewayAddressCache origCache = new GatewayAddressCache(serviceEndpoint, + Protocol.HTTPS, + authorizationTokenProvider, + null, + clientWrapper.getSpyHttpClient(), refreshPeriodInSeconds); + + GatewayAddressCache spyCache = Mockito.spy(origCache); + + final AtomicInteger getMasterAddressesViaGatewayAsyncInvocation = new AtomicInteger(0); + Mockito.doAnswer(new Answer() { + @Override + public Mono> answer(InvocationOnMock invocationOnMock) throws Throwable { + + System.out.print("fetch"); + + RxDocumentServiceRequest request = invocationOnMock.getArgumentAt(0, RxDocumentServiceRequest.class); + ResourceType resourceType = invocationOnMock.getArgumentAt(1, ResourceType.class); + String resourceAddress = invocationOnMock.getArgumentAt(2, String.class); + String entryUrl = invocationOnMock.getArgumentAt(3, String.class); + boolean forceRefresh = invocationOnMock.getArgumentAt(4, Boolean.class); + boolean useMasterCollectionResolver = invocationOnMock.getArgumentAt(5, Boolean.class); + + int cnt = getMasterAddressesViaGatewayAsyncInvocation.getAndIncrement(); + + if (cnt == 0) { + Mono> res = origCache.getMasterAddressesViaGatewayAsync( + request, + resourceType, + resourceAddress, + entryUrl, + forceRefresh, + useMasterCollectionResolver, + null); + + // remove one replica + return res.map(list -> removeOneReplica(list)); + } + + return origCache.getMasterAddressesViaGatewayAsync( + request, + resourceType, + resourceAddress, + entryUrl, + forceRefresh, + useMasterCollectionResolver, + null); + } + }).when(spyCache).getMasterAddressesViaGatewayAsync(Matchers.any(RxDocumentServiceRequest.class), Matchers.any(ResourceType.class), Matchers.anyString(), + Matchers.anyString(), Matchers.anyBoolean(), Matchers.anyBoolean(), Matchers.anyMap()); + + RxDocumentServiceRequest req = + RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Database, + "/dbs", + new Database(), new HashMap<>()); + + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity("M"); + + // request master partition info to ensure it is cached. + AddressInformation[] subOptimalAddresses = spyCache.tryGetAddresses(req, + partitionKeyRangeIdentity, + false) + .block(); + + assertThat(getMasterAddressesViaGatewayAsyncInvocation.get()).isEqualTo(1); + assertThat(subOptimalAddresses).hasSize(ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize - 1); + + Instant start = Instant.now(); + TimeUnit.SECONDS.sleep(refreshPeriodInSeconds + 1); + Instant end = Instant.now(); + assertThat(end.minusSeconds(refreshPeriodInSeconds)).isAfter(start); + + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + clientWrapper.capturedRequests.clear(); + + Mono addressesObs = spyCache.tryGetAddresses(req, + partitionKeyRangeIdentity, + false); + + + AddressInformation[] actualAddresses = getSuccessResult(addressesObs, TIMEOUT); + // the cache address is used. no new http request is sent + assertThat(clientWrapper.capturedRequests).asList().hasSize(1); + assertThat(getMasterAddressesViaGatewayAsyncInvocation.get()).isEqualTo(2); + assertThat(actualAddresses).hasSize(ServiceConfig.SystemReplicationPolicy.MaxReplicaSetSize); + + List
    fetchedAddresses = origCache.getMasterAddressesViaGatewayAsync(req, ResourceType.Database, + null, "/dbs/", false, false, null).block(); + + assertSameAs(ImmutableList.copyOf(actualAddresses), fetchedAddresses); + } + + public static void assertSameAs(List actual, List
    expected) { + assertThat(actual).asList().hasSize(expected.size()); + for(int i = 0; i < expected.size(); i++) { + assertEqual(actual.get(i), expected.get(i)); + } + } + + private static void assertEqual(AddressInformation actual, Address expected) { + assertThat(actual.getPhysicalUri()).isEqualTo(expected.getPhyicalUri()); + assertThat(actual.getProtocolScheme()).isEqualTo(expected.getProtocolScheme().toLowerCase()); + assertThat(actual.isPrimary()).isEqualTo(expected.IsPrimary()); + } + + private static void assertEqual(AddressInformation actual, AddressInformation expected) { + assertThat(actual.getPhysicalUri()).isEqualTo(expected.getPhysicalUri()); + assertThat(actual.getProtocolName()).isEqualTo(expected.getProtocolName()); + assertThat(actual.isPrimary()).isEqualTo(expected.isPrimary()); + assertThat(actual.isPublic()).isEqualTo(expected.isPublic()); + } + + public static void assertExactlyEqual(AddressInformation[] actual, AddressInformation[] expected) { + assertExactlyEqual(Arrays.asList(actual), Arrays.asList(expected)); + } + + public static void assertExactlyEqual(List actual, List expected) { + assertThat(actual).asList().hasSize(expected.size()); + for(int i = 0; i < expected.size(); i++) { + assertEqual(actual.get(i), expected.get(i)); + } + } + + public static T getSuccessResult(Mono observable, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + return testSubscriber.values().get(0); + } + + public static void validateSuccess(Mono> observable, + PartitionReplicasAddressesValidator validator, long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + @BeforeClass(groups = { "direct" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = SHARED_DATABASE; + + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(30000); + createdCollection = createCollection(client, createdDatabase.id(), getCollectionDefinition(), options); + } + + @AfterClass(groups = { "direct" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteCollection(client, createdCollection); + safeClose(client); + } + + static protected DocumentCollection getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id("mycol"); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + private HttpClient getHttpClient(Configs configs) { + return HttpClient.createFixed(new HttpClientConfig(configs)); + } + + private HttpClientUnderTestWrapper getHttpClientUnderTestWrapper(Configs configs) { + HttpClient origHttpClient = getHttpClient(configs); + return new HttpClientUnderTestWrapper(origHttpClient); + } + + public String getNameBasedCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } + + public String getCollectionSelfLink() { + return createdCollection.selfLink(); + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java new file mode 100644 index 0000000000000..99ce070900378 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java @@ -0,0 +1,174 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.BaseAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.SpyClientUnderTestFactory; +import com.azure.data.cosmos.internal.TestSuiteBase; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import com.azure.data.cosmos.internal.TestConfigurations; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.io.IOUtils; +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GatewayServiceConfigurationReaderTest extends TestSuiteBase { + + private static final int TIMEOUT = 8000; + private HttpClient mockHttpClient; + private BaseAuthorizationTokenProvider baseAuthorizationTokenProvider; + private ConnectionPolicy connectionPolicy; + private GatewayServiceConfigurationReader mockGatewayServiceConfigurationReader; + private GatewayServiceConfigurationReader gatewayServiceConfigurationReader; + private AsyncDocumentClient client; + private String databaseAccountJson; + private DatabaseAccount expectedDatabaseAccount; + + @Factory(dataProvider = "clientBuilders") + public GatewayServiceConfigurationReaderTest(Builder clientBuilder) { + super(clientBuilder); + } + + @BeforeClass(groups = "simple") + public void setup() throws Exception { + client = clientBuilder().build(); + SpyClientUnderTestFactory.ClientUnderTest clientUnderTest = SpyClientUnderTestFactory.createClientUnderTest(this.clientBuilder()); + HttpClient httpClient = clientUnderTest.getSpyHttpClient(); + baseAuthorizationTokenProvider = new BaseAuthorizationTokenProvider(TestConfigurations.MASTER_KEY); + connectionPolicy = ConnectionPolicy.defaultPolicy(); + mockHttpClient = Mockito.mock(HttpClient.class); + mockGatewayServiceConfigurationReader = new GatewayServiceConfigurationReader(new URI(TestConfigurations.HOST), + false, TestConfigurations.MASTER_KEY, connectionPolicy, baseAuthorizationTokenProvider, mockHttpClient); + + gatewayServiceConfigurationReader = new GatewayServiceConfigurationReader(new URI(TestConfigurations.HOST), + false, + TestConfigurations.MASTER_KEY, + connectionPolicy, + baseAuthorizationTokenProvider, + httpClient); + databaseAccountJson = IOUtils + .toString(getClass().getClassLoader().getResourceAsStream("databaseAccount.json"), "UTF-8"); + expectedDatabaseAccount = new DatabaseAccount(databaseAccountJson); + HttpResponse mockResponse = getMockResponse(databaseAccountJson); + Mockito.when(mockHttpClient.send(Mockito.any(HttpRequest.class))).thenReturn(Mono.just(mockResponse)); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @Test(groups = "simple") + public void mockInitializeReaderAsync() { + Mono databaseAccount = mockGatewayServiceConfigurationReader.initializeReaderAsync(); + validateSuccess(databaseAccount, expectedDatabaseAccount); + } + + @Test(groups = "simple") + public void mockInitializeReaderAsyncWithResourceToken() throws Exception { + HttpResponse mockResponse = getMockResponse(databaseAccountJson); + Mockito.when(mockHttpClient.send(Mockito.any(HttpRequest.class))).thenReturn(Mono.just(mockResponse)); + + mockGatewayServiceConfigurationReader = new GatewayServiceConfigurationReader(new URI(TestConfigurations.HOST), + true, "SampleResourceToken", connectionPolicy, baseAuthorizationTokenProvider, mockHttpClient); + + Mono databaseAccount = mockGatewayServiceConfigurationReader.initializeReaderAsync(); + validateSuccess(databaseAccount, expectedDatabaseAccount); + } + + @Test(groups = "simple") + public void initializeReaderAsync() { + Mono databaseAccount = gatewayServiceConfigurationReader.initializeReaderAsync(); + validateSuccess(databaseAccount); + } + + public static void validateSuccess(Mono observable) { + TestSubscriber testSubscriber = new TestSubscriber(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + DatabaseAccount databaseAccount = testSubscriber.values().get(0); + assertThat(BridgeInternal.getQueryEngineConfiuration(databaseAccount).size() > 0).isTrue(); + assertThat(BridgeInternal.getReplicationPolicy(databaseAccount)).isNotNull(); + assertThat(BridgeInternal.getSystemReplicationPolicy(databaseAccount)).isNotNull(); + } + + public static void validateSuccess(Mono observable, DatabaseAccount expectedDatabaseAccount) { + TestSubscriber testSubscriber = new TestSubscriber(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + DatabaseAccount databaseAccount = testSubscriber.values().get(0); + assertThat(databaseAccount.id()).isEqualTo(expectedDatabaseAccount.id()); + assertThat(databaseAccount.getAddressesLink()) + .isEqualTo(expectedDatabaseAccount.getAddressesLink()); + assertThat(databaseAccount.getWritableLocations().iterator().next().getEndpoint()) + .isEqualTo(expectedDatabaseAccount.getWritableLocations().iterator().next().getEndpoint()); + assertThat(BridgeInternal.getSystemReplicationPolicy(databaseAccount).getMaxReplicaSetSize()) + .isEqualTo(BridgeInternal.getSystemReplicationPolicy(expectedDatabaseAccount).getMaxReplicaSetSize()); + assertThat(BridgeInternal.getSystemReplicationPolicy(databaseAccount).getMaxReplicaSetSize()) + .isEqualTo(BridgeInternal.getSystemReplicationPolicy(expectedDatabaseAccount).getMaxReplicaSetSize()); + assertThat(BridgeInternal.getQueryEngineConfiuration(databaseAccount)) + .isEqualTo(BridgeInternal.getQueryEngineConfiuration(expectedDatabaseAccount)); + } + + private HttpResponse getMockResponse(String databaseAccountJson) { + HttpResponse httpResponse = Mockito.mock(HttpResponse.class); + Mockito.doReturn(200).when(httpResponse).statusCode(); + Mockito.doReturn(Flux.just(ByteBufUtil.writeUtf8(ByteBufAllocator.DEFAULT, databaseAccountJson))) + .when(httpResponse).body(); + Mockito.doReturn(Mono.just(databaseAccountJson)) + .when(httpResponse).bodyAsString(StandardCharsets.UTF_8); + + Mockito.doReturn(new HttpHeaders()).when(httpResponse).headers(); + return httpResponse; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfiguratorReaderMock.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfiguratorReaderMock.java new file mode 100644 index 0000000000000..9d97801ce09eb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GatewayServiceConfiguratorReaderMock.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.ReplicationPolicy; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +public class GatewayServiceConfiguratorReaderMock { + + public GatewayServiceConfigurationReader gatewayServiceConfigurationReader; + + public static GatewayServiceConfiguratorReaderMock from(ConsistencyLevel accountConsistencyLevel) { + return new GatewayServiceConfiguratorReaderMock(new ReplicationPolicy("{}"), new ReplicationPolicy("{}"), accountConsistencyLevel); + } + + public static GatewayServiceConfiguratorReaderMock from(ConsistencyLevel accountConsistencyLevel, + int systemMaxReplicaCount, + int systemMinReplicaCount, + int userMaxReplicaCount, + int userMinReplicaCount) { + ReplicationPolicy userRP = Mockito.mock(ReplicationPolicy.class); + Mockito.doReturn(userMaxReplicaCount).when(userRP).getMaxReplicaSetSize(); + Mockito.doReturn(userMinReplicaCount).when(userRP).getMinReplicaSetSize(); + + ReplicationPolicy systemRP = Mockito.mock(ReplicationPolicy.class); + Mockito.doReturn(systemMaxReplicaCount).when(systemRP).getMaxReplicaSetSize(); + Mockito.doReturn(systemMinReplicaCount).when(systemRP).getMinReplicaSetSize(); + + return new GatewayServiceConfiguratorReaderMock(userRP, systemRP, accountConsistencyLevel); + } + + public static GatewayServiceConfiguratorReaderMock from(ConsistencyLevel accountConsistencyLevel, int maxReplicaSize, int minReplicaCase) { + ReplicationPolicy rp = Mockito.mock(ReplicationPolicy.class); + Mockito.doReturn(maxReplicaSize).when(rp).getMaxReplicaSetSize(); + Mockito.doReturn(minReplicaCase).when(rp).getMinReplicaSetSize(); + + return new GatewayServiceConfiguratorReaderMock(rp, rp, accountConsistencyLevel); + } + + + public GatewayServiceConfiguratorReaderMock(ReplicationPolicy userReplicationPolicy, + ReplicationPolicy systemReplicationPolicy, + ConsistencyLevel defaultConsistencyLevel) { + this.gatewayServiceConfigurationReader = Mockito.mock(GatewayServiceConfigurationReader.class); + + Mockito.doReturn(Mono.just(Mockito.mock(DatabaseAccount.class))).when(this.gatewayServiceConfigurationReader).initializeReaderAsync(); + Mockito.doReturn(defaultConsistencyLevel).when(this.gatewayServiceConfigurationReader).getDefaultConsistencyLevel(); + Mockito.doReturn(systemReplicationPolicy).when(this.gatewayServiceConfigurationReader).getSystemReplicationPolicy(); + Mockito.doReturn(userReplicationPolicy).when(this.gatewayServiceConfigurationReader).getUserReplicationPolicy(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolverTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolverTest.java new file mode 100644 index 0000000000000..a6a05b430d380 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GlobalAddressResolverTest.java @@ -0,0 +1,192 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.GlobalEndpointManager; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.caches.RxCollectionCache; +import com.azure.data.cosmos.internal.caches.RxPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.routing.CollectionRoutingMap; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.Assertions.assertThat; + +; + +public class GlobalAddressResolverTest { + + private HttpClient httpClient; + private GlobalEndpointManager endpointManager; + private IAuthorizationTokenProvider authorizationTokenProvider; + private UserAgentContainer userAgentContainer; + private RxCollectionCache collectionCache; + private GatewayServiceConfigurationReader serviceConfigReader; + private RxPartitionKeyRangeCache routingMapProvider; + private ConnectionPolicy connectionPolicy; + private URL urlforRead1; + private URL urlforRead2; + private URL urlforRead3; + + private URL urlforWrite1; + private URL urlforWrite2; + private URL urlforWrite3; + + @BeforeClass(groups = "unit") + public void setup() throws Exception { + urlforRead1 = new URL("http://testRead1.com/"); + urlforRead2 = new URL("http://testRead2.com/"); + urlforRead3 = new URL("http://testRead3.com/"); + urlforWrite1 = new URL("http://testWrite1.com/"); + urlforWrite2 = new URL("http://testWrite2.com/"); + urlforWrite3 = new URL("http://testWrite3.com/"); + + connectionPolicy = new ConnectionPolicy(); + connectionPolicy.enableReadRequestsFallback(true); + httpClient = Mockito.mock(HttpClient.class); + endpointManager = Mockito.mock(GlobalEndpointManager.class); + + List readEndPointList = new ArrayList<>(); + readEndPointList.add(urlforRead1); + readEndPointList.add(urlforRead2); + readEndPointList.add(urlforRead3); + UnmodifiableList readList = new UnmodifiableList(readEndPointList); + + List writeEndPointList = new ArrayList<>(); + writeEndPointList.add(urlforWrite1); + writeEndPointList.add(urlforWrite2); + writeEndPointList.add(urlforWrite3); + UnmodifiableList writeList = new UnmodifiableList(writeEndPointList); + + Mockito.when(endpointManager.getReadEndpoints()).thenReturn(readList); + Mockito.when(endpointManager.getWriteEndpoints()).thenReturn(writeList); + + authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionCache = Mockito.mock(RxCollectionCache.class); + Mockito.when(collectionCache.resolveCollectionAsync(Matchers.any(RxDocumentServiceRequest.class))).thenReturn(Mono.just(collectionDefinition)); + routingMapProvider = Mockito.mock(RxPartitionKeyRangeCache.class); + userAgentContainer = Mockito.mock(UserAgentContainer.class); + serviceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + + } + + @Test(groups = "unit") + public void resolveAsync() throws Exception { + + GlobalAddressResolver globalAddressResolver = new GlobalAddressResolver(httpClient, endpointManager, Protocol.HTTPS, authorizationTokenProvider, collectionCache, routingMapProvider, + userAgentContainer, + serviceConfigReader, connectionPolicy); + RxDocumentServiceRequest request; + request = RxDocumentServiceRequest.createFromName( + OperationType.Read, + "dbs/db/colls/coll/docs/doc1", + ResourceType.Document); + + Set urlsBeforeResolve = globalAddressResolver.addressCacheByEndpoint.keySet(); + assertThat(urlsBeforeResolve.size()).isEqualTo(5); + assertThat(urlsBeforeResolve.contains(urlforRead3)).isFalse();//Last read will be removed from addressCacheByEndpoint after 5 endpoints + assertThat(urlsBeforeResolve.contains(urlforRead2)).isTrue(); + + URL testUrl = new URL("http://Test.com/"); + Mockito.when(endpointManager.resolveServiceEndpoint(Matchers.any(RxDocumentServiceRequest.class))).thenReturn(testUrl); + globalAddressResolver.resolveAsync(request, true); + Set urlsAfterResolve = globalAddressResolver.addressCacheByEndpoint.keySet(); + assertThat(urlsAfterResolve.size()).isEqualTo(5); + assertThat(urlsAfterResolve.contains(urlforRead2)).isFalse();//Last read will be removed from addressCacheByEndpoint after 5 endpoints + assertThat(urlsBeforeResolve.contains(testUrl)).isTrue();//New endpoint will be added in addressCacheByEndpoint + } + + @Test(groups = "unit") + public void openAsync() throws Exception { + GlobalAddressResolver globalAddressResolver = new GlobalAddressResolver(httpClient, endpointManager, Protocol.HTTPS, authorizationTokenProvider, collectionCache, routingMapProvider, + userAgentContainer, + serviceConfigReader, connectionPolicy); + Map addressCacheByEndpoint = Mockito.spy(globalAddressResolver.addressCacheByEndpoint); + GlobalAddressResolver.EndpointCache endpointCache = new GlobalAddressResolver.EndpointCache(); + GatewayAddressCache gatewayAddressCache = Mockito.mock(GatewayAddressCache.class); + AtomicInteger numberOfTaskCompleted = new AtomicInteger(0); + endpointCache.addressCache = gatewayAddressCache; + globalAddressResolver.addressCacheByEndpoint.clear(); + globalAddressResolver.addressCacheByEndpoint.put(urlforRead1, endpointCache); + globalAddressResolver.addressCacheByEndpoint.put(urlforRead2, endpointCache); + + + DocumentCollection documentCollection = new DocumentCollection(); + documentCollection.id("TestColl"); + documentCollection.resourceId("IXYFAOHEBPM="); + CollectionRoutingMap collectionRoutingMap = Mockito.mock(CollectionRoutingMap.class); + PartitionKeyRange range = new PartitionKeyRange("0", PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey, + PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey); + List partitionKeyRanges = new ArrayList<>(); + partitionKeyRanges.add(range); + Mockito.when(collectionRoutingMap.getOrderedPartitionKeyRanges()).thenReturn(partitionKeyRanges); + Mono collectionRoutingMapSingle = Mono.just(collectionRoutingMap); + Mockito.when(routingMapProvider.tryLookupAsync(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(collectionRoutingMapSingle); + + List ranges = new ArrayList<>(); + for (PartitionKeyRange partitionKeyRange : (List) collectionRoutingMap.getOrderedPartitionKeyRanges()) { + PartitionKeyRangeIdentity partitionKeyRangeIdentity = new PartitionKeyRangeIdentity(documentCollection.resourceId(), partitionKeyRange.id()); + ranges.add(partitionKeyRangeIdentity); + } + + Mono completable = Mono.fromCallable(new Callable() { + @Override + public Void call() throws Exception { + numberOfTaskCompleted.getAndIncrement(); + return null; + } + }); + Mockito.when(gatewayAddressCache.openAsync(documentCollection, ranges)).thenReturn(completable); + + globalAddressResolver.openAsync(documentCollection).block(); + assertThat(numberOfTaskCompleted.get()).isEqualTo(2); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicyTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicyTest.java new file mode 100644 index 0000000000000..4601b7df252e1 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/GoneAndRetryWithRetryPolicyTest.java @@ -0,0 +1,161 @@ +/* + * + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IRetryPolicy; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.directconnectivity.GoneAndRetryWithRetryPolicy; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This test file will cover various exception on GoneAndRetryWithRetryPolicy. + * + */ +public class GoneAndRetryWithRetryPolicyTest { + protected static final int TIMEOUT = 60000; + + /** + * Retry with GoneException , retried 4 times and verified the returned + * shouldRetryResult. ShouldRetryResult + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void shouldRetryWithGoneException() { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); + Mono singleShouldRetry = goneAndRetryWithRetryPolicy + .shouldRetry(new GoneException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(1); + assertThat(shouldRetryResult.backOffTime.getSeconds()).isEqualTo(0); + + singleShouldRetry = goneAndRetryWithRetryPolicy.shouldRetry(new GoneException()); + shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(2); + assertThat(shouldRetryResult.backOffTime.getSeconds()).isEqualTo(1); + + singleShouldRetry = goneAndRetryWithRetryPolicy.shouldRetry(new GoneException()); + shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(3); + assertThat(shouldRetryResult.backOffTime.getSeconds()).isEqualTo(2); + + singleShouldRetry = goneAndRetryWithRetryPolicy.shouldRetry(new GoneException()); + shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue3()).isEqualTo(4); + assertThat(shouldRetryResult.backOffTime.getSeconds()).isEqualTo(4); + + } + + /** + * Retry with PartitionIsMigratingException + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void shouldRetryWithPartitionIsMigratingException() { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); + Mono singleShouldRetry = goneAndRetryWithRetryPolicy + .shouldRetry(new PartitionIsMigratingException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(request.forceCollectionRoutingMapRefresh).isTrue(); + assertThat(shouldRetryResult.policyArg.getValue0()).isTrue(); + } + + /** + * Retry with InvalidPartitionException + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void shouldRetryWithInvalidPartitionException() { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); + Mono singleShouldRetry = goneAndRetryWithRetryPolicy + .shouldRetry(new InvalidPartitionException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(request.requestContext.quorumSelectedLSN).isEqualTo(-1); + assertThat(request.requestContext.resolvedPartitionKeyRange).isNull(); + assertThat(request.requestContext.globalCommittedSelectedLSN).isEqualTo(-1); + assertThat(shouldRetryResult.policyArg.getValue0()).isFalse(); + + goneAndRetryWithRetryPolicy.shouldRetry(new InvalidPartitionException()); + // It will retry max till 3 attempts + shouldRetryResult = goneAndRetryWithRetryPolicy.shouldRetry(new InvalidPartitionException()).block(); + assertThat(shouldRetryResult.shouldRetry).isFalse(); + CosmosClientException clientException = (CosmosClientException) shouldRetryResult.exception; + assertThat(clientException.statusCode()).isEqualTo(HttpConstants.StatusCodes.SERVICE_UNAVAILABLE); + + } + + /** + * Retry with PartitionKeyRangeIsSplittingException + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void shouldRetryWithPartitionKeyRangeIsSplittingException() { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); + Mono singleShouldRetry = goneAndRetryWithRetryPolicy + .shouldRetry(new PartitionKeyRangeIsSplittingException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isTrue(); + assertThat(request.forcePartitionKeyRangeRefresh).isTrue(); + assertThat(request.requestContext.resolvedPartitionKeyRange).isNull(); + assertThat(request.requestContext.quorumSelectedLSN).isEqualTo(-1); + assertThat(shouldRetryResult.policyArg.getValue0()).isFalse(); + + } + + /** + * No retry on bad request exception + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void shouldRetryWithGenericException() { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + GoneAndRetryWithRetryPolicy goneAndRetryWithRetryPolicy = new GoneAndRetryWithRetryPolicy(request, 30); + Mono singleShouldRetry = goneAndRetryWithRetryPolicy + .shouldRetry(new BadRequestException()); + IRetryPolicy.ShouldRetryResult shouldRetryResult = singleShouldRetry.block(); + assertThat(shouldRetryResult.shouldRetry).isFalse(); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientMockWrapper.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientMockWrapper.java new file mode 100644 index 0000000000000..2f19b24068f02 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpClientMockWrapper.java @@ -0,0 +1,181 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.WFConstants; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import org.mockito.Mockito; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +; + +public class HttpClientMockWrapper { + public static HttpClientBehaviourBuilder httpClientBehaviourBuilder() { + return new HttpClientBehaviourBuilder(); + } + + public static class HttpClientBehaviourBuilder { + private int status; + private String content; + private HttpHeaders httpHeaders = new HttpHeaders(); + private Exception networkFailure; + + public HttpClientBehaviourBuilder withNetworkFailure(Exception networkFailure) { + this.networkFailure = networkFailure; + return this; + } + + public HttpClientBehaviourBuilder withStatus(int status) { + this.status = status; + return this; + } + + public HttpClientBehaviourBuilder withHeaders(HttpHeaders httpHeaders) { + this.httpHeaders = httpHeaders; + return this; + } + + public HttpClientBehaviourBuilder withHeaders(String... pairs) { + if (pairs.length % 2 != 0) { + throw new IllegalArgumentException(); + } + + for(int i = 0; i < pairs.length/ 2; i++) { + this.httpHeaders.set(pairs[2*i], pairs[2*i +1]); + } + + return this; + } + + public HttpClientBehaviourBuilder withContent(String content) { + this.content = content; + return this; + } + + public HttpClientBehaviourBuilder withHeaderLSN(long lsn) { + this.httpHeaders.set(WFConstants.BackendHeaders.LSN, Long.toString(lsn)); + return this; + } + + public HttpClientBehaviourBuilder withHeaderPartitionKeyRangeId(String partitionKeyRangeId) { + this.httpHeaders.set(WFConstants.BackendHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId); + return this; + } + + public HttpClientBehaviourBuilder withHeaderSubStatusCode(int subStatusCode) { + this.httpHeaders.set(WFConstants.BackendHeaders.SUB_STATUS, Integer.toString(subStatusCode)); + return this; + } + + public HttpResponse asHttpResponse() { + if (this.networkFailure != null) { + return null; + } + + HttpResponse resp = Mockito.mock(HttpResponse.class); + Mockito.doReturn(this.status).when(resp).statusCode(); + Mockito.doReturn(Flux.just(ByteBufUtil.writeUtf8(ByteBufAllocator.DEFAULT, this.content))).when(resp).body(); + Mockito.doReturn(Mono.just(this.content)).when(resp).bodyAsString(StandardCharsets.UTF_8); + Mockito.doReturn(this.httpHeaders).when(resp).headers(); + return resp; + } + + public Exception asNetworkFailure() { + return this.networkFailure; + } + + @Override + public String toString() { + return "HttpClientBehaviourBuilder{" + + "status=" + status + + ", content='" + content + '\'' + + ", httpHeaders=" + httpHeaders + + ", networkFailure=" + networkFailure + + '}'; + } + } + + private final HttpClient httpClient; + private final List requests = Collections.synchronizedList(new ArrayList<>()); + + public HttpClientMockWrapper(long responseAfterMillis, HttpResponse httpResponse) { + this(responseAfterMillis, httpResponse, null); + } + + private static Mono httpResponseOrException(HttpResponse httpResponse, Exception e) { + assert ((httpResponse != null && e == null) || (httpResponse == null && e != null)); + return httpResponse != null ? Mono.just(httpResponse) : Mono.error(e); + } + + public HttpClientMockWrapper(long responseAfterMillis, Exception e) { + this(responseAfterMillis, null, e); + } + + public HttpClientMockWrapper(HttpResponse httpResponse) { + this(0, httpResponse); + } + + private HttpClientMockWrapper(long responseAfterMillis, final HttpResponse httpResponse, final Exception e) { + httpClient = Mockito.mock(HttpClient.class); + assert httpResponse == null || e == null; + + Mockito.doAnswer(invocationOnMock -> { + HttpRequest httpRequest = invocationOnMock.getArgumentAt(0, HttpRequest.class); + requests.add(httpRequest); + if (responseAfterMillis <= 0) { + return httpResponseOrException(httpResponse, e); + } else { + return Mono.delay(Duration.ofMillis(responseAfterMillis)).flatMap(t -> httpResponseOrException(httpResponse, e)); + } + }).when(httpClient).send(Mockito.any(HttpRequest.class)); + } + + public HttpClientMockWrapper(HttpClientBehaviourBuilder builder) { + this(0, builder.asHttpResponse(), builder.asNetworkFailure()); + } + + public HttpClientMockWrapper(Exception e) { + this(0, e); + } + + public HttpClient getClient() { + return httpClient; + } + + public List getCapturedInvocation() { + return requests; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClientTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClientTest.java new file mode 100644 index 0000000000000..517a3fca3fb41 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpTransportClientTest.java @@ -0,0 +1,653 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.ConflictException; +import com.azure.data.cosmos.ForbiddenException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.LockedException; +import com.azure.data.cosmos.MethodNotAllowedException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PreconditionFailedException; +import com.azure.data.cosmos.RequestEntityTooLargeException; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.RetryWithException; +import com.azure.data.cosmos.ServiceUnavailableException; +import com.azure.data.cosmos.UnauthorizedException; +import com.azure.data.cosmos.internal.directconnectivity.HttpTransportClient; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.UserAgentContainer; +import com.azure.data.cosmos.internal.directconnectivity.HttpTransportClient; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpClient; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpRequest; +import com.azure.data.cosmos.internal.http.HttpResponse; +import com.azure.data.cosmos.internal.FailureValidator; +import io.netty.channel.ConnectTimeoutException; +import io.reactivex.subscribers.TestSubscriber; +import org.assertj.core.api.Assertions; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +; + +/** + * Tests validating {@link HttpTransportClient} + */ +public class HttpTransportClientTest { + private final static Configs configs = new Configs(); + private final static int TIMEOUT = 1000; + + private final URI physicalAddress = URI.create( + "https://by4prdddc03-docdb-1.documents.azure.com:9056" + + "/apps/b76af614-5421-4318-4c9e-33056ff5a2bf/services/e7c8d429-c379-40c9-9486-65b89b70be2f" + + "/partitions/5f5b8766-3bdf-4713-b85a-a55ac2ccd62c/replicas/131828696163674404p/"); + + private final long lsn = 5; + private final String partitionKeyRangeId = "3"; + + @Test(groups = "unit") + public void getResourceFeedUri_Document() throws Exception { + RxDocumentServiceRequest req = RxDocumentServiceRequest.createFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document); + URI res = HttpTransportClient.getResourceFeedUri(req.getResourceType(), physicalAddress, req); + assertThat(res.toString()).isEqualTo(physicalAddress.toString() + HttpUtils.urlEncode("dbs/db/colls/col/docs")); + } + + @Test(groups = "unit") + public void getResourceFeedUri_Attachment() throws Exception { + RxDocumentServiceRequest req = RxDocumentServiceRequest.createFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Attachment); + URI res = HttpTransportClient.getResourceFeedUri(req.getResourceType(), physicalAddress, req); + assertThat(res.toString()).isEqualTo(physicalAddress.toString() + HttpUtils.urlEncode("dbs/db/colls/col/attachments")); + } + + @Test(groups = "unit") + public void getResourceFeedUri_Collection() throws Exception { + RxDocumentServiceRequest req = RxDocumentServiceRequest.createFromName( + OperationType.Create, "dbs/db", ResourceType.DocumentCollection); + URI res = HttpTransportClient.getResourceFeedUri(req.getResourceType(), physicalAddress, req); + assertThat(res.toString()).isEqualTo(physicalAddress.toString() + HttpUtils.urlEncode("dbs/db/colls")); + } + + @Test(groups = "unit") + public void getResourceFeedUri_Conflict() throws Exception { + RxDocumentServiceRequest req = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/dbs/db/colls/col", ResourceType.Conflict); + URI res = HttpTransportClient.getResourceFeedUri(req.getResourceType(), physicalAddress, req); + assertThat(res.toString()).isEqualTo(physicalAddress.toString() + HttpUtils.urlEncode("dbs/db/colls/col/conflicts")); + } + + @Test(groups = "unit") + public void getResourceFeedUri_Database() throws Exception { + RxDocumentServiceRequest req = RxDocumentServiceRequest.createFromName( + OperationType.Create, "/", ResourceType.Database); + URI res = HttpTransportClient.getResourceFeedUri(req.getResourceType(), physicalAddress, req); + assertThat(res.toString()).isEqualTo(physicalAddress.toString() + "dbs"); + } + + public static HttpTransportClient getHttpTransportClientUnderTest(int requestTimeout, + UserAgentContainer userAgent, + HttpClient httpClient) { + class HttpTransportClientUnderTest extends HttpTransportClient { + public HttpTransportClientUnderTest(int requestTimeout, UserAgentContainer userAgent) { + super(configs, requestTimeout, userAgent); + } + + @Override + HttpClient createHttpClient(int requestTimeout) { + return httpClient; + } + } + + return new HttpTransportClientUnderTest(requestTimeout, userAgent); + } + + @Test(groups = "unit") + public void validateDefaultHeaders() { + HttpResponse mockedResponse = new HttpClientMockWrapper.HttpClientBehaviourBuilder() + .withContent("").withStatus(200) + .withHeaders(new HttpHeaders()) + .asHttpResponse(); + HttpClientMockWrapper httpClientMockWrapper = new HttpClientMockWrapper(mockedResponse); + + UserAgentContainer userAgentContainer = new UserAgentContainer(); + userAgentContainer.setSuffix("i am suffix"); + + HttpTransportClient transportClient = getHttpTransportClientUnderTest(100, + userAgentContainer, + httpClientMockWrapper.getClient()); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document); + request.setContentBytes(new byte[0]); + + transportClient.invokeStoreAsync(physicalAddress, request).block(); + + assertThat(httpClientMockWrapper.getCapturedInvocation()).asList().hasSize(1); + HttpRequest httpRequest = httpClientMockWrapper.getCapturedInvocation().get(0); + + assertThat(httpRequest.headers().value(HttpConstants.HttpHeaders.USER_AGENT)).endsWith("i am suffix"); + assertThat(httpRequest.headers().value(HttpConstants.HttpHeaders.CACHE_CONTROL)).isEqualTo("no-cache"); + assertThat(httpRequest.headers().value(HttpConstants.HttpHeaders.ACCEPT)).isEqualTo("application/json"); + assertThat(httpRequest.headers().value(HttpConstants.HttpHeaders.VERSION)).isEqualTo(HttpConstants.Versions.CURRENT_VERSION); + + } + + @DataProvider(name = "fromMockedHttpResponseToExpectedDocumentClientException") + public Object[][] fromMockedHttpResponseToExpectedDocumentClientException() { + return new Object[][]{ + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(401) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(UnauthorizedException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(403) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(ForbiddenException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(404) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(NotFoundException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(404) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaders(HttpConstants.HttpHeaders.CONTENT_TYPE, "text/html"), + + FailureValidator.builder() + .instanceOf(GoneException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(400) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(BadRequestException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(405) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(MethodNotAllowedException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(409) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(ConflictException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(412) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(PreconditionFailedException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(412) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(PreconditionFailedException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(413) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(RequestEntityTooLargeException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(423) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(LockedException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(503) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(ServiceUnavailableException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(408) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(RequestTimeoutException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(449) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(RetryWithException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(429) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(RequestRateTooLargeException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(500) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId), + + FailureValidator.builder() + .instanceOf(InternalServerErrorException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(410) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaderSubStatusCode(HttpConstants.SubStatusCodes.NAME_CACHE_IS_STALE), + + FailureValidator.builder() + .instanceOf(InvalidPartitionException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(410) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaderSubStatusCode(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE), + + FailureValidator.builder() + .instanceOf(PartitionKeyRangeGoneException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(410) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaderSubStatusCode(HttpConstants.SubStatusCodes.COMPLETING_SPLIT), + + FailureValidator.builder() + .instanceOf(PartitionKeyRangeIsSplittingException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(410) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaderSubStatusCode(HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION), + + FailureValidator.builder() + .instanceOf(PartitionIsMigratingException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + { + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withContent("").withStatus(410) + .withHeaderLSN(lsn) + .withHeaderPartitionKeyRangeId(partitionKeyRangeId) + .withHeaderSubStatusCode(0), + + FailureValidator.builder() + .instanceOf(GoneException.class) + .resourceAddress("dbs/db/colls/col") + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + }, + }; + } + + /** + * Validates the error handling behaviour of HttpTransportClient for https status codes >= 400 + * @param mockedResponseBuilder + * @param failureValidatorBuilder + */ + @Test(groups = "unit", dataProvider = "fromMockedHttpResponseToExpectedDocumentClientException") + public void failuresWithHttpStatusCodes(HttpClientMockWrapper.HttpClientBehaviourBuilder mockedResponseBuilder, + FailureValidator.Builder failureValidatorBuilder) { + HttpClientMockWrapper httpClientMockWrapper = new HttpClientMockWrapper(mockedResponseBuilder); + UserAgentContainer userAgentContainer = new UserAgentContainer(); + HttpTransportClient transportClient = getHttpTransportClientUnderTest( + 100, + userAgentContainer, + httpClientMockWrapper.getClient()); + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document); + request.setContentBytes(new byte[0]); + + Mono storeResp = transportClient.invokeStoreAsync( + physicalAddress, + request); + + validateFailure(storeResp, failureValidatorBuilder.build()); + } + + @DataProvider(name = "fromMockedNetworkFailureToExpectedDocumentClientException") + public Object[][] fromMockedNetworkFailureToExpectedDocumentClientException() { + return new Object[][]{ + // create request, retriable network exception + { + createRequestFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new UnknownHostException()), + + FailureValidator.builder() + .instanceOf(GoneException.class) + }, + + // create request, retriable network exception + { + createRequestFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new UnknownHostException()), + + FailureValidator.builder() + .instanceOf(GoneException.class) + }, + + // create request, retriable network exception + { + createRequestFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new ConnectTimeoutException()), + + FailureValidator.builder() + .instanceOf(GoneException.class) + }, + + // read request, retriable network exception + { + createRequestFromName( + OperationType.Read, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new ConnectTimeoutException()), + + FailureValidator.builder() + .instanceOf(GoneException.class) + }, + + // create request, non-retriable network exception + { + createRequestFromName( + OperationType.Create, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new RuntimeException()), + + FailureValidator.builder() + .instanceOf(ServiceUnavailableException.class) + }, + + // read request, non-retriable network exception + { + createRequestFromName( + OperationType.Read, "dbs/db/colls/col", ResourceType.Document), + + HttpClientMockWrapper. + httpClientBehaviourBuilder() + .withNetworkFailure(new RuntimeException()), + + FailureValidator.builder() + .instanceOf(GoneException.class) + }, + }; + } + + /** + * Validates the error handling behaviour of HttpTransportClient for network failures from which http status codes + * cannot be derived. For example Socket Connection failure. + * @param request + * @param mockedResponseBuilder + * @param failureValidatorBuilder + */ + @Test(groups = "unit", dataProvider = "fromMockedNetworkFailureToExpectedDocumentClientException") + public void networkFailures(RxDocumentServiceRequest request, + HttpClientMockWrapper.HttpClientBehaviourBuilder mockedResponseBuilder, + FailureValidator.Builder failureValidatorBuilder) { + HttpClientMockWrapper httpClientMockWrapper = new HttpClientMockWrapper(mockedResponseBuilder); + UserAgentContainer userAgentContainer = new UserAgentContainer(); + HttpTransportClient transportClient = getHttpTransportClientUnderTest( + 100, + userAgentContainer, + httpClientMockWrapper.getClient()); + + Mono storeResp = transportClient.invokeStoreAsync( + physicalAddress, + request); + + validateFailure(storeResp, failureValidatorBuilder.build()); + } + + private static RxDocumentServiceRequest createRequestFromName( + OperationType operationType, + String resourceFullName, + ResourceType resourceType) { + return createRequestFromName(operationType, resourceFullName, resourceType, new byte[0]); + } + + private static RxDocumentServiceRequest createRequestFromName( + OperationType operationType, + String resourceFullName, + ResourceType resourceType, + byte[] content) { + RxDocumentServiceRequest req = RxDocumentServiceRequest.create( + operationType, + resourceType, + resourceFullName, + new HashMap<>()); + + req.setContentBytes(content); + return req; + } + + public void validateSuccess(Mono single, StoreResponseValidator validator) { + validateSuccess(single, validator, TIMEOUT); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public void validateFailure(Mono single, + FailureValidator validator) { + validateFailure(single, validator, TIMEOUT); + } + + public static void validateFailure(Mono single, + FailureValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + Assertions.assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtilsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtilsTest.java new file mode 100644 index 0000000000000..9a3e804c3f799 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/HttpUtilsTest.java @@ -0,0 +1,64 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2019 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.directconnectivity.HttpUtils; +import com.azure.data.cosmos.internal.http.HttpHeaders; +import com.azure.data.cosmos.internal.http.HttpResponse; +import org.mockito.Mockito; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HttpUtilsTest { + + private static final String OWNER_FULL_NAME_VALUE = "dbs/RxJava.SDKTest.SharedDatabase_20190304T121302_iZc/colls/+%20-_,:.%7C~b2d67001-9000-454e-a140-abceb1756c48%20+-_,:.%7C~"; + + @Test(groups = { "unit" }) + public void verifyConversionOfHttpResponseHeadersToMap() { + HttpHeaders headersMap = new HttpHeaders(1); + headersMap.set(HttpConstants.HttpHeaders.OWNER_FULL_NAME, OWNER_FULL_NAME_VALUE); + + HttpResponse httpResponse = Mockito.mock(HttpResponse.class); + Mockito.when(httpResponse.headers()).thenReturn(headersMap); + HttpHeaders httpResponseHeaders = httpResponse.headers(); + Set> resultHeadersSet = HttpUtils.asMap(httpResponseHeaders).entrySet(); + + assertThat(resultHeadersSet.size()).isEqualTo(1); + Entry entry = resultHeadersSet.iterator().next(); + assertThat(entry.getKey()).isEqualTo(HttpConstants.HttpHeaders.OWNER_FULL_NAME); + assertThat(entry.getValue()).isEqualTo(HttpUtils.urlDecode(OWNER_FULL_NAME_VALUE)); + + List> resultHeadersList = HttpUtils.unescape(httpResponseHeaders.toMap().entrySet()); + assertThat(resultHeadersList.size()).isEqualTo(1); + entry = resultHeadersSet.iterator().next(); + assertThat(entry.getKey()).isEqualTo(HttpConstants.HttpHeaders.OWNER_FULL_NAME); + assertThat(entry.getValue()).isEqualTo(HttpUtils.urlDecode(OWNER_FULL_NAME_VALUE)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MultiStoreResultValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MultiStoreResultValidator.java new file mode 100644 index 0000000000000..fe1652ca17eaf --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MultiStoreResultValidator.java @@ -0,0 +1,176 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.FailureValidator; +import com.google.common.base.Predicates; +import org.apache.commons.lang3.mutable.MutableObject; +import org.assertj.core.description.Description; +import org.assertj.core.description.TextDescription; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Predicate; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.fail; + +/** + * this is meant to be used when there reading multiple replicas for the same thing + */ +public interface MultiStoreResultValidator { + + static Builder create() { + return new Builder(); + } + + void validate(List storeResults); + + class Builder { + private List validators = new ArrayList<>(); + + public MultiStoreResultValidator build() { + return new MultiStoreResultValidator() { + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void validate(List storeResults) { + for (MultiStoreResultValidator validator : validators) { + validator.validate(storeResults); + } + } + }; + } + + public Builder validateEachWith(StoreResultValidator storeResultValidator) { + validators.add(new MultiStoreResultValidator() { + + @Override + public void validate(List storeResults) { + for(StoreResult srr: storeResults) { + storeResultValidator.validate(srr); + } + } + }); + return this; + } + + public Builder validateEachWith(StoreResponseValidator storeResponseValidator) { + validators.add(new MultiStoreResultValidator() { + + @Override + public void validate(List storeResults) { + for(StoreResult srr: storeResults) { + try { + storeResponseValidator.validate(srr.toResponse()); + } catch (CosmosClientException e) { + fail(e.getMessage()); + } + } + } + }); + return this; + } + + public Builder withMinimumLSN(long minimumLSN) { + this.validateEachWith(StoreResultValidator.create().withMinLSN(minimumLSN).build()); + return this; + } + + public Builder withAggregate(BiFunction aggregator, + T initialValue, + Predicate finalValuePredicate, + Description description) { + MutableObject total = new MutableObject<>(initialValue); + validators.add(new MultiStoreResultValidator() { + + @Override + public void validate(List storeResults) { + for(StoreResult srr: storeResults) { + total.setValue(aggregator.apply(srr, total.getValue())); + } + + assertThat(finalValuePredicate.test(total.getValue())) + .describedAs(Description.mostRelevantDescription(description, + String.format("actual value %s.", + total.getValue().toString()))) + .isTrue(); + } + }); + return this; + } + + public Builder withTotalRequestCharge(double totalExpectedRC) { + this.withAggregate((srr, v) -> srr.requestCharge + v.doubleValue(), + 0d, + Predicates.equalTo(totalExpectedRC), + new TextDescription("total request charge is expected to be %f", totalExpectedRC)); + return this; + } + + public Builder withNonZeroRequestCharge() { + + this.withAggregate((srr, v) -> srr.requestCharge + v.doubleValue(), + 0d, + aDouble -> aDouble > 0, + new TextDescription("total request charge expected to be greater than 0")); + return this; + } + + public Builder validateEachWith(FailureValidator failureValidator) { + validators.add(new MultiStoreResultValidator() { + + @Override + public void validate(List storeResults) { + for(StoreResult srr: storeResults) { + try { + failureValidator.validate(srr.getException()); + } catch (CosmosClientException e) { + fail(e.getMessage()); + } + } + } + }); + return this; + } + + public Builder noFailure() { + this.validateEachWith(StoreResultValidator.create().isValid().noException().build()); + return this; + } + + public Builder withSize(int expectedNumber) { + validators.add(new MultiStoreResultValidator() { + + @Override + public void validate(List storeResults) { + assertThat(storeResults).hasSize(expectedNumber); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MurmurHash3_32Test.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MurmurHash3_32Test.java new file mode 100644 index 0000000000000..05cd764baa415 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/MurmurHash3_32Test.java @@ -0,0 +1,115 @@ +/* + * + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.routing.MurmurHash3_32; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import org.apache.commons.lang3.RandomUtils; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * validates {@link MurmurHash3_32} against Google's murmur3_32 implementation. + */ +public class MurmurHash3_32Test { + + private MurmurHash3_32 murmurHash3_32; + + @BeforeClass(groups = "unit") + public void setup() { + murmurHash3_32 = new MurmurHash3_32(); + } + + @Test(groups = "unit") + public void murmurHash3_32_EmptyByteArray() { + byte[] byteArray = new byte[0]; + int actualHash = murmurHash3_32.hash(byteArray, byteArray.length, 0); + + HashFunction googleMurmur3_32 = Hashing.murmur3_32(0); + int expectedHash = googleMurmur3_32.hashBytes(byteArray).asInt(); + + assertThat(actualHash).isEqualTo(expectedHash); + } + + @Test(groups = "unit") + public void murmurHash3_32_String() { + byte[] byteArray = new String("test").getBytes(Charset.forName("UTF-8")); + int actualHash = murmurHash3_32.hash(byteArray, byteArray.length, 0); + + HashFunction googleMurmur3_32 = Hashing.murmur3_32(0); + int expectedHash = googleMurmur3_32.hashBytes(byteArray).asInt(); + + assertThat(actualHash).isEqualTo(expectedHash); + } + + @Test(groups = "unit") + public void murmurHash3_32_NonLatin() throws UnsupportedEncodingException { + String nonLatin = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюя"; + for(int i = 0; i < nonLatin.length() + 1; i++) { + byte[] byteArray = nonLatin.substring(0, i).getBytes("UTF-8"); + int actualHash = murmurHash3_32.hash(byteArray, byteArray.length, 0); + + HashFunction googleMurmur3_32 = Hashing.murmur3_32(0); + int expectedHash = googleMurmur3_32.hashBytes(byteArray).asInt(); + + assertThat(actualHash).isEqualTo(expectedHash); + } + } + + @Test(groups = "unit") + public void murmurHash3_32_ZeroByteArray() { + byte[] byteArray = new byte[3]; + int actualHash = murmurHash3_32.hash(byteArray, byteArray.length, 0); + + HashFunction googleMurmur3_32 = Hashing.murmur3_32(0); + int expectedHash = googleMurmur3_32.hashBytes(byteArray).asInt(); + + assertThat(actualHash).isEqualTo(expectedHash); + } + + @Test(groups = "unit") + public void murmurHash3_32_RandomBytesOfAllSizes() { + for(int i = 0; i < 1000; i++) { + byte[] byteArray = randomBytes(i); + + int actualHash = murmurHash3_32.hash(byteArray, byteArray.length, 0); + + HashFunction googleMurmur3_32 = Hashing.murmur3_32(0); + int expectedHash = googleMurmur3_32.hashBytes(byteArray).asInt(); + + assertThat(actualHash).isEqualTo(expectedHash); + } + } + + private byte[] randomBytes(int count) { + return RandomUtils.nextBytes(count); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyInternalTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyInternalTest.java new file mode 100644 index 0000000000000..b93d46d986bde --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyInternalTest.java @@ -0,0 +1,473 @@ +/* + * + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CommonsBridgeInternal; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.PartitionKind; +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternal; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalUtils; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.function.BiFunction; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.fail; + +public class PartitionKeyInternalTest { + + /** + * Tests serialization of empty partition key. + */ + @Test(groups="unit") + public void emptyPartitionKey() { + String json = "[]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey).isEqualTo(PartitionKeyInternal.getEmpty()); + assertThat(partitionKey.toJson()).isEqualTo("[]"); + } + + /** + * Tests serialization of various types. + */ + @Test(groups="unit") + public void variousTypes() { + String json = "[\"aa\", null, true, false, {}, 5, 5.5]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey).isEqualTo( + PartitionKeyInternal.fromObjectArray( + Lists.newArrayList(new Object[]{"aa", null, true, false, Undefined.Value(), 5, 5.5}), true)); + + assertThat(partitionKey.toJson()).isEqualTo("[\"aa\",null,true,false,{},5.0,5.5]"); + } + + /** + * Tests deserialization of empty string + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void deserializeEmptyString() { + PartitionKeyInternal.fromJsonString(""); + } + + /** + * Tests deserialization of null + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void deserializeNull() { + PartitionKeyInternal.fromJsonString(null); + } + + /** + * Tests deserialization of invalid partition key + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void invalidString() { + PartitionKeyInternal.fromJsonString("[aa]"); + } + + + /** + * Tests deserialization of invalid partition key + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void invalidNumber() { + PartitionKeyInternal.fromJsonString("[1.a]"); + } + + /** + * Tests deserialization of invalid partition key + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void missingBraces() { + PartitionKeyInternal.fromJsonString("[{]"); + } + + /** + * Missing Value + */ + @Test(groups = "unit") + public void missingValue() { + try { + PartitionKeyInternal.fromJsonString(""); + fail("should throw"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).isEqualTo( + String.format( + RMResources.UnableToDeserializePartitionKeyValue, "")); + } + } + + /** + * Tests serialization of infinity value. + */ + @Test(groups = "unit") + public void maxValue() { + String json = "\"Infinity\""; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey).isEqualTo(PartitionKeyInternal.ExclusiveMaximum); + } + + /** + * Tests serialization of minimum value. + */ + @Test(groups = "unit") + public void minValue() { + String json = "[]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey).isEqualTo(PartitionKeyInternal.InclusiveMinimum); + } + + /** + * Tests serialization of undefined value. + */ + @Test(groups = "unit") + public void undefinedValue() { + String json = "[]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey).isEqualTo(PartitionKeyInternal.Empty); + } + + /** + * Tests JsonConvert.DefaultSettings that could cause indentation. + */ + @Test(groups="unit") + public void jsonConvertDefaultSettings() { + String json = "[123.0]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey.toJson()).isEqualTo(json); + } + + /** + * Tests unicode characters in partition key + */ + @Test(groups="unit") + public void unicodeCharacters() { + String json = "[\"电脑\"]"; + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(json); + assertThat(partitionKey.toJson()).isEqualTo("[\"\u7535\u8111\"]"); + } + + /** + * Tests partition key value comparisons. + */ + @Test(groups="unit") + public void comparison() { + verifyComparison("[]", "[]", 0); + verifyComparison("[]", "[{}]", -1); + verifyComparison("[]", "[false]", -1); + verifyComparison("[]", "[true]", -1); + verifyComparison("[]", "[null]", -1); + verifyComparison("[]", "[2]", -1); + verifyComparison("[]", "[\"aa\"]", -1); + verifyComparison("[]", "\"Infinity\"", -1); + + verifyComparison("[{}]", "[]", 1); + verifyComparison("[{}]", "[{}]", 0); + verifyComparison("[{}]", "[false]", -1); + verifyComparison("[{}]", "[true]", -1); + verifyComparison("[{}]", "[null]", -1); + verifyComparison("[{}]", "[2]", -1); + verifyComparison("[{}]", "[\"aa\"]", -1); + verifyComparison("[{}]", "\"Infinity\"", -1); + + verifyComparison("[false]", "[]", 1); + verifyComparison("[false]", "[{}]", 1); + verifyComparison("[false]", "[null]", 1); + verifyComparison("[false]", "[false]", 0); + verifyComparison("[false]", "[true]", -1); + verifyComparison("[false]", "[2]", -1); + verifyComparison("[false]", "[\"aa\"]", -1); + verifyComparison("[false]", "\"Infinity\"", -1); + + verifyComparison("[true]", "[]", 1); + verifyComparison("[true]", "[{}]", 1); + verifyComparison("[true]", "[null]", 1); + verifyComparison("[true]", "[false]", 1); + verifyComparison("[true]", "[true]", 0); + verifyComparison("[true]", "[2]", -1); + verifyComparison("[true]", "[\"aa\"]", -1); + verifyComparison("[true]", "\"Infinity\"", -1); + + verifyComparison("[null]", "[]", 1); + verifyComparison("[null]", "[{}]", 1); + verifyComparison("[null]", "[null]", 0); + verifyComparison("[null]", "[false]", -1); + verifyComparison("[null]", "[true]", -1); + verifyComparison("[null]", "[2]", -1); + verifyComparison("[null]", "[\"aa\"]", -1); + verifyComparison("[null]", "\"Infinity\"", -1); + + verifyComparison("[2]", "[]", 1); + verifyComparison("[2]", "[{}]", 1); + verifyComparison("[2]", "[null]", 1); + verifyComparison("[2]", "[false]", 1); + verifyComparison("[2]", "[true]", 1); + verifyComparison("[1]", "[2]", -1); + verifyComparison("[2]", "[2]", 0); + verifyComparison("[3]", "[2]", 1); + verifyComparison("[2.1234344]", "[2]", 1); + verifyComparison("[2]", "[\"aa\"]", -1); + verifyComparison("[2]", "\"Infinity\"", -1); + + verifyComparison("[\"aa\"]", "[]", 1); + verifyComparison("[\"aa\"]", "[{}]", 1); + verifyComparison("[\"aa\"]", "[null]", 1); + verifyComparison("[\"aa\"]", "[false]", 1); + verifyComparison("[\"aa\"]", "[true]", 1); + verifyComparison("[\"aa\"]", "[2]", 1); + verifyComparison("[\"\"]", "[\"aa\"]", -1); + verifyComparison("[\"aa\"]", "[\"aa\"]", 0); + verifyComparison("[\"b\"]", "[\"aa\"]", 1); + verifyComparison("[\"aa\"]", "\"Infinity\"", -1); + + verifyComparison("\"Infinity\"", "[]", 1); + verifyComparison("\"Infinity\"", "[{}]", 1); + verifyComparison("\"Infinity\"", "[null]", 1); + verifyComparison("\"Infinity\"", "[false]", 1); + verifyComparison("\"Infinity\"", "[true]", 1); + verifyComparison("\"Infinity\"", "[2]", 1); + verifyComparison("\"Infinity\"", "[\"aa\"]", 1); + verifyComparison("\"Infinity\"", "\"Infinity\"", 0); + } + + /** + * Tests that invalid partition key value will throw an exception. + */ + @Test(groups = "unit", expectedExceptions = IllegalArgumentException.class) + public void invalidPartitionKeyValue() { + PartitionKeyInternal.fromObjectArray( + Lists.newArrayList(new Object[]{2, true, new StringBuilder()}), true); + } + + /** + * Tests {@link PartitionKeyInternal#contains(PartitionKeyInternal)} method. + */ + @Test(groups="unit") + public void contains() { + BiFunction verifyContains = (parentPartitionKey, childPartitionKey) -> + PartitionKeyInternal.fromJsonString(parentPartitionKey) + .contains(PartitionKeyInternal.fromJsonString(childPartitionKey)); + + assertThat(verifyContains.apply("[]", "[]")).isTrue(); + assertThat(verifyContains.apply("[]", "[{}]")).isTrue(); + assertThat(verifyContains.apply("[]", "[null]")).isTrue(); + assertThat(verifyContains.apply("[]", "[true]")).isTrue(); + assertThat(verifyContains.apply("[]", "[false]")).isTrue(); + assertThat(verifyContains.apply("[]", "[2]")).isTrue(); + assertThat(verifyContains.apply("[]", "[\"fdfd\"]")).isTrue(); + + assertThat(verifyContains.apply("[2]", "[]")).isFalse(); + assertThat(verifyContains.apply("[2]", "[2]")).isTrue(); + assertThat(verifyContains.apply("[2]", "[2, \"USA\"]")).isTrue(); + assertThat(verifyContains.apply("[1]", "[2, \"USA\"]")).isFalse(); + } + + @Test(groups="unit") + public void invalidPartitionKeyValueNonStrict() { + assertThat(PartitionKeyInternal.fromObjectArray(new Object[]{2, true, Undefined.Value()}, true)) + .isEqualTo( + PartitionKeyInternal.fromObjectArray(new Object[]{2, true, new StringBuilder()}, false)); + } + + /** + * Tests constructing effective partition key value. + */ + @Test(groups="unit") + public void hashEffectivePartitionKey() { + + assertThat(PartitionKeyInternalHelper.getEffectivePartitionKeyString(PartitionKeyInternal.InclusiveMinimum, new PartitionKeyDefinition())) + .isEqualTo(PartitionKeyInternalHelper.MinimumInclusiveEffectivePartitionKey); + + assertThat( + PartitionKeyInternalHelper.getEffectivePartitionKeyString(PartitionKeyInternal.ExclusiveMaximum, new PartitionKeyDefinition())) + .isEqualTo(PartitionKeyInternalHelper.MaximumExclusiveEffectivePartitionKey); + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.paths(Lists.newArrayList("/A", "/B", "/C", "/E", "/F", "/G")); + + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromObjectArray( + new Object[]{2, true, false, null, Undefined.Value(), "Привет!"}, true); + String effectivePartitionKey = PartitionKeyInternalHelper.getEffectivePartitionKeyString(partitionKey, partitionKeyDefinition); + + assertThat(effectivePartitionKey).isEqualTo("05C1D19581B37C05C0000302010008D1A0D281D1B9D1B3D1B6D2832200"); + } + + @DataProvider(name = "v2ParamProvider") + public Object[][] v2ParamProvider() { + return new Object[][] { + {"[5.0]", "19C08621B135968252FB34B4CF66F811"}, + { "[5.12312419050912359123]", "0EF2E2D82460884AF0F6440BE4F726A8"}, + {"[\"redmond\"]", "22E342F38A486A088463DFF7838A5963"}, + {"[true]", "0E711127C5B5A8E4726AC6DD306A3E59"}, + {"[false]", "2FE1BE91E90A3439635E0E9E37361EF2"}, + {"[]", ""}, + {"[null]", "378867E4430E67857ACE5C908374FE16"}, + {"[{}]", "11622DAA78F835834610ABE56EFF5CB5"}, + {"[5.0, \"redmond\", true, null]", "3032DECBE2AB1768D8E0AEDEA35881DF"}, + {"[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"]", + "36375D21568760E891C9CB7002D5E059"}, + }; + } + + /** + * Tests binary encoding of partition key + */ + @Test(groups="unit", dataProvider = "v2ParamProvider") + public void partitionKeyBinaryEncodingV2(String partitionKeyRangeJson, String expectedHexEncoding) { + validateEffectivePartitionKeyV2(partitionKeyRangeJson, expectedHexEncoding); + } + + /** + * Tests that effective partition key produced by us and the backend is the same. + */ + @Test(groups="unit") + public void managedNativeCompatibility() { + PartitionKeyInternal partitionKey = + PartitionKeyInternal.fromJsonString("[\"по-русски\",null,true,false,{},5.5]"); + + PartitionKeyDefinition pkDefinition = new PartitionKeyDefinition(); + pkDefinition.paths(ImmutableList.of("/field1", "/field2", "/field3", "/field4", "/field5", "/field6")); + + String effectivePartitionKey = PartitionKeyInternalHelper.getEffectivePartitionKeyString(partitionKey, pkDefinition); + assertThat("05C1D39FA55F0408D1C0D1BF2ED281D284D282D282D1BBD1B9000103020005C016").isEqualTo(effectivePartitionKey); + + String latin = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; + String nonLatin = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюяабвгдеёжзийклмнопрстуфхцчшщъыьэюя"; + + verifyEffectivePartitionKeyEncoding(latin, 99, "05C19B2DC38FC00862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F7071727374757600", false); + verifyEffectivePartitionKeyEncoding(latin, 99, "072D8FA3228DD2A6C0A7129C845700E6", true); + + verifyEffectivePartitionKeyEncoding(latin, 100, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 100, "023D5F0B62EBEF22A43564F267193B4D", true); + + verifyEffectivePartitionKeyEncoding(latin, 101, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 101, "357D83181DB32D35F58CDA3C9F2E0742", true); + + verifyEffectivePartitionKeyEncoding(latin, 102, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 102, "12B320F72959AB449FD8E090C6B23B88", true); + + verifyEffectivePartitionKeyEncoding(latin, 103, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 103, "25FD21A31C69A8C8AD994F7FAC2B2B9F", true); + + verifyEffectivePartitionKeyEncoding(latin, 104, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 104, "1DC6FB1CF6E1228C506AA6C8735023C4", true); + + verifyEffectivePartitionKeyEncoding(latin, 105, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 105, "308E1E7870956CE5D9BDAD01200E09BD", true); + + verifyEffectivePartitionKeyEncoding(latin, 106, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 106, "362E21ABDEA7179DBDF7BF549DD8303B", true); + + verifyEffectivePartitionKeyEncoding(latin, 107, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 107, "1EBE932ECEFA4F53CE339D31B6BF53FD", true); + + verifyEffectivePartitionKeyEncoding(latin, 108, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 108, "3BFA3A6E9CBABA0EF756AEDEC66B1B3C", true); + + verifyEffectivePartitionKeyEncoding(latin, 109, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 109, "2880BF78DE0CE2CD1B0120EDA22601C4", true); + + verifyEffectivePartitionKeyEncoding(latin, 110, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 110, "1F3577D1D9CA7FC56100AED11F4DC646", true); + + verifyEffectivePartitionKeyEncoding(latin, 111, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 111, "205A9EB61F3B063E61C6ED655C9220E6", true); + + verifyEffectivePartitionKeyEncoding(latin, 112, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 112, "1152A43F1A852AFDDD4518C9CDD48616", true); + + verifyEffectivePartitionKeyEncoding(latin, 113, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 113, "38E2EB2EF54012B5CA40CDA34F1C7736", true); + + verifyEffectivePartitionKeyEncoding(latin, 114, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 114, "19BCC416843B9085DBBC18E8C7C80D72", true); + + verifyEffectivePartitionKeyEncoding(latin, 115, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 115, "03F1BB89FD8E9747B047281E80FA2E84", true); + + verifyEffectivePartitionKeyEncoding(latin, 116, "05C1DD5D8149640862636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767778797A7B62636465666768696A6B6C6D6E6F707172737475767700", false); + verifyEffectivePartitionKeyEncoding(latin, 116, "2BA0757B833F3922A3CBBB6DDA3803B4", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 49, "05C1C1BD37FE08D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BF00", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 49, "3742C1AF65AFA809282539F4BCDF2F6F", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 50, "05C1B339EF472008D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C000", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 50, "399CF1F141E066E09CC7557EA7F0977A", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 51, "05C1EB1F29DBFA08D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D2", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 51, "2D63C2F5FDAC6EFE5660CD509A723A90", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 99, "05C1E72F79C71608D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D2", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 99, "1E9836D9BCB67FDB2B5C984BD40AFAF9", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 100, "05C1E3653D9F3E08D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D2", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 100, "16102F19448867537E51BB4377962AF9", true); + + verifyEffectivePartitionKeyEncoding(nonLatin, 101, "05C1E3653D9F3E08D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D281D282D283D284D285D286D287D288D289D28AD28BD28CD28DD28ED28FD290D1B1D1B2D1B3D1B4D1B5D1B6D292D1B7D1B8D1B9D1BAD1BBD1BCD1BDD1BED1BFD1C0D2", false); + verifyEffectivePartitionKeyEncoding(nonLatin, 101, "0B6D25D07748AB9CA0F523D4BAD146C8", true); + } + + private static void validateEffectivePartitionKeyV2(String partitionKeyRangeJson, String expectedHexEncoding) { + PartitionKeyInternal partitionKey = PartitionKeyInternal.fromJsonString(partitionKeyRangeJson); + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + partitionKeyDefinition.kind(PartitionKind.HASH); + CommonsBridgeInternal.setV2(partitionKeyDefinition); + ArrayList paths = new ArrayList(); + for (int i = 0; i < partitionKey.getComponents().size(); i++) { + paths.add("/path" + i); + } + + if (paths.size() > 0) { + partitionKeyDefinition.paths(paths); + } + + String hexEncodedEffectivePartitionKey = PartitionKeyInternalHelper.getEffectivePartitionKeyString(partitionKey, partitionKeyDefinition); + assertThat(hexEncodedEffectivePartitionKey).isEqualTo(expectedHexEncoding); + } + + private void verifyComparison(String leftKey, String rightKey, int result) { + assertThat(PartitionKeyInternal.fromJsonString(leftKey). + compareTo(PartitionKeyInternal.fromJsonString(rightKey))).isEqualTo(result); + } + + private static void verifyEffectivePartitionKeyEncoding(String buffer, int length, String expectedValue, boolean v2) { + PartitionKeyDefinition pkDefinition = new PartitionKeyDefinition(); + pkDefinition.paths(ImmutableList.of("/field1")); + if (v2) { + CommonsBridgeInternal.setV2(pkDefinition); + } + + PartitionKeyInternal pk = PartitionKeyInternalUtils.createPartitionKeyInternal(buffer.substring(0, length)); + assertThat(PartitionKeyInternalHelper.getEffectivePartitionKeyString(pk, pkDefinition)).isEqualTo(expectedValue); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyTest.java new file mode 100644 index 0000000000000..d793868d99213 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionKeyTest.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.Undefined; +import com.azure.data.cosmos.internal.RMResources; +import com.azure.data.cosmos.internal.routing.PartitionKeyInternalHelper; +import com.google.common.collect.ImmutableList; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.fail; + +public class PartitionKeyTest { + + @DataProvider(name = "paramProvider") + public Object[][] paramProvider() { + return new Object[][] { + { Undefined.Value(), "[{}]" }, + { null, "[null]"}, + { false, "[false]"}, + { true, "[true]"}, + { 123.456, "[123.456]"}, + { 5, "[5.0]"}, + { "PartitionKeyValue", "[\"PartitionKeyValue\"]"}, + }; + } + + /** + * Simple test for @{@link PartitionKey}. + */ + @Test(groups = "unit", dataProvider = "paramProvider") + public void partitionKey(Object partitionKey, String partitionKeyAsJson) { + assertThat(new PartitionKey(partitionKey).toString()).isEqualTo(partitionKeyAsJson); + } + + /** + * Test equals override for @{@link PartitionKey} + */ + @Test(groups = "unit", dataProvider = "paramProvider") + public void partitionKeyCompare(Object partitionKey, String partitionKeyAsJson) { + assertThat(new PartitionKey(partitionKey)).isEqualTo(PartitionKey.fromJsonString(partitionKeyAsJson)); + } + + /** + * too few partition key values. + */ + @Test(groups = "unit") + public void tooFewPartitionKeyComponents() { + PartitionKeyDefinition pkd = new PartitionKeyDefinition(); + pkd.paths(ImmutableList.of("/pk1", "/pk2")); + PartitionKey pk = PartitionKey.fromJsonString("[\"PartitionKeyValue\"]"); + + try { + PartitionKeyInternalHelper.getEffectivePartitionKeyString(pk.getInternalPartitionKey(), pkd); + fail("should throw"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).isEqualTo(RMResources.TooFewPartitionKeyComponents); + } + } + + /** + * too many partition key values. + */ + @Test(groups = "unit") + public void tooManyPartitionKeyComponents() { + PartitionKeyDefinition pkd = new PartitionKeyDefinition(); + pkd.paths(ImmutableList.of("/pk1")); + PartitionKey pk = PartitionKey.fromJsonString("[true, false]"); + + try { + PartitionKeyInternalHelper.getEffectivePartitionKeyString(pk.getInternalPartitionKey(), pkd); + fail("should throw"); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).isEqualTo(RMResources.TooManyPartitionKeyComponents); + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionReplicasAddressesValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionReplicasAddressesValidator.java new file mode 100644 index 0000000000000..9a7e053035fb7 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/PartitionReplicasAddressesValidator.java @@ -0,0 +1,162 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.Address; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.directconnectivity.Address; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This is a helper class for validating partition replicas' addresses for tests. + */ +public interface PartitionReplicasAddressesValidator { + + int MAX_REPLICA_SIZE = 4; + + void validate(Collection
    addresses); + + class Builder { + private List validators = new ArrayList<>(); + + public PartitionReplicasAddressesValidator build() { + return new PartitionReplicasAddressesValidator() { + + public void validate(Collection
    addresses) { + for (PartitionReplicasAddressesValidator validator : validators) { + validator.validate(addresses); + } + } + }; + } + + public Builder size(final int expectedCount) { + + validators.add(new PartitionReplicasAddressesValidator() { + @Override + public void validate(Collection
    addresses) { + assertThat(addresses).hasSize(expectedCount); + } + }); + return this; + } + + public Builder forEach(AddressValidator validator) { + + validators.add(new PartitionReplicasAddressesValidator() { + @Override + public void validate(Collection
    addresses) { + + for (Address address : addresses) { + validator.validate(address); + } + + } + }); + return this; + } + + public Builder httpsProtocol() { + this.forEach(new AddressValidator.Builder().httpsProtocol().build()); + return this; + } + + public Builder withProtocol(Protocol protocol) { + this.forEach(new AddressValidator.Builder().protocol(protocol).build()); + return this; + } + + public Builder replicasOfPartition(String partitionKeyRangeId) { + validators.add(new PartitionReplicasAddressesValidator() { + @Override + public void validate(Collection
    addresses) { + + // if running against prod due to upgrade etc, we may have occasionally 3 or 4 replicas. + assertThat(addresses).size().isGreaterThanOrEqualTo(MAX_REPLICA_SIZE - 1).isLessThanOrEqualTo(MAX_REPLICA_SIZE); + assertThat(addresses.stream().filter(a -> a.IsPrimary()).count()).isEqualTo(1); + + Address a = addresses.iterator().next(); + + AddressValidator validator = new AddressValidator.Builder() + .withPartitionKeyRangeId(partitionKeyRangeId) + .withRid(a.resourceId()) + .build(); + + for (Address address : addresses) { + validator.validate(address); + } + } + }); + return this; + } + + public Builder replicasOfSamePartition() { + validators.add(new PartitionReplicasAddressesValidator() { + @Override + public void validate(Collection
    addresses) { + + // if running against prod due to upgrade etc, we may have occasionally 3 or 4 replicas. + assertThat(addresses).size().isGreaterThanOrEqualTo(MAX_REPLICA_SIZE - 1).isLessThanOrEqualTo(MAX_REPLICA_SIZE); + assertThat(addresses.stream().filter(a -> a.IsPrimary()).count()).isEqualTo(1); + + Address a = addresses.iterator().next(); + + AddressValidator validator = new AddressValidator.Builder() + .withPartitionKeyRangeId(a.getParitionKeyRangeId()) + .withRid(a.resourceId()) + .build(); + + for (Address address : addresses) { + validator.validate(address); + } + } + }); + return this; + } + + public Builder replicasOfPartitions(Collection partitionKeyRangeIds) { + validators.add(new PartitionReplicasAddressesValidator() { + @Override + public void validate(Collection
    addresses) { + + for (String pki : partitionKeyRangeIds) { + List
    partitionReplicas = addresses.stream() + .filter(a -> pki.equals(a.getParitionKeyRangeId())) + .collect(Collectors.toList()); + + PartitionReplicasAddressesValidator v = new Builder().replicasOfPartition(pki).build(); + v.validate(partitionReplicas); + } + } + }); + return this; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReaderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReaderTest.java new file mode 100644 index 0000000000000..a502c26de2419 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/QuorumReaderTest.java @@ -0,0 +1,668 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.internal.*; +import com.google.common.base.Stopwatch; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.URI; +import java.time.Duration; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class QuorumReaderTest { + private final Duration timeResolution = Duration.ofMillis(10); + private final Configs configs; + + public QuorumReaderTest() { + configs = new Configs(); + } + + @DataProvider(name = "simpleReadStrongArgProvider") + public Object[][] simpleReadStrongArgProvider() { + return new Object[][]{ + //int replicaCountToRead, ReadMode readMode, Long lsn, Long localLSN + { 1, ReadMode.Strong, 51l, 18l }, + { 2, ReadMode.Strong, 51l, 18l }, + { 3, ReadMode.Strong, 51l, 18l }, + + { 2, ReadMode.Any, 51l, 18l }, + { 1, ReadMode.Any, 51l, 18l }, + + { 2, ReadMode.Any, null, 18l }, + { 1, ReadMode.Any, null, 18l }, + }; + } + + private StoreResponse storeResponse(Long lsn, Long localLSN, Double rc) { + StoreResponseBuilder srb = StoreResponseBuilder.create(); + if (rc != null) { + srb.withRequestCharge(rc); + } + + if (lsn != null) { + srb.withLSN(lsn); + } + + if (localLSN != null) { + srb.withLocalLSN(localLSN); + } + + return srb.build(); + } + + @Test(groups = "unit", dataProvider = "simpleReadStrongArgProvider") + public void basicReadStrong_AllReplicasSameLSN(int replicaCountToRead, ReadMode readMode, Long lsn, Long localLSN) { + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2"), URI.create("secondary3")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + BigDecimal requestChargePerRead = new BigDecimal(1.1); + + StoreResponse primaryResponse = storeResponse(lsn, localLSN, requestChargePerRead.doubleValue()); + StoreResponse secondaryResponse1 = storeResponse(lsn, localLSN, requestChargePerRead.doubleValue()); + StoreResponse secondaryResponse2 = storeResponse(lsn, localLSN, requestChargePerRead.doubleValue()); + StoreResponse secondaryResponse3 = storeResponse(lsn, localLSN, requestChargePerRead.doubleValue()); + + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryReplicaURI, OperationType.Read, ResourceType.Document, primaryResponse, false) + .storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, secondaryResponse1, false) + .storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, secondaryResponse2, false) + .storeResponseOn(secondaryReplicaURIs.get(2), OperationType.Read, ResourceType.Document, secondaryResponse3, false) + .build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider); + + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + StoreResponseValidator.Builder validatorBuilder = StoreResponseValidator.create() + .withBELocalLSN(localLSN) + .withRequestCharge(requestChargePerRead.multiply(BigDecimal.valueOf(replicaCountToRead)).setScale(2, RoundingMode.FLOOR).doubleValue()); + + if (lsn != null) { + validatorBuilder.withBELSN(lsn); + } + + validateSuccess(storeResponseSingle, validatorBuilder.build()); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(replicaCountToRead); + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1); + } + + @DataProvider(name = "readStrong_RequestBarrierArgProvider") + public Object[][] readStrong_RequestBarrierArgProvider() { + return new Object[][]{ + { 1 }, + { 2 }, + { configs.getMaxNumberOfReadBarrierReadRetries() - 1 }, + { configs.getMaxNumberOfReadBarrierReadRetries() }, + }; + } + + @Test(groups = "unit", dataProvider = "readStrong_RequestBarrierArgProvider") + public void readStrong_OnlySecondary_RequestBarrier_Success(int numberOfBarrierRequestTillCatchUp) { + // scenario: we get lsn l1, l2 where l1 > l2 + // we do barrier request and send it to all replicas till we have two replicas with at least l1 lsn + + ReadMode readMode = ReadMode.Strong; + int replicaCountToRead = 2; + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + BigDecimal requestChargePerRead = new BigDecimal(1.1); + BigDecimal requestChargePerHead = BigDecimal.ZERO; + + long expectedQuorumLsn = 53; + long expectedQuorumLocalLSN = 20; + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 2) + .withLocalLSN(expectedQuorumLocalLSN - 2) + .withRequestCharge(requestChargePerRead) + .build(); + + TransportClientWrapper.Builder.UriToResultBuilder builder = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryReplicaURI, OperationType.Read, ResourceType.Document, primaryResponse, false); + + // slow replica + StoreResponse readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1) + .withLocalLSN(expectedQuorumLocalLSN -1) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false); + + for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) { + int lsnIncrement = (i == numberOfBarrierRequestTillCatchUp - 1) ? 1 : 0; + readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1 + lsnIncrement) + .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false); + + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1 + lsnIncrement) + .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement) + .withRequestCharge(requestChargePerHead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Head, ResourceType.DocumentCollection, headResponse, false); + } + + // faster replica + readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn) + .withLocalLSN(expectedQuorumLocalLSN) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, readResponse, false); + for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) { + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn + 10 * (i + 1)) + .withLocalLSN(expectedQuorumLocalLSN + 10 * (i + 1)) + .withRequestCharge(requestChargePerHead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Head, ResourceType.DocumentCollection, headResponse, false); + } + + TransportClientWrapper transportClientWrapper = builder.build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider); + + int expectedNumberOfReads = 2; + int expectedNumberOfHeads = 2 * numberOfBarrierRequestTillCatchUp; + + double expectedRequestCharge = requestChargePerRead.multiply(BigDecimal.valueOf(expectedNumberOfReads)).add( + requestChargePerHead.multiply(BigDecimal.valueOf(expectedNumberOfHeads))).setScale(4, RoundingMode.FLOOR).doubleValue(); + + Stopwatch stopwatch = Stopwatch.createStarted(); + + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(expectedQuorumLsn) + .withRequestCharge(expectedRequestCharge) + .build(); + + validateSuccess(storeResponseSingle, validator); + + assertThat(stopwatch.elapsed().plus(timeResolution)).isGreaterThanOrEqualTo(Duration.ofMillis( + numberOfBarrierRequestTillCatchUp * configs.getDelayBetweenReadBarrierCallsInMs())); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(expectedNumberOfReads + expectedNumberOfHeads); + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1 + numberOfBarrierRequestTillCatchUp); + + AddressSelectorWrapper.InOrderVerification.Verifier addressSelectorVerifier = AddressSelectorWrapper.InOrderVerification.Verifier.builder() + .resolveAllUriAsync_IncludePrimary(false) + .resolveAllUriAsync_ForceRefresh(false) + .build(); + + addressSelectorWrapper.getInOrderVerification() + .verifyNumberOfInvocations(1 + numberOfBarrierRequestTillCatchUp) + .verifyOnAll(addressSelectorVerifier); + + DocumentServiceRequestValidator requestValidator = DocumentServiceRequestValidator.builder() + .add(DocumentServiceRequestContextValidator.builder() + .qurorumSelectedLSN(0l) + .globalCommittedSelectedLSN(0l) + .storeResponses(null) + .build()) + .build(); + requestValidator.validate(request); + } + + @DataProvider(name = "readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_SuccessArgProvider") + public Object[][] readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_SuccessArgProvider() { + return new Object[][]{ + { 1 }, + { 2 }, + { configs.getMaxNumberOfReadBarrierReadRetries() - 1 }, + { configs.getMaxNumberOfReadBarrierReadRetries() }, + }; + } + + @Test(groups = "unit", dataProvider = "readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_SuccessArgProvider") + public void readStrong_SecondaryReadBarrierExhausted_ReadBarrierOnPrimary_Success(int numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet) { + // scenario: we exhaust all barrier request retries on secondaries + // after that we start barrier requests including the primary + + int numberOfBarrierRequestTillCatchUp = configs.getMaxNumberOfReadBarrierReadRetries() + numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet; + + ReadMode readMode = ReadMode.Strong; + int replicaCountToRead = 2; + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + BigDecimal requestChargePerRead = new BigDecimal(1.1); + BigDecimal requestChargePerHead = BigDecimal.ZERO; + + TransportClientWrapper.Builder.UriToResultBuilder builder = TransportClientWrapper.Builder.uriToResultBuilder(); + + long expectedQuorumLsn = 53; + long expectedQuorumLocalLSN = 20; + + for(int i = 0; i < numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet; i++) { + int lsnIncrement = (i == numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet - 1) ? 1 : 0; + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1 + lsnIncrement) + .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement) + .withRequestCharge(requestChargePerHead) + .build(); + builder.storeResponseOn(primaryReplicaURI, OperationType.Head, ResourceType.DocumentCollection, headResponse, false); + } + + // slow replica + StoreResponse readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1) + .withLocalLSN(expectedQuorumLocalLSN - 1) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false); + + for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) { + int lsnIncrement = (i == numberOfBarrierRequestTillCatchUp - 1) ? 1 : 0; + readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1 + lsnIncrement) + .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false); + + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn - 1 + lsnIncrement) + .withLocalLSN(expectedQuorumLocalLSN - 1 + lsnIncrement) + .withRequestCharge(requestChargePerHead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Head, ResourceType.DocumentCollection, headResponse, false); + } + + // faster replica + readResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn) + .withLocalLSN(expectedQuorumLocalLSN) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, readResponse, false); + for(int i = 0; i < numberOfBarrierRequestTillCatchUp; i++) { + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(expectedQuorumLsn + 10 * (i + 1)) + .withLocalLSN(expectedQuorumLocalLSN + 10 * (i + 1)) + .withRequestCharge(requestChargePerHead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Head, ResourceType.DocumentCollection, headResponse, false); + } + + TransportClientWrapper transportClientWrapper = builder.build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider); + + int beforeSecondariesRetriesExhausted_expectedNumberOfReads = 2; + int beforeSecondariesRetriesExhausted_expectedNumberOfHeads = 2 * configs.getMaxNumberOfReadBarrierReadRetries(); + + int numberOfHeadRetriesRequestWhenPrimaryIncluded = 3 * numberOfHeadBarriersWithPrimaryIncludedTillQuorumMet; + + double expectedRequestCharge = requestChargePerRead.multiply(BigDecimal.valueOf(beforeSecondariesRetriesExhausted_expectedNumberOfReads)) + .add(requestChargePerHead.multiply(BigDecimal.valueOf(beforeSecondariesRetriesExhausted_expectedNumberOfHeads))) + .setScale(4, RoundingMode.FLOOR).doubleValue(); + + Stopwatch stopwatch = Stopwatch.createStarted(); + + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(expectedQuorumLsn) + .withRequestCharge(expectedRequestCharge) + .build(); + + validateSuccess(storeResponseSingle, validator); + + assertThat(stopwatch.elapsed().plus(timeResolution)).isGreaterThanOrEqualTo(Duration.ofMillis( + numberOfBarrierRequestTillCatchUp * configs.getDelayBetweenReadBarrierCallsInMs())); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(beforeSecondariesRetriesExhausted_expectedNumberOfReads + + beforeSecondariesRetriesExhausted_expectedNumberOfHeads + + numberOfHeadRetriesRequestWhenPrimaryIncluded); + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1 + numberOfBarrierRequestTillCatchUp); + + AddressSelectorWrapper.InOrderVerification.Verifier primaryNotIncludedVerifier = AddressSelectorWrapper + .InOrderVerification.Verifier.builder() + .resolveAllUriAsync_IncludePrimary(false) + .resolveAllUriAsync_ForceRefresh(false) + .build(); + + AddressSelectorWrapper.InOrderVerification.Verifier primaryIncludedVerifier = AddressSelectorWrapper + .InOrderVerification.Verifier.builder() + .resolveAllUriAsync_IncludePrimary(true) + .resolveAllUriAsync_ForceRefresh(false) + .build(); + + int numberOfAddressResolutionWithoutPrimary = configs.getMaxNumberOfReadBarrierReadRetries()+ 1; + int numberOfAddressResolutionWithPrimary = 1; + + AddressSelectorWrapper.InOrderVerification ov = addressSelectorWrapper.getInOrderVerification(); + + for(int i = 0; i < numberOfAddressResolutionWithoutPrimary; i++) { + ov.verifyNext(primaryNotIncludedVerifier); + } + + for(int i = 0; i < numberOfAddressResolutionWithPrimary; i++) { + ov.verifyNext(primaryIncludedVerifier); + } + + DocumentServiceRequestValidator requestValidator = DocumentServiceRequestValidator.builder() + .add(DocumentServiceRequestContextValidator.builder() + .qurorumSelectedLSN(0l) + .globalCommittedSelectedLSN(0l) + .storeResponses(null) + .build()) + .build(); + requestValidator.validate(request); + } + + @Test(groups = "unit") + public void readStrong_QuorumNotSelected_ReadPrimary() { + // scenario: attempts to read from secondaries, + // only one secondary is available so ends in QuorumNotSelected State + // reads from Primary and succeeds + + ReadMode readMode = ReadMode.Strong; + int replicaCountToRead = 2; + + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + BigDecimal requestChargePerRead = new BigDecimal(1.1); + BigDecimal requestChargePerHead = BigDecimal.ZERO; + + TransportClientWrapper.Builder.UriToResultBuilder builder = TransportClientWrapper.Builder.uriToResultBuilder(); + + long primaryLSN = 52; + long primaryLocalLSN = 19; + + StoreResponse headResponse = StoreResponseBuilder.create() + .withLSN(primaryLSN) + .withLocalLSN(primaryLocalLSN) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, "2") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, Long.toString(primaryLSN)) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(primaryLocalLSN)) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(primaryReplicaURI, OperationType.Read, ResourceType.Document, headResponse, false); + + StoreResponse readResponse = StoreResponseBuilder.create() + .withLSN(primaryLSN) + .withLocalLSN(primaryLocalLSN) + .withRequestCharge(requestChargePerRead) + .build(); + builder.storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, readResponse, false); + + TransportClientWrapper transportClientWrapper = builder.build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + QuorumReader quorumReader = new QuorumReader(configs, transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, storeReader, serviceConfigurator, authTokenProvider); + + double expectedRequestCharge = requestChargePerRead.multiply(BigDecimal.valueOf(1)) + .add(requestChargePerHead.multiply(BigDecimal.valueOf(0))) + .setScale(4, RoundingMode.FLOOR).doubleValue(); + + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(primaryLSN) + .withBELocalLSN(primaryLocalLSN) + .withRequestCharge(expectedRequestCharge) + .build(); + + validateSuccess(storeResponseSingle, validator); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(1); + + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(1) + .verifyTotalInvocations(2); + + AddressSelectorWrapper.InOrderVerification.Verifier primaryNotIncludedVerifier = AddressSelectorWrapper + .InOrderVerification.Verifier.builder() + .resolveAllUriAsync_IncludePrimary(false) + .resolveAllUriAsync_ForceRefresh(false) + .build(); + + AddressSelectorWrapper.InOrderVerification.Verifier resolvePrimaryVerifier = AddressSelectorWrapper + .InOrderVerification.Verifier.builder() + .resolvePrimaryUriAsync() + .build(); + + AddressSelectorWrapper.InOrderVerification ov = addressSelectorWrapper.getInOrderVerification(); + ov.verifyNext(primaryNotIncludedVerifier); + ov.verifyNext(resolvePrimaryVerifier); + + DocumentServiceRequestValidator requestValidator = DocumentServiceRequestValidator.builder() + .add(DocumentServiceRequestContextValidator.builder() + .qurorumSelectedLSN(0l) + .globalCommittedSelectedLSN(0l) + .storeResponses(null) + .build()) + .build(); + requestValidator.validate(request); + } + + @DataProvider(name = "readPrimaryArgProvider") + public Object[][] readPrimaryArgProvider() { + return new Object[][]{ + // endpoint, verifier for endpoint expected result, verifying the StoreResponse returned + { + EndpointMock.noSecondaryReplicaBuilder() + .response(StoreResponseBuilder.create() + .withLSN(52) + .withLocalLSN(19) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, "1") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, "19") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, "19") + .withRequestCharge(0) + .build()) + .build(), + + EndpointMock.EndpointMockVerificationBuilder.builder() + .withAddressSelectorValidation(AddressSelectorWrapper + .InOrderVerificationBuilder + .create() + .verifyNumberOfInvocations(2) + .verifyNext(AddressSelectorWrapper.InOrderVerification.Verifier.builder() + .resolveAllUriAsync_IncludePrimary(false) + .resolveAllUriAsync_ForceRefresh(false) + .build()) + .verifyNext(AddressSelectorWrapper.InOrderVerification.Verifier.builder() + .resolvePrimaryUriAsync() + .build())) + .withTransportClientValidation(TransportClientWrapper.TransportClientWrapperVerificationBuilder.create().verifyNumberOfInvocations(1)), + + StoreResponseValidator.create() + .withBELSN(52) + .build() + } + }; + } + + @Test(groups = "unit", dataProvider = "readPrimaryArgProvider") + public void readPrimary(EndpointMock endpointMock, + EndpointMock.EndpointMockVerificationBuilder verification, + StoreResponseValidator storeResponseValidator) { + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + GatewayServiceConfigurationReader serviceConfigurator = Mockito.mock(GatewayServiceConfigurationReader.class); + IAuthorizationTokenProvider authTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + + QuorumReader quorumReader = new QuorumReader(configs, endpointMock.transportClientWrapper.transportClient, + endpointMock.addressSelectorWrapper.addressSelector, + new StoreReader(endpointMock.transportClientWrapper.transportClient, + endpointMock.addressSelectorWrapper.addressSelector, + sessionContainer), + serviceConfigurator, + authTokenProvider); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = Mockito.mock(PartitionKeyRange.class); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + int replicaCountToRead = 1; + ReadMode readMode = ReadMode.Strong; + Mono storeResponseSingle = quorumReader.readStrongAsync(request, replicaCountToRead, readMode); + + validateSuccess(storeResponseSingle, storeResponseValidator); + endpointMock.validate(verification); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator, + long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator, + long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReflectionUtils.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReflectionUtils.java new file mode 100644 index 0000000000000..a3fd8b6a3e4ef --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReflectionUtils.java @@ -0,0 +1,92 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.internal.RxDocumentClientImpl; +import com.azure.data.cosmos.internal.http.HttpClient; +import org.apache.commons.lang3.reflect.FieldUtils; + +/** + * + * TransportClient transportClient = ReflectionUtils.getDirectHttpsHttpClient(documentClient); + * TransportClient spyTransportClient = Mockito.spy(transportClient); + * ReflectionUtils.setTransportClient(documentClient, spyTransportClient); + * + * // use the documentClient + * // do assertion on the request and response spyTransportClient recieves using Mockito + */ +public class ReflectionUtils { + + private static void set(Object object, T newValue, String fieldName) { + try { + FieldUtils.writeField(object, fieldName, newValue, true); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static T get(Class klass, Object object, String fieldName) { + try { + return (T) FieldUtils.readField(object, fieldName, true); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static ServerStoreModel getServerStoreModel(RxDocumentClientImpl client) { + return get(ServerStoreModel.class, client, "storeModel"); + } + + public static StoreClient getStoreClient(RxDocumentClientImpl client) { + ServerStoreModel serverStoreModel = getServerStoreModel(client); + return get(StoreClient.class, serverStoreModel, "storeClient"); + } + + public static TransportClient getTransportClient(RxDocumentClientImpl client) { + StoreClient storeClient = getStoreClient(client); + return get(TransportClient.class, storeClient, "transportClient"); + } + + public static HttpClient getDirectHttpsHttpClient(RxDocumentClientImpl client) { + TransportClient transportClient = getTransportClient(client); + assert transportClient instanceof HttpTransportClient; + return get(HttpClient.class, transportClient, "httpClient"); + } + + public static void setDirectHttpsHttpClient(RxDocumentClientImpl client, HttpClient newHttpClient) { + TransportClient transportClient = getTransportClient(client); + assert transportClient instanceof HttpTransportClient; + set(transportClient, newHttpClient, "httpClient"); + } + + public static AsyncDocumentClient getAsyncDocumentClient(CosmosClient client) { + return get(AsyncDocumentClient.class, client, "asyncDocumentClient"); + } + + public static void setAsyncDocumentClient(CosmosClient client, RxDocumentClientImpl rxClient) { + set(client, rxClient, "asyncDocumentClient"); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicaAddressFactory.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicaAddressFactory.java new file mode 100644 index 0000000000000..ecba77dc0d190 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicaAddressFactory.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.azure.data.cosmos.internal.directconnectivity.AddressInformation; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.apache.commons.lang3.RandomStringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class ReplicaAddressFactory { + private static String TEMPLATE = "https://by4prdddc03-docdb-1.documents.azure.com:9056" + + "/apps/%s/services/e7c8d429-c379-40c9-9486-65b89b70be2f" + + "/partitions/%s/replicas/%s/"; + + public static String createPartitionPhysicalURI(String partitionId, boolean isPrimary) { + return String.format(TEMPLATE, UUID.randomUUID(), partitionId, RandomStringUtils.randomNumeric(18) + (isPrimary ? "p" : "s")); + } + + public static String createPrimaryPhysicalURI(String partitionId) { + return createPartitionPhysicalURI(partitionId, true); + } + + public static String createSecondaryPhysicalURI(String partitionId) { + return createPartitionPhysicalURI(partitionId, false); + } + + public static AddressInformation createAddressInformation(String partitionId, boolean isPrimary, Protocol protocol) { + String loc = createPartitionPhysicalURI(partitionId, isPrimary); + return new AddressInformation(true, isPrimary, loc, protocol); + } + + public static List createPartitionAddressInformation(String partitionId, + boolean includePrimary, + int numberOfAllReplicas, + Protocol protocol) { + List addressInformationList = new ArrayList<>(); + for (boolean isPrimary = includePrimary; numberOfAllReplicas > 0; numberOfAllReplicas--) { + addressInformationList.add(createAddressInformation(partitionId, isPrimary, protocol)); + isPrimary = false; + } + + return addressInformationList; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientPartitionSplitTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientPartitionSplitTest.java new file mode 100644 index 0000000000000..1db2a0d577ee1 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientPartitionSplitTest.java @@ -0,0 +1,210 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import io.reactivex.subscribers.TestSubscriber; +import org.assertj.core.api.Assertions; +import org.mockito.Mockito; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +public class ReplicatedResourceClientPartitionSplitTest { + protected static final int TIMEOUT = 120000; + + @DataProvider(name = "partitionIsSplittingArgProvider") + public Object[][] partitionIsSplittingArgProvider() { + return new Object[][]{ + // Consistency mode, number of partition splitting exception till split migration completes + { ConsistencyLevel.EVENTUAL, 1}, + { ConsistencyLevel.EVENTUAL, 2}, + { ConsistencyLevel.EVENTUAL, Integer.MAX_VALUE }, // server side partition split operation never completes + }; + } + + @Test(groups = { "unit" }, dataProvider = "partitionIsSplittingArgProvider", timeOut = TIMEOUT) + public void partitionSplit_RefreshCache_Read(ConsistencyLevel consistencyLevel, int partitionIsSplitting) { + URI secondary1AddressBeforeMove = URI.create("secondary"); + URI secondary1AddressAfterMove = URI.create("secondaryNew"); + + URI primaryAddressBeforeMove = URI.create("primary"); + URI primaryAddressAfterMove = URI.create("primaryNew"); + + String partitionKeyRangeIdBeforeSplit = "1"; + String partitionKeyRangeIdAfterSplit = "2"; + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.ReplicaMoveBuilder.create(Protocol.HTTPS) + .withPrimaryMove(primaryAddressBeforeMove, primaryAddressAfterMove) + .withSecondaryMove(secondary1AddressBeforeMove, secondary1AddressAfterMove) + .newPartitionKeyRangeIdOnRefresh(r -> partitionKeyRangeWithId(partitionKeyRangeIdAfterSplit)) + .build(); + + long lsn = 54; + long localLsn = 18; + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withLSN(lsn) + .withLocalLSN(localLsn) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(localLsn)) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, partitionKeyRangeIdAfterSplit) + .withRequestCharge(1.1) + .build(); + StoreResponse secondaryResponse1 = StoreResponseBuilder.create() + .withLSN(lsn) + .withLocalLSN(localLsn) + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LOCAL_LSN, Long.toString(localLsn)) + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, partitionKeyRangeIdAfterSplit) + .withRequestCharge(1.1) + .build(); + + TransportClientWrapper.Builder.UriToResultBuilder transportClientWrapperBuilder = TransportClientWrapper.Builder.uriToResultBuilder(); + + PartitionKeyRangeIsSplittingException splittingException = new PartitionKeyRangeIsSplittingException(); + if (partitionIsSplitting == Integer.MAX_VALUE) { + transportClientWrapperBuilder + .exceptionOn(primaryAddressBeforeMove, OperationType.Read, ResourceType.Document, splittingException, true) + .exceptionOn(secondary1AddressBeforeMove, OperationType.Read, ResourceType.Document, splittingException, true); + } else { + for (int i = 0; i < partitionIsSplitting; i++) { + transportClientWrapperBuilder + .exceptionOn(primaryAddressBeforeMove, OperationType.Read, ResourceType.Document, splittingException, false) + .exceptionOn(secondary1AddressBeforeMove, OperationType.Read, ResourceType.Document, splittingException, false); + } + } + + GoneException goneException = new GoneException(); + transportClientWrapperBuilder + .exceptionOn(primaryAddressBeforeMove, OperationType.Read, ResourceType.Document, goneException, true) + .exceptionOn(secondary1AddressBeforeMove, OperationType.Read, ResourceType.Document, goneException, true) + .storeResponseOn(primaryAddressAfterMove, OperationType.Read, ResourceType.Document, secondaryResponse1, true) + .storeResponseOn(secondary1AddressAfterMove, OperationType.Read, ResourceType.Document, primaryResponse, true); + + + TransportClientWrapper transportClientWrapper = transportClientWrapperBuilder.build(); + + GatewayServiceConfiguratorReaderMock gatewayServiceConfigurationReaderWrapper = GatewayServiceConfiguratorReaderMock.from(ConsistencyLevel.STRONG, + 4, + 3, + 4, + 3); + + SessionContainer sessionContainer = new SessionContainer("test"); + + IAuthorizationTokenProvider authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + ReplicatedResourceClient resourceClient = new ReplicatedResourceClient(new Configs(), + addressSelectorWrapper.addressSelector, + sessionContainer, + transportClientWrapper.transportClient, + gatewayServiceConfigurationReaderWrapper.gatewayServiceConfigurationReader, + authorizationTokenProvider, + false, + false); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + request.requestContext = new DocumentServiceRequestContext(); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeIdBeforeSplit); + request.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, consistencyLevel.toString()); + + Function> prepareRequestAsyncDelegate = null; + Mono storeResponseObs = resourceClient.invokeAsync(request, prepareRequestAsyncDelegate); + + if (partitionIsSplitting < Integer.MAX_VALUE) { + + StoreResponseValidator validator = StoreResponseValidator.create() + .withBELSN(lsn) + .withRequestCharge(1.1) + .build(); + validateSuccess(storeResponseObs, validator); + + addressSelectorWrapper.verifyNumberOfForceCacheRefreshGreaterThanOrEqualTo(1); + } else { + FailureValidator validator = FailureValidator.builder().instanceOf(CosmosClientException.class) + .statusCode(503).build(); + validateFailure(storeResponseObs, validator, TIMEOUT); + } + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator) { + validateSuccess(single, validator, TIMEOUT); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator, long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator) { + validateSuccess(single, validator, TIMEOUT); + } + + public static void validateSuccess(Mono single, + StoreResponseValidator validator, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + + public static void validateFailure(Mono single, FailureValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + Assertions.assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } + + private PartitionKeyRange partitionKeyRangeWithId(String id) { + PartitionKeyRange partitionKeyRange = Mockito.mock(PartitionKeyRange.class); + Mockito.doReturn(id).when(partitionKeyRange).id(); + return partitionKeyRange; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientTest.java new file mode 100644 index 0000000000000..19bb302ee0762 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/ReplicatedResourceClientTest.java @@ -0,0 +1,95 @@ +/* + * + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.directconnectivity.*; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.IAuthorizationTokenProvider; +import com.azure.data.cosmos.internal.OperationType; +import com.azure.data.cosmos.internal.ResourceType; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.directconnectivity.*; +import io.reactivex.subscribers.TestSubscriber; +import org.assertj.core.api.Assertions; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.concurrent.TimeUnit; + +public class ReplicatedResourceClientTest { + protected static final int TIMEOUT = 60000; + private IAddressResolver addressResolver; + private TransportClient transportClient; + private boolean enableReadRequestsFallback; + public boolean forceAddressRefresh; + private GatewayServiceConfigurationReader serviceConfigReader; + private IAuthorizationTokenProvider authorizationTokenProvider; + + @BeforeClass(groups = "unit") + public void setup() throws Exception { + addressResolver = Mockito.mock(IAddressResolver.class); + transportClient = Mockito.mock(TransportClient.class); + serviceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + authorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + } + + /** + * This test will verify that Gone exception will be retired + * fixed number of time before throwing error. + */ + @Test(groups = { "unit" }, timeOut = TIMEOUT) + public void invokeAsyncWithGoneException() { + Configs configs = new Configs(); + ReplicatedResourceClient resourceClient = new ReplicatedResourceClient(configs, new AddressSelector(addressResolver, Protocol.HTTPS), null, + transportClient, serviceConfigReader, authorizationTokenProvider, enableReadRequestsFallback, false); + FailureValidator validator = FailureValidator.builder().instanceOf(CosmosClientException.class).build(); + RxDocumentServiceRequest request = Mockito.spy(RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document)); + + Mockito.when(addressResolver.resolveAsync(Matchers.any(), Matchers.anyBoolean())) + .thenReturn(Mono.error(new GoneException())); + Mono response = resourceClient.invokeAsync(request, null); + + validateFailure(response, validator, TIMEOUT); + //method will fail 7 time (first try ,last try , and 5 retries within 30 sec(1,2,4,8,15 wait)) + Mockito.verify(addressResolver, Mockito.times(7)).resolveAsync(Matchers.any(), Matchers.anyBoolean()); + } + + public static void validateFailure(Mono single, FailureValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + Assertions.assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClientTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClientTest.java new file mode 100644 index 0000000000000..094e599e2bd36 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/RntbdTransportClientTest.java @@ -0,0 +1,934 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConflictException; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.ForbiddenException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.LockedException; +import com.azure.data.cosmos.MethodNotAllowedException; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.PreconditionFailedException; +import com.azure.data.cosmos.RequestEntityTooLargeException; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.RequestTimeoutException; +import com.azure.data.cosmos.RetryWithException; +import com.azure.data.cosmos.ServiceUnavailableException; +import com.azure.data.cosmos.UnauthorizedException; +import com.azure.data.cosmos.internal.directconnectivity.RntbdTransportClient; +import com.azure.data.cosmos.internal.directconnectivity.ServerProperties; +import com.azure.data.cosmos.internal.directconnectivity.RntbdTransportClient; +import com.azure.data.cosmos.internal.directconnectivity.ServerProperties; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdContext; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdContextNegotiator; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdContextRequest; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdEndpoint; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequest; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestArgs; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestEncoder; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestManager; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestRecord; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdRequestTimer; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdResponse; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdResponseDecoder; +import com.azure.data.cosmos.internal.directconnectivity.rntbd.RntbdUUID; +import com.azure.data.cosmos.BadRequestException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.InternalServerErrorException; +import com.azure.data.cosmos.InvalidPartitionException; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandler; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.ConnectException; +import java.net.URI; +import java.time.Duration; +import java.util.Arrays; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import static com.azure.data.cosmos.internal.HttpConstants.HttpHeaders; +import static com.azure.data.cosmos.internal.HttpConstants.HttpMethods; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes; +import static org.assertj.core.api.Assertions.assertThat; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +public final class RntbdTransportClientTest { + + private static final Logger logger = LoggerFactory.getLogger(RntbdTransportClientTest.class); + private static final int lsn = 5; + private static final ByteBuf noContent = Unpooled.wrappedBuffer(new byte[0]); + private static final String partitionKeyRangeId = "3"; + private static final URI physicalAddress = URI.create("rntbd://host:10251/replica-path/"); + private static final Duration requestTimeout = Duration.ofSeconds(1000); + + @DataProvider(name = "fromMockedNetworkFailureToExpectedDocumentClientException") + public Object[][] fromMockedNetworkFailureToExpectedDocumentClientException() { + + return new Object[][] { + }; + } + + @DataProvider(name = "fromMockedRntbdResponseToExpectedDocumentClientException") + public Object[][] fromMockedRntbdResponseToExpectedDocumentClientException() { + + return new Object[][] { + { + // 1 BadRequestException + + FailureValidator.builder() + .instanceOf(BadRequestException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 400, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(1L) + ), + noContent) + }, + { + // 2 UnauthorizedException + + FailureValidator.builder() + .instanceOf(UnauthorizedException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 401, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(2L) + ), + noContent) + }, + { + // 3 ForbiddenException + + FailureValidator.builder() + .instanceOf(ForbiddenException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 403, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(3L) + ), + noContent) + }, + { + // 4 NotFoundException + + FailureValidator.builder() + .instanceOf(NotFoundException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 404, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(4L) + ), + noContent) + }, + { + // 5 MethodNotAllowedException + + FailureValidator.builder() + .instanceOf(MethodNotAllowedException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 405, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(5L) + ), + noContent) + }, + { + // 6 RequestTimeoutException + + FailureValidator.builder() + .instanceOf(RequestTimeoutException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 408, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(6L) + ), + noContent) + }, + { + // 7 ConflictException + + FailureValidator.builder() + .instanceOf(ConflictException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 409, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(7L) + ), + noContent) + }, + { + // 8 InvalidPartitionException + + FailureValidator.builder() + .instanceOf(InvalidPartitionException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 410, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.SUB_STATUS, Integer.toString(SubStatusCodes.NAME_CACHE_IS_STALE), + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(8L) + ), + noContent) + }, + { + // 9 PartitionKeyRangeGoneException + + FailureValidator.builder() + .instanceOf(PartitionKeyRangeGoneException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 410, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.SUB_STATUS, Integer.toString(SubStatusCodes.PARTITION_KEY_RANGE_GONE), + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(9L) + ), + noContent) + }, + { + // 10 PartitionKeyRangeIsSplittingException + + FailureValidator.builder() + .instanceOf(PartitionKeyRangeIsSplittingException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 410, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.SUB_STATUS, Integer.toString(SubStatusCodes.COMPLETING_SPLIT), + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(10L) + ), + noContent) + }, + { + // 11 PartitionIsMigratingException + + FailureValidator.builder() + .instanceOf(PartitionIsMigratingException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 410, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.SUB_STATUS, Integer.toString(SubStatusCodes.COMPLETING_PARTITION_MIGRATION), + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(11L) + ), + noContent) + }, + { + // 12 GoneException + + FailureValidator.builder() + .instanceOf(GoneException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 410, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.SUB_STATUS, String.valueOf(SubStatusCodes.UNKNOWN), + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(12L) + ), + noContent) + }, + { + // 13 PreconditionFailedException + + FailureValidator.builder() + .instanceOf(PreconditionFailedException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 412, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(13L) + ), + noContent) + }, + { + // 14 RequestEntityTooLargeException + + FailureValidator.builder() + .instanceOf(RequestEntityTooLargeException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 413, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(14L) + ), + noContent) + }, + { + // 15 LockedException + + FailureValidator.builder() + .instanceOf(LockedException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 423, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(15L) + ), + noContent) + }, + { + // 16 RequestRateTooLargeException + + FailureValidator.builder() + .instanceOf(RequestRateTooLargeException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 429, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(16L) + ), + noContent) + }, + { + // 17 RetryWithException + + FailureValidator.builder() + .instanceOf(RetryWithException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 449, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(17L) + ), + noContent) + }, + { + // 18 InternalServerErrorException + + FailureValidator.builder() + .instanceOf(InternalServerErrorException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 500, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(18L) + ), + noContent) + }, + { + // 19 ServiceUnavailableException + + FailureValidator.builder() + .instanceOf(ServiceUnavailableException.class) + .lsn(lsn) + .partitionKeyRangeId(partitionKeyRangeId) + .resourceAddress(null), + RxDocumentServiceRequest.create( + OperationType.Read, + ResourceType.DocumentCollection, + "/dbs/db/colls/col", + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId + )), + new RntbdResponse( + RntbdUUID.EMPTY, + 503, + ImmutableMap.of( + HttpHeaders.LSN, Integer.toString(lsn), + HttpHeaders.PARTITION_KEY_RANGE_ID, partitionKeyRangeId, + HttpHeaders.TRANSPORT_REQUEST_ID, Long.toString(19L) + ), + noContent) + }, + }; + } + + /** + * Verifies that a request for a non-existent resource produces a {@link }GoneException} + */ + @Test(enabled = false, groups = { "direct" }) + public void verifyGoneResponseMapsToGoneException() throws Exception { + + final RntbdTransportClient.Options options = new RntbdTransportClient.Options.Builder(requestTimeout).build(); + final SslContext sslContext = SslContextBuilder.forClient().build(); + + try (final RntbdTransportClient transportClient = new RntbdTransportClient(options, sslContext)) { + + final BaseAuthorizationTokenProvider authorizationTokenProvider = new BaseAuthorizationTokenProvider( + RntbdTestConfiguration.AccountKey + ); + + final URI physicalAddress = new URI("rntbd://" + + RntbdTestConfiguration.RntbdAuthority + + "/apps/DocDbApp/services/DocDbMaster0/partitions/780e44f4-38c8-11e6-8106-8cdcd42c33be/replicas/1p/" + ); + + final ImmutableMap.Builder builder = ImmutableMap.builder(); + + builder.put(HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + + final String token = authorizationTokenProvider.generateKeyAuthorizationSignature(HttpMethods.GET, + Paths.DATABASE_ACCOUNT_PATH_SEGMENT, + ResourceType.DatabaseAccount, + builder.build() + ); + + builder.put(HttpHeaders.AUTHORIZATION, token); + + final RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + ResourceType.DatabaseAccount, + Paths.DATABASE_ACCOUNT_PATH_SEGMENT, + builder.build() + ); + + final Mono responseMono = transportClient.invokeStoreAsync(physicalAddress, request); + + responseMono.subscribe(response -> { }, error -> { + final String format = "Expected %s, not %s"; + assertTrue(error instanceof GoneException, String.format(format, GoneException.class, error.getClass())); + final Throwable cause = error.getCause(); + if (cause != null) { + // assumption: cosmos isn't listening on 10251 + assertTrue(cause instanceof ConnectException, String.format(format, ConnectException.class, error.getClass())); + } + }); + + } catch (final Exception error) { + final String message = String.format("%s: %s", error.getClass(), error.getMessage()); + fail(message, error); + } + } + + /** + * Validates the error handling behavior of {@link RntbdTransportClient} for network failures + *

    + * These are the exceptions that cannot be derived from server responses. They are mapped from Netty channel + * failures simulated by {@link FakeChannel}. + * + * @param builder A feature validator builder to confirm that response is correctly mapped to an exception + * @param request An RNTBD request instance + * @param exception An exception mapping + */ + @Test(enabled = false, groups = { "unit" }, dataProvider = "fromMockedNetworkFailureToExpectedDocumentClientException") + public void verifyNetworkFailure( + final FailureValidator.Builder builder, + final RxDocumentServiceRequest request, + final CosmosClientException exception + ) { + // TODO: DANOBLE: Implement RntbdTransportClientTest.verifyNetworkFailure + // Links: + // https://msdata.visualstudio.com/CosmosDB/_workitems/edit/378750 + throw new UnsupportedOperationException("TODO: DANOBLE: Implement this test"); + } + + /** + * Validates the error handling behavior of the {@link RntbdTransportClient} for HTTP status codes >= 400 + * + * @param builder A feature validator builder to confirm that response is correctly mapped to an exception + * @param request An RNTBD request instance + * @param response The RNTBD response instance to be returned as a result of the request + */ + @Test(enabled = true, groups = { "unit" }, dataProvider = "fromMockedRntbdResponseToExpectedDocumentClientException") + public void verifyRequestFailures( + final FailureValidator.Builder builder, + final RxDocumentServiceRequest request, + final RntbdResponse response + ) { + final UserAgentContainer userAgent = new UserAgentContainer(); + final Duration timeout = Duration.ofMillis(1000); + + try (final RntbdTransportClient client = getRntbdTransportClientUnderTest(userAgent, timeout, response)) { + + final Mono responseMono; + + try { + responseMono = client.invokeStoreAsync(physicalAddress, request); + } catch (final Exception error) { + throw new AssertionError(String.format("%s: %s", error.getClass(), error)); + } + + this.validateFailure(responseMono, builder.build()); + } + } + + private static RntbdTransportClient getRntbdTransportClientUnderTest( + final UserAgentContainer userAgent, + final Duration requestTimeout, + final RntbdResponse expected + ) { + + final RntbdTransportClient.Options options = new RntbdTransportClient.Options.Builder(requestTimeout) + .userAgent(userAgent) + .build(); + + final SslContext sslContext; + + try { + sslContext = SslContextBuilder.forClient().build(); + } catch (final Exception error) { + throw new AssertionError(String.format("%s: %s", error.getClass(), error.getMessage())); + } + + return new RntbdTransportClient(new FakeEndpoint.Provider(options, sslContext, expected)); + } + + private void validateFailure(final Mono responseMono, final FailureValidator validator) { + validateFailure(responseMono, validator, requestTimeout.toMillis()); + } + + private static void validateFailure( + final Mono mono, final FailureValidator validator, final long timeout + ) { + + final TestSubscriber subscriber = new TestSubscriber<>(); + mono.subscribe(subscriber); + + subscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + assertThat(subscriber.errorCount()).isEqualTo(1); + subscriber.assertSubscribed(); + subscriber.assertNoValues(); + validator.validate(subscriber.errors().get(0)); + } + + // region Types + + private static final class FakeChannel extends EmbeddedChannel { + + private static final ServerProperties serverProperties = new ServerProperties("agent", "3.0.0"); + private final BlockingQueue responses; + + FakeChannel(final BlockingQueue responses, final ChannelHandler... handlers) { + super(handlers); + this.responses = responses; + } + + @Override + protected void handleInboundMessage(final Object message) { + super.handleInboundMessage(message); + assertTrue(message instanceof ByteBuf); + } + + @Override + protected void handleOutboundMessage(final Object message) { + + assertTrue(message instanceof ByteBuf); + + final ByteBuf out = Unpooled.buffer(); + final ByteBuf in = (ByteBuf) message; + + // This is the end of the outbound pipeline and so we can do what we wish with the outbound message + + if (in.getUnsignedIntLE(4) == 0) { + + final RntbdContextRequest request = RntbdContextRequest.decode(in.copy()); + final RntbdContext rntbdContext = RntbdContext.from(request, serverProperties, HttpResponseStatus.OK); + + rntbdContext.encode(out); + + } else { + + final RntbdRequest rntbdRequest = RntbdRequest.decode(in.copy()); + final RntbdResponse rntbdResponse; + + try { + rntbdResponse = this.responses.take(); + } catch (final Exception error) { + throw new AssertionError(String.format("%s: %s", error.getClass(), error.getMessage())); + } + + assertEquals(rntbdRequest.getTransportRequestId(), rntbdResponse.getTransportRequestId()); + rntbdResponse.encode(out); + out.setBytes(8, in.slice(8, 16)); // Overwrite activityId + } + + this.writeInbound(out); + } + } + + private static final class FakeEndpoint implements RntbdEndpoint { + + final RntbdRequestTimer requestTimer; + final FakeChannel fakeChannel; + final URI physicalAddress; + + private FakeEndpoint( + final Config config, final RntbdRequestTimer timer, final URI physicalAddress, + final RntbdResponse... expected + ) { + + final ArrayBlockingQueue responses = new ArrayBlockingQueue<>( + expected.length, true, Arrays.asList(expected) + ); + + RntbdRequestManager requestManager = new RntbdRequestManager(30); + this.physicalAddress = physicalAddress; + this.requestTimer = timer; + + this.fakeChannel = new FakeChannel(responses, + new RntbdContextNegotiator(requestManager, config.getUserAgent()), + new RntbdRequestEncoder(), + new RntbdResponseDecoder(), + requestManager + ); + } + + @Override + public String getName() { + return "FakeEndpoint"; + } + + @Override + public void close() { + this.fakeChannel.close().syncUninterruptibly(); + } + + @Override + public RntbdRequestRecord request(final RntbdRequestArgs requestArgs) { + final RntbdRequestRecord requestRecord = new RntbdRequestRecord(requestArgs, this.requestTimer); + this.fakeChannel.writeOutbound(requestRecord); + return requestRecord; + } + + static class Provider implements RntbdEndpoint.Provider { + + final Config config; + final RntbdResponse expected; + final RntbdRequestTimer timer; + + Provider(RntbdTransportClient.Options options, SslContext sslContext, RntbdResponse expected) { + this.config = new Config(options, sslContext, LogLevel.WARN); + this.timer = new RntbdRequestTimer(config.getRequestTimeout()); + this.expected = expected; + } + + @Override + public void close() throws RuntimeException { + this.timer.close(); + } + + @Override + public Config config() { + return this.config; + } + + @Override + public int count() { + return 1; + } + + @Override + public RntbdEndpoint get(URI physicalAddress) { + return new FakeEndpoint(config, timer, physicalAddress, expected); + } + + @Override + public Stream list() { + return Stream.empty(); + } + } + } + + private static final class RntbdTestConfiguration { + + static String AccountHost = System.getProperty("ACCOUNT_HOST", + StringUtils.defaultString( + Strings.emptyToNull(System.getenv().get("ACCOUNT_HOST")), + "https://localhost:8081/" + ) + ); + + static String AccountKey = System.getProperty("ACCOUNT_KEY", + StringUtils.defaultString( + Strings.emptyToNull(System.getenv().get("ACCOUNT_KEY")), + "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" + ) + ); + + static String RntbdAuthority = System.getProperty("rntbd.authority", + StringUtils.defaultString( + Strings.emptyToNull(System.getenv().get("RNTBD_AUTHORITY")), + String.format("%s:10251", URI.create(AccountHost).getHost()) + ) + ); + + private RntbdTestConfiguration() { + } + } + + // endregion +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderDotNetTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderDotNetTest.java new file mode 100644 index 0000000000000..5891bde18a51b --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderDotNetTest.java @@ -0,0 +1,891 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.ServiceUnavailableException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.InvalidPartitionException; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.StringUtils; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.net.URISyntaxException; +import java.time.Duration; +import java.util.ArrayDeque; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Queue; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StoreReaderDotNetTest { + private static final Logger logger = LoggerFactory.getLogger(StoreReaderDotNetTest.class); + @Test(groups = "unit") + public void addressCache() { + // create a real document service request + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + + // setup mocks for address information + AddressInformation[] addressInformation = new AddressInformation[3]; + for (int i = 0; i < 3; i++) { + addressInformation[i] = new AddressInformation(true, true, "http://replica-" + i, Protocol.HTTPS); + } + + IAddressResolver mockAddressCache = Mockito.mock(IAddressResolver.class); + + Mockito.doReturn(Mono.just(addressInformation)) + .when(mockAddressCache) + .resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.eq(false)); + + // validate that the mock works + AddressInformation[] addressInfo = mockAddressCache.resolveAsync(entity, false).block(); + assertThat(addressInfo[0]).isEqualTo(addressInformation[0]); + } + + /** + * Tests for TransportClient + */ + @Test(groups = "unit") + public void transportClient() { + // create a real document service request + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + + // setup mocks for address information + AddressInformation[] addressInformation = new AddressInformation[3]; + + // construct URIs that look like the actual uri + // rntbd://yt1prdddc01-docdb-1.documents.azure.com:14003/apps/ce8ab332-f59e-4ce7-a68e-db7e7cfaa128/services/68cc0b50-04c6-4716-bc31-2dfefd29e3ee/partitions/5604283d-0907-4bf4-9357-4fa9e62de7b5/replicas/131170760736528207s/ + for (int i = 0; i < 3; i++) { + String physicalUri = + "rntbd://dummytenant.documents.azure.com:14003/apps/APPGUID/services/SERVICEGUID/partitions/PARTITIONGUID/replicas/" + + Integer.toString(i) + (i == 0 ? "p" : "s") + "/"; + addressInformation[i] = new AddressInformation(true, true, physicalUri, Protocol.TCP); + + } + + // create objects for all the dependencies of the StoreReader + TransportClient mockTransportClient = Mockito.mock(TransportClient.class); + + // create mock store response object + StoreResponseBuilder srb = new StoreResponseBuilder(); + + + // set lsn and activityid on the store response. + srb.withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1" ); + srb.withHeader(WFConstants.BackendHeaders.LSN, "50"); + + // setup mock transport client + Mockito.doReturn(Mono.just(srb.build())) + .when(mockTransportClient) + .invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[0].getPhysicalUri())), + Mockito.any(RxDocumentServiceRequest.class)); + + + + // get response from mock object + StoreResponse response = mockTransportClient.invokeResourceOperationAsync(URI.create(addressInformation[0].getPhysicalUri()), entity).block(); + + // validate that the LSN matches + // validate that the ActivityId Matches + + StoreResponseValidator validator = StoreResponseValidator.create().withBELSN(50).withBEActivityId("ACTIVITYID1_1").build(); + validator.validate(response); + } + + private TransportClient getMockTransportClientDuringUpgrade(AddressInformation[] addressInformation) { + // create objects for all the dependencies of the StoreReader + TransportClient mockTransportClient = Mockito.mock(TransportClient.class); + + // create mock store response object + // set lsn and activityid on the store response. + StoreResponse mockStoreResponseFast = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "50") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1") + .build(); + + StoreResponse mockStoreResponseSlow = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "30") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1") + .build(); + + // setup mock transport client for the first replica + Mockito.doReturn(Mono.just(mockStoreResponseFast)) + .when(mockTransportClient) + .invokeResourceOperationAsync(Mockito.eq(URI.create(addressInformation[0].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + + // setup mock transport client with a sequence of outputs + Mockito.doReturn(Mono.just(mockStoreResponseFast)) // initial read response + .doReturn(Mono.just(mockStoreResponseFast)) // barrier retry, count 1 + .doReturn(Mono.just(mockStoreResponseFast)) // barrier retry, count 2 + .doReturn(Mono.error(new InvalidPartitionException())) // throw invalid partition exception to simulate collection recreate with same name + .doReturn(Mono.just(mockStoreResponseFast)) // new read + .doReturn(Mono.just(mockStoreResponseFast)) // subsequent barriers + .doReturn(Mono.just(mockStoreResponseFast)) + .doReturn(Mono.just(mockStoreResponseFast)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[1].getPhysicalUri())), + Mockito.any(RxDocumentServiceRequest.class)); + + // After this, the product code should reset target identity, and lsn response + Queue queueOfResponses = new ArrayDeque<>(); + + // let the first 10 responses be slow, and then fast + for (int i = 0; i < 20; i++) { + queueOfResponses.add(i <= 2 ? mockStoreResponseSlow : mockStoreResponseFast); + } + + // setup mock transport client with a sequence of outputs, for the second replica + // This replica behaves in the following manner: + // calling InvokeResourceOperationAsync + // 1st time: returns valid LSN + // 2nd time: returns InvalidPartitionException + // initial read response + + Mockito.doAnswer((params) -> Mono.just(queueOfResponses.poll())) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[2].getPhysicalUri())), + Mockito.any(RxDocumentServiceRequest.class)); + + return mockTransportClient; + } + + private enum ReadQuorumResultKind { + QuorumMet, + QuorumSelected, + QuorumNotSelected + } + + private TransportClient getMockTransportClientForGlobalStrongReads(AddressInformation[] addressInformation, ReadQuorumResultKind result) { + // create objects for all the dependencies of the StoreReader + TransportClient mockTransportClient = Mockito.mock(TransportClient.class); + + // create mock store response object + + StoreResponse mockStoreResponse1 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "100") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "90") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse2 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "90") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "90") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_2") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + + StoreResponse mockStoreResponse3 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "92") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "90") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse4 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "100") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "92") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse5 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "100") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "100") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .withHeader(WFConstants.BackendHeaders.CURRENT_REPLICA_SET_SIZE, "1") + .withHeader(WFConstants.BackendHeaders.QUORUM_ACKED_LSN, "100") + .build(); + // set lsn and activityid on the store response. + + StoreResponse mockStoreResponseFast = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "50") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1") + .build(); + + if(result == ReadQuorumResultKind.QuorumMet) { + // setup mock transport client for the first replica + Mockito.doReturn(Mono.just(mockStoreResponse5)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[0].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + Mockito.doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse5)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[1].getPhysicalUri())), + Mockito.any(RxDocumentServiceRequest.class)); + + Mockito.doReturn(Mono.just(mockStoreResponse2)) + .doReturn(Mono.just(mockStoreResponse2)) + .doReturn(Mono.just(mockStoreResponse2)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse4)) + .doReturn(Mono.just(mockStoreResponse5)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[2].getPhysicalUri())), + Mockito.any(RxDocumentServiceRequest.class)); + } + + if (result == ReadQuorumResultKind.QuorumSelected) { + // setup mock transport client for the first replica + Mockito.doReturn(Mono.just(mockStoreResponse2)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[0].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + // setup mock transport client with a sequence of outputs + Mockito.doReturn(Mono.just(mockStoreResponse1)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[1].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + + // setup mock transport client with a sequence of outputs + Mockito.doReturn(Mono.just(mockStoreResponse2)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[2].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + } else if (result == ReadQuorumResultKind.QuorumNotSelected) { + // setup mock transport client for the first replica + + Mockito.doReturn(Mono.just(mockStoreResponse5)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[0].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + Mockito.doReturn(Mono.just(mockStoreResponse5)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[1].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + Mockito.doReturn(Mono.error(new GoneException("test"))) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[2].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + } + + return mockTransportClient; + } + + private TransportClient getMockTransportClientForGlobalStrongWrites( + AddressInformation[] addressInformation, + int indexOfCaughtUpReplica, + boolean undershootGlobalCommittedLsnDuringBarrier, + boolean overshootLsnDuringBarrier, + boolean overshootGlobalCommittedLsnDuringBarrier) + { + TransportClient mockTransportClient = Mockito.mock(TransportClient.class); + + // create mock store response object + + // set lsn and activityid on the store response. + StoreResponse mockStoreResponse1 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "100") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_1") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "90") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse2 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "100") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_2") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "100") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse3 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "103") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "100") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse4 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "103") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "103") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse mockStoreResponse5 = StoreResponseBuilder.create() + .withHeader(WFConstants.BackendHeaders.LSN, "106") + .withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, "ACTIVITYID1_3") + .withHeader(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, "103") + .withHeader(WFConstants.BackendHeaders.NUMBER_OF_READ_REGIONS, "1") + .build(); + + StoreResponse finalResponse = null; + if (undershootGlobalCommittedLsnDuringBarrier) { + finalResponse = mockStoreResponse1; + } else { + if (overshootLsnDuringBarrier) { + if (overshootGlobalCommittedLsnDuringBarrier) { + finalResponse = mockStoreResponse5; + } else { + finalResponse = mockStoreResponse3; + } + } else { + if (overshootGlobalCommittedLsnDuringBarrier) { + finalResponse = mockStoreResponse4; + } else { + finalResponse = mockStoreResponse2; + } + } + } + + for (int i = 0; i < addressInformation.length; i++) { + if (i == indexOfCaughtUpReplica) { + Mockito.doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(finalResponse)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[i].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + + } else { + Mockito.doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .doReturn(Mono.just(mockStoreResponse1)) + .when(mockTransportClient).invokeResourceOperationAsync( + Mockito.eq(URI.create(addressInformation[i].getPhysicalUri())), Mockito.any(RxDocumentServiceRequest.class)); + } + } + + return mockTransportClient; + } + + /** + * We are simulating upgrade scenario where one of the secondary replicas is down. + * And one of the other secondary replicas is an XP Primary (lagging behind). + * Dyanmic Quorum is in effect, so Write Quorum = 2 + * @return array of AddressInformation + */ + private AddressInformation[] getMockAddressInformationDuringUpgrade() { + // setup mocks for address information + AddressInformation[] addressInformation = new AddressInformation[3]; + + // construct URIs that look like the actual uri + // rntbd://yt1prdddc01-docdb-1.documents.azure.com:14003/apps/ce8ab332-f59e-4ce7-a68e-db7e7cfaa128/services/68cc0b50-04c6-4716-bc31-2dfefd29e3ee/partitions/5604283d-0907-4bf4-9357-4fa9e62de7b5/replicas/131170760736528207s/ + for (int i = 0; i <= 2; i++) { + String physicalUri = + "rntbd://dummytenant.documents.azure.com:14003/apps/APPGUID/services/SERVICEGUID/partitions/PARTITIONGUID/replicas/" + + Integer.toString(i) + (i == 0 ? "p" : "s") + "/"; + addressInformation[i] = new AddressInformation(true, i == 0 ? true : false, physicalUri, Protocol.TCP); + } + + return addressInformation; + } + + /** + * Given an array of address information, gives mock address cache. + * @param addressInformation + * @return + */ + private IAddressResolver getMockAddressCache(AddressInformation[] addressInformation) + { + // Address Selector is an internal sealed class that can't be mocked, but its dependency + // AddressCache can be mocked. + IAddressResolver mockAddressCache = Mockito.mock(IAddressResolver.class); + + Mockito.doReturn(Mono.just(addressInformation)).when(mockAddressCache) + .resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.eq(false) /*forceRefresh*/); + + Mockito.doReturn(Mono.just(new AddressInformation[0])).when(mockAddressCache) + .resolveAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.eq(true) /*forceRefresh*/); + + return mockAddressCache; + } + + /** + * Tests for {@link StoreReader} + */ + @Test(groups = "unit") + public void storeReaderBarrier() { + // create a real document service request + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + + // set request charge tracker - this is referenced in store reader (ReadMultipleReplicaAsync) + DocumentServiceRequestContext requestContext = new DocumentServiceRequestContext(); + // requestContext.ClientRequestStatistics = new ClientSideRequestStatistics(); + requestContext.requestChargeTracker = new RequestChargeTracker(); + entity.requestContext = requestContext; + + // also setup timeout helper, used in store reader + // entity.requestContext.timeoutHelper = new TimeoutHelper(new TimeSpan(2, 2, 2)); + entity.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + + // when the store reader throws INVALID Partition exception, the higher layer should + // clear this target identity. + // entity.requestContext.TargetIdentity = new ServiceIdentity("dummyTargetIdentity1", new Uri("http://dummyTargetIdentity1"), false); + entity.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + + AddressInformation[] addressInformation = getMockAddressInformationDuringUpgrade(); + IAddressResolver mockAddressCache = getMockAddressCache(addressInformation); + + // validate that the mock works + AddressInformation[] addressInfo = mockAddressCache.resolveAsync(entity, false).block(); + + assertThat(addressInfo[0]).isEqualTo(addressInformation[0]); + + AddressSelector addressSelector = new AddressSelector(mockAddressCache, Protocol.TCP); + URI primaryAddress = addressSelector.resolvePrimaryUriAsync(entity, false /*forceAddressRefresh*/).block(); + + // check if the address return from Address Selector matches the original address info + assertThat(primaryAddress.toString()).isEqualTo(addressInformation[0].getPhysicalUri()); + + // get mock transport client that returns a sequence of responses to simulate upgrade + TransportClient mockTransportClient = getMockTransportClientDuringUpgrade(addressInformation); + + // get response from mock object + StoreResponse response = mockTransportClient.invokeResourceOperationAsync(URI.create(addressInformation[0].getPhysicalUri()), entity).block(); + + // validate that the LSN matches + assertThat(response.getLSN()).isEqualTo(50); + + String activityId = response.getHeaderValue(WFConstants.BackendHeaders.ACTIVITY_ID); + + // validate that the ActivityId Matches + assertThat(activityId).isEqualTo("ACTIVITYID1_1"); + + // create a real session container - we don't need session for this test anyway + ISessionContainer sessionContainer = new SessionContainer(Strings.Emtpy); + + // create store reader with mock transport client, real address selector (that has mock address cache), and real session container + StoreReader storeReader = + new StoreReader(mockTransportClient, + addressSelector, + sessionContainer); + + // reads always go to read quorum (2) replicas + int replicaCountToRead = 2; + + List result = storeReader.readMultipleReplicaAsync( + entity, + false /*includePrimary*/, + replicaCountToRead, + true /*requiresValidLSN*/, + false /*useSessionToken*/, + ReadMode.Strong).block(); + + // make sure we got 2 responses from the store reader + assertThat(result).hasSize(2); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator, long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateSuccess(Mono single, + StoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono single, + StoreResultValidator validator, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateException(Mono single, + FailureValidator validator) { + validateException(single, validator, 10000); + } + + public static void validateException(Mono single, + FailureValidator validator, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate(testSubscriber.errors().get(0)); + } + + /** + * StoreClient uses ReplicatedResourceClient uses ConsistencyReader uses QuorumReader uses StoreReader uses TransportClient uses RntbdConnection + */ + @Test(groups = "unit", enabled = false) + public void storeClient() throws URISyntaxException { + // create a real document service request (with auth token level = god) + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + entity.authorizationTokenType = AuthorizationTokenType.PrimaryMasterKey; + + // set request charge tracker - this is referenced in store reader (ReadMultipleReplicaAsync) + DocumentServiceRequestContext requestContext = new DocumentServiceRequestContext(); + requestContext.requestChargeTracker = new RequestChargeTracker(); + entity.requestContext = requestContext; + + // set a dummy resource id on the request. + entity.setResourceId("1-MxAPlgMgA="); + + // set consistency level on the request to Bounded Staleness + entity.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.BOUNDED_STALENESS.toString()); + + // also setup timeout helper, used in store reader + entity.requestContext.timeoutHelper = new TimeoutHelper(Duration.ofSeconds(2 * 60 * 60 + 2 * 60 + 2)); + + // when the store reader throws INVALID Partition exception, the higher layer should + entity.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + + AddressInformation[] addressInformations = getMockAddressInformationDuringUpgrade(); + IAddressResolver mockAddressCache = getMockAddressCache(addressInformations); + + // validate that the mock works + AddressInformation[] addressInfo = mockAddressCache.resolveAsync(entity, false).block(); + assertThat(addressInfo[0]).isEqualTo(addressInformations[0]); + + AddressSelector addressSelector = new AddressSelector(mockAddressCache, Protocol.TCP); + URI primaryAddress = addressSelector.resolvePrimaryUriAsync(entity, false).block(); + + // check if the address return from Address Selector matches the original address info + assertThat(primaryAddress.toString()).isEqualTo(addressInformations[0].getPhysicalUri()); + + // get mock transport client that returns a sequence of responses to simulate upgrade + TransportClient mockTransportClient = getMockTransportClientDuringUpgrade(addressInformations); + + // get response from mock object + StoreResponse response = mockTransportClient.invokeResourceOperationAsync(new URI(addressInformations[0].getPhysicalUri()), entity).block(); + + // validate that the LSN matches + assertThat(response.getLSN()).isEqualTo(50); + + String activityId = response.getHeaderValue(WFConstants.BackendHeaders.ACTIVITY_ID); + // validate that the ActivityId Matches + assertThat(activityId).isEqualTo("ACTIVITYID1_1"); + + // create a real session container - we don't need session for this test anyway + SessionContainer sessionContainer = new SessionContainer(StringUtils.EMPTY); + + // create store reader with mock transport client, real address selector (that has mock address cache), and real session container + StoreReader storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + + IAuthorizationTokenProvider mockAuthorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + Mockito.when(mockAuthorizationTokenProvider.getUserAuthorizationToken(Matchers.anyString(), Matchers.any(), Matchers.anyString(), Matchers.anyMap(), + Matchers.any(), Matchers.anyMap())).thenReturn("dummyauthtoken"); + + // setup max replica set size on the config reader + ReplicationPolicy replicationPolicy = new ReplicationPolicy(); + GatewayServiceConfigurationReader mockServiceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + Mockito.when(mockServiceConfigReader.getUserReplicationPolicy()).thenReturn(replicationPolicy); + + try { + StoreClient storeClient = new StoreClient(new Configs(),mockAddressCache, sessionContainer, mockServiceConfigReader, mockAuthorizationTokenProvider, mockTransportClient, false); + + ServerStoreModel storeModel = new ServerStoreModel(storeClient); + Mono result = storeModel.processMessage(entity).single(); + result.block(); + + // if we have reached this point, there was a successful request. + // validate if the target identity has been cleared out. + // If the target identity is null and the request still succeeded, it means + // that the very first read succeeded without a barrier request. + assertThat(entity.requestContext.resolvedPartitionKeyRange).isNotNull(); + } catch (Exception e) { + assertThat(e instanceof ServiceUnavailableException + || e instanceof IllegalArgumentException + || e instanceof NullPointerException + || e instanceof NoSuchElementException).isTrue(); + } + } + + /** + * test consistency writer for global strong + */ + @Test(groups = "unit") + public void globalStrongConsistentWrite() { + // create a real document service request (with auth token level = god) + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document); + entity.authorizationTokenType = AuthorizationTokenType.PrimaryMasterKey; + + // set request charge tracker - this is referenced in store reader (ReadMultipleReplicaAsync) + DocumentServiceRequestContext requestContext = new DocumentServiceRequestContext(); + requestContext.requestChargeTracker = new RequestChargeTracker(); + entity.requestContext = requestContext; + + // set a dummy resource id on the request. + entity.setResourceId("1-MxAPlgMgA="); + + // set consistency level on the request to Bounded Staleness + entity.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.STRONG.toString()); + + // also setup timeout helper, used in store reader + entity.requestContext.timeoutHelper = new TimeoutHelper(Duration.ofSeconds(2 * 60 * 60 + 2 * 60 + 2)); + + // when the store reader throws INVALID Partition exception, the higher layer should + // clear this target identity. + entity.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + + AddressInformation[] addressInformations = getMockAddressInformationDuringUpgrade(); + IAddressResolver mockAddressCache = getMockAddressCache(addressInformations); + + // validate that the mock works + AddressInformation[] addressInfo = mockAddressCache.resolveAsync(entity, false).block(); + assertThat(addressInformations[0]).isEqualTo(addressInfo[0]); + + AddressSelector addressSelector = new AddressSelector(mockAddressCache, Protocol.TCP); + URI primaryAddress = addressSelector.resolvePrimaryUriAsync(entity, false).block(); + + // check if the address return from Address Selector matches the original address info + assertThat(primaryAddress.toString()).isEqualTo(addressInformations[0].getPhysicalUri()); + + // create a real session container - we don't need session for this test anyway + SessionContainer sessionContainer = new SessionContainer(StringUtils.EMPTY); + GatewayServiceConfigurationReader serviceConfigurationReader = Mockito.mock(GatewayServiceConfigurationReader.class); + + IAuthorizationTokenProvider mockAuthorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + Mockito.when(mockAuthorizationTokenProvider.getUserAuthorizationToken(Matchers.anyString(),Matchers.any(), Matchers.anyString(), Matchers.anyMap(), + Matchers.any(), Matchers.anyMap())).thenReturn("dummyauthtoken"); + + for (int i = 0; i < addressInformations.length; i++) { + TransportClient mockTransportClient = getMockTransportClientForGlobalStrongWrites(addressInformations, i, false, false, false); + StoreReader storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + ConsistencyWriter consistencyWriter = new ConsistencyWriter(addressSelector, sessionContainer, mockTransportClient, mockAuthorizationTokenProvider, serviceConfigurationReader, false); + StoreResponse response = consistencyWriter.writeAsync(entity, new TimeoutHelper(Duration.ofSeconds(30)), false).block(); + assertThat(response.getLSN()).isEqualTo(100); + + //globalCommittedLsn never catches up in this case + mockTransportClient = getMockTransportClientForGlobalStrongWrites(addressInformations, i, true, false, false); + consistencyWriter = new ConsistencyWriter(addressSelector, sessionContainer, mockTransportClient, mockAuthorizationTokenProvider, serviceConfigurationReader, false); + try { + response = consistencyWriter.writeAsync(entity, new TimeoutHelper(Duration.ofSeconds(30)), false).block(); + // fail("it should throw exception"); + } catch (Exception e) { + } + + mockTransportClient = getMockTransportClientForGlobalStrongWrites(addressInformations, i, false, true, false); + storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + consistencyWriter = new ConsistencyWriter(addressSelector, sessionContainer, mockTransportClient, mockAuthorizationTokenProvider, serviceConfigurationReader, false); + response = consistencyWriter.writeAsync(entity, new TimeoutHelper(Duration.ofSeconds(30)), false).block(); + assertThat(response.getLSN()).isEqualTo(100); + + mockTransportClient = getMockTransportClientForGlobalStrongWrites(addressInformations, i, false, true, true); + storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + consistencyWriter = new ConsistencyWriter(addressSelector, sessionContainer, mockTransportClient, mockAuthorizationTokenProvider, serviceConfigurationReader, false); + response = consistencyWriter.writeAsync(entity, new TimeoutHelper(Duration.ofSeconds(30)), false).block(); + assertThat(response.getLSN()).isEqualTo(100); + + + mockTransportClient = getMockTransportClientForGlobalStrongWrites(addressInformations, i, false, false, true); + storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + consistencyWriter = new ConsistencyWriter(addressSelector, sessionContainer, mockTransportClient, mockAuthorizationTokenProvider, serviceConfigurationReader, false); + response = consistencyWriter.writeAsync(entity, new TimeoutHelper(Duration.ofSeconds(30)), false).block(); + assertThat(response.getLSN()).isEqualTo(100); + + } + } + + /** + * Mocking Consistency + */ + @Test(groups = "unit", priority = 1) + public void globalStrongConsistency() { + // create a real document service request (with auth token level = god) + RxDocumentServiceRequest entity = RxDocumentServiceRequest.create(OperationType.Read, ResourceType.Document); + entity.authorizationTokenType = AuthorizationTokenType.PrimaryMasterKey; + + // set request charge tracker - this is referenced in store reader (ReadMultipleReplicaAsync) + DocumentServiceRequestContext requestContext = new DocumentServiceRequestContext(); + requestContext.requestChargeTracker = new RequestChargeTracker(); + entity.requestContext = requestContext; + + // set a dummy resource id on the request. + entity.setResourceId("1-MxAPlgMgA="); + + // set consistency level on the request to Bounded Staleness + entity.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.BOUNDED_STALENESS.toString()); + + // also setup timeout helper, used in store reader + entity.requestContext.timeoutHelper = new TimeoutHelper(Duration.ofSeconds(2 * 60 * 60 + 2 * 60 + 2)); + + // when the store reader throws INVALID Partition exception, the higher layer should + // clear this target identity. + entity.requestContext.resolvedPartitionKeyRange = new PartitionKeyRange(); + + AddressInformation[] addressInformations = getMockAddressInformationDuringUpgrade(); + IAddressResolver mockAddressCache = getMockAddressCache(addressInformations); + + // validate that the mock works + AddressInformation[] addressInfo = mockAddressCache.resolveAsync(entity, false).block(); + assertThat(addressInfo[0]).isEqualTo(addressInformations[0]); + + AddressSelector addressSelector = new AddressSelector(mockAddressCache, Protocol.TCP); + URI primaryAddress = addressSelector.resolvePrimaryUriAsync(entity, false).block(); + + // check if the address return from Address Selector matches the original address info + assertThat(primaryAddress.toString()).isEqualTo(addressInformations[0].getPhysicalUri()); + + // Quorum Met scenario Start + { + // get mock transport client that returns a sequence of responses to simulate upgrade + TransportClient mockTransportClient = getMockTransportClientForGlobalStrongReads(addressInformations, ReadQuorumResultKind.QuorumMet); + + // create a real session container - we don't need session for this test anyway + SessionContainer sessionContainer = new SessionContainer(StringUtils.EMPTY); + + // create store reader with mock transport client, real address selector (that has mock address cache), and real session container + StoreReader storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + + IAuthorizationTokenProvider mockAuthorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + Mockito.when(mockAuthorizationTokenProvider.getUserAuthorizationToken(Matchers.anyString(), Matchers.any(), Matchers.anyString(), Matchers.anyMap(), + Matchers.any(), Matchers.anyMap())).thenReturn("dummyauthtoken"); + + // setup max replica set size on the config reader + ReplicationPolicy replicationPolicy = new ReplicationPolicy(); + GatewayServiceConfigurationReader mockServiceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + Mockito.when(mockServiceConfigReader.getUserReplicationPolicy()).thenReturn(replicationPolicy); + + QuorumReader reader = new QuorumReader(new Configs(),mockTransportClient, addressSelector, storeReader, mockServiceConfigReader, mockAuthorizationTokenProvider); + + entity.requestContext.originalRequestConsistencyLevel = ConsistencyLevel.STRONG; + + StoreResponse result = reader.readStrongAsync(entity, 2, ReadMode.Strong).block(); + assertThat(result.getLSN()).isEqualTo(100); + + String globalCommitedLSN = result.getHeaderValue(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN); + + long nGlobalCommitedLSN = Long.parseLong(globalCommitedLSN); + assertThat(nGlobalCommitedLSN).isEqualTo(90); + } + + // Quorum Selected scenario + { + // get mock transport client that returns a sequence of responses to simulate upgrade + TransportClient mockTransportClient = getMockTransportClientForGlobalStrongReads(addressInformations, ReadQuorumResultKind.QuorumSelected); + + // create a real session container - we don't need session for this test anyway + SessionContainer sessionContainer = new SessionContainer(StringUtils.EMPTY); + + // create store reader with mock transport client, real address selector (that has mock address cache), and real session container + StoreReader storeReader = new StoreReader(mockTransportClient, addressSelector, sessionContainer); + + IAuthorizationTokenProvider mockAuthorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + Mockito.when(mockAuthorizationTokenProvider.getUserAuthorizationToken(Matchers.anyString(), Matchers.any(), Matchers.anyString(), Matchers.anyMap(), + Matchers.any(), Matchers.anyMap())).thenReturn("dummyauthtoken"); + + // setup max replica set size on the config reader + ReplicationPolicy replicationPolicy = new ReplicationPolicy(); + BridgeInternal.setMaxReplicaSetSize(replicationPolicy,4); + + GatewayServiceConfigurationReader mockServiceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + Mockito.when(mockServiceConfigReader.getUserReplicationPolicy()).thenReturn(replicationPolicy); + Mockito.when(mockServiceConfigReader.getDefaultConsistencyLevel()).thenReturn(ConsistencyLevel.STRONG); + + QuorumReader reader = new QuorumReader(new Configs(), mockTransportClient, addressSelector, storeReader, mockServiceConfigReader, mockAuthorizationTokenProvider); + entity.requestContext.originalRequestConsistencyLevel = ConsistencyLevel.STRONG; + entity.requestContext.quorumSelectedLSN = -1; + entity.requestContext.globalCommittedSelectedLSN = -1; + try { + StoreResponse result = reader.readStrongAsync(entity, 2, ReadMode.Strong).block(); + assertThat(false).isTrue(); + } catch (Exception ex) { + if (ex.getCause() instanceof GoneException) { + logger.info("Gone exception expected!"); + } + } + + assertThat(entity.requestContext.quorumSelectedLSN).isEqualTo(100); + assertThat(entity.requestContext.globalCommittedSelectedLSN).isEqualTo(100); + } + + // Quorum not met scenario + { + // get mock transport client that returns a sequence of responses to simulate upgrade + TransportClient mockTransportClient = getMockTransportClientForGlobalStrongReads(addressInformations, ReadQuorumResultKind.QuorumNotSelected); + + // create a real session container - we don't need session for this test anyway + SessionContainer sessionContainer = new SessionContainer(StringUtils.EMPTY); + + // create store reader with mock transport client, real address selector (that has mock address cache), and real session container + StoreReader storeReader = + new StoreReader(mockTransportClient, + addressSelector, + sessionContainer); + + IAuthorizationTokenProvider mockAuthorizationTokenProvider = Mockito.mock(IAuthorizationTokenProvider.class); + Mockito.when(mockAuthorizationTokenProvider.getUserAuthorizationToken(Matchers.anyString(), Matchers.any(), Matchers.anyString(), Matchers.anyMap(), + Matchers.any(), Matchers.anyMap())).thenReturn("dummyauthtoken"); + // setup max replica set size on the config reader + ReplicationPolicy replicationPolicy = new ReplicationPolicy(); + BridgeInternal.setMaxReplicaSetSize(replicationPolicy,4); + + GatewayServiceConfigurationReader mockServiceConfigReader = Mockito.mock(GatewayServiceConfigurationReader.class); + Mockito.when(mockServiceConfigReader.getUserReplicationPolicy()).thenReturn(replicationPolicy); + Mockito.when(mockServiceConfigReader.getDefaultConsistencyLevel()).thenReturn(ConsistencyLevel.STRONG); + + QuorumReader reader = new QuorumReader(new Configs(), mockTransportClient, addressSelector, storeReader, mockServiceConfigReader, mockAuthorizationTokenProvider); + entity.requestContext.originalRequestConsistencyLevel = ConsistencyLevel.STRONG; + entity.requestContext.performLocalRefreshOnGoneException = true; + + StoreResponse result = reader.readStrongAsync(entity, 2, ReadMode.Strong).block(); + assertThat(result.getLSN()).isEqualTo(100); + + String globalCommitedLSN; + globalCommitedLSN = result.getHeaderValue(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN); + long nGlobalCommitedLSN = Long.parseLong(globalCommitedLSN); + assertThat(nGlobalCommitedLSN).isEqualTo(90); + } + + } + + // TODO: more mocking unit tests for different scenarios in StoreReader + // TODO: more mocking tests on how session work for StoreReader +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderTest.java new file mode 100644 index 0000000000000..af3c084974043 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderTest.java @@ -0,0 +1,814 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.GoneException; +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.PartitionKeyRangeGoneException; +import com.azure.data.cosmos.RequestRateTooLargeException; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.NotFoundException; +import com.azure.data.cosmos.PartitionIsMigratingException; +import com.azure.data.cosmos.PartitionKeyRangeIsSplittingException; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.assertj.core.api.AssertionsForClassTypes; +import org.mockito.Mockito; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.DirectProcessor; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; + +import static com.azure.data.cosmos.internal.HttpConstants.StatusCodes.GONE; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.COMPLETING_PARTITION_MIGRATION; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.COMPLETING_SPLIT; +import static com.azure.data.cosmos.internal.HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE; +import static org.assertj.core.api.Assertions.assertThat; + +public class StoreReaderTest { + private static final int TIMEOUT = 30000; + + + /** + * Tests for {@link StoreReader} + */ + @Test(groups = "unit") + public void startBackgroundAddressRefresh() throws Exception { + TransportClient transportClient = Mockito.mock(TransportClient.class); + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + StoreReader storeReader = new StoreReader(transportClient, addressSelector, sessionContainer); + + CyclicBarrier b = new CyclicBarrier(2); + DirectProcessor> subject = DirectProcessor.create(); + CountDownLatch c = new CountDownLatch(1); + + List uris = ImmutableList.of(URI.create("https://localhost:5050"), URI.create("https://localhost:5051"), + URI.create("https://localhost:50502"), URI.create("https://localhost:5053")); + + Mockito.doAnswer(invocationOnMock -> subject.single().doOnSuccess(x -> c.countDown()).doAfterTerminate(() -> new Thread() { + @Override + public void run() { + try { + b.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }.start())).when(addressSelector).resolveAllUriAsync(Mockito.any(RxDocumentServiceRequest.class), Mockito.eq(true), Mockito.eq(true)); + RxDocumentServiceRequest request = Mockito.mock(RxDocumentServiceRequest.class); + storeReader.startBackgroundAddressRefresh(request); + + subject.onNext(uris); + subject.onComplete(); + + TimeUnit.MILLISECONDS.sleep(100); + AssertionsForClassTypes.assertThat(c.getCount()).isEqualTo(0); + AssertionsForClassTypes.assertThat(b.getNumberWaiting()).isEqualTo(1); + b.await(1000, TimeUnit.MILLISECONDS); + } + + @DataProvider(name = "verifyCanContinueOnExceptionArgProvider") + public Object[][] verifyCanContinueOnExceptionArgProvider() { + return new Object[][]{ + {new PartitionKeyRangeGoneException(), false,}, + {new PartitionKeyRangeIsSplittingException(), false,}, + {new PartitionKeyRangeGoneException(), false,}, + {new PartitionIsMigratingException(), false,}, + {new GoneException(), true,}, + {ExceptionBuilder.create().withHeader(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "").asGoneException(), true,}, + {ExceptionBuilder.create().withHeader(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "0").asGoneException(), true,}, + {ExceptionBuilder.create().withHeader(HttpConstants.HttpHeaders.REQUEST_VALIDATION_FAILURE, "1").asGoneException(), false,}, + }; + } + + @Test(groups = "unit", dataProvider = "verifyCanContinueOnExceptionArgProvider") + public void verifyCanContinueOnException(CosmosClientException dce, Boolean shouldVerify) { + CosmosClientException capturedFailure = null; + try { + StoreReader.verifyCanContinueOnException(dce); + } catch (CosmosClientException e) { + capturedFailure = e; + } + + if (shouldVerify) { + assertThat(capturedFailure).isNull(); + } else { + assertThat(capturedFailure).isEqualTo(dce); + } + } + + @DataProvider(name = "exceptionArgProvider") + public Object[][] exceptionArgProvider() { + return new Object[][]{ + // exception to be thrown from transportClient, expected (exception type, status, subStatus) + { new PartitionKeyRangeGoneException(), PartitionKeyRangeGoneException.class, GONE, PARTITION_KEY_RANGE_GONE, }, + { new PartitionKeyRangeIsSplittingException() , PartitionKeyRangeIsSplittingException.class, GONE, COMPLETING_SPLIT, }, + { new PartitionIsMigratingException(), PartitionIsMigratingException.class, GONE, COMPLETING_PARTITION_MIGRATION, }, + }; + } + + @Test(groups = "unit", dataProvider = "exceptionArgProvider") + public void exception(Exception ex, Class klass, int expectedStatusCode, Integer expectedSubStatusCode) { + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(ex) + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("1"); + Mono> res = storeReader.readMultipleReplicaAsync(dsr, true, 3, true, true, ReadMode.Strong); + + FailureValidator failureValidator = FailureValidator.builder() + .instanceOf(klass) + .statusCode(expectedStatusCode) + .subStatusCode(expectedSubStatusCode) + .build(); + + TestSubscriber> subscriber = new TestSubscriber<>(); + res.subscribe(subscriber); + subscriber.awaitTerminalEvent(); + subscriber.assertNotComplete(); + assertThat(subscriber.errorCount()).isEqualTo(1); + failureValidator.validate(subscriber.errors().get(0)); + } + + /** + * reading in session consistency, if the requested session token cannot be supported by some replicas + * tries others till we find a replica which can support the given session token + */ + @Test(groups = "unit") + public void sessionNotAvailableFromSomeReplicas_FindReplicaSatisfyingRequestedSession() { + long slowReplicaLSN = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + slowReplicaLSN); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(slowReplicaLSN)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(slowReplicaLSN)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + long fasterReplicaLSN = 651176; + + StoreResponse storeResponse = StoreResponseBuilder.create() + .withSessionToken(partitionKeyRangeId + ":-1#" + fasterReplicaLSN) + .withLSN(fasterReplicaLSN) + .withLocalLSN(fasterReplicaLSN) + .withQuorumAckecdLsn(fasterReplicaLSN) + .withQuorumAckecdLocalLsn(fasterReplicaLSN) + .withGlobalCommittedLsn(-1) + .withItemLocalLSN(fasterReplicaLSN) + .withRequestCharge(1.1) + .build(); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read returns not found with lower lsn + .then(foundException) // 2nd replica read returns not found with lower lsn + .then(foundException) // 3rd replica read returns not found with lower lsn + .then(storeResponse) // 4th replica read returns storeResponse satisfying requested session token + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + dsr.requestContext.sessionToken = sessionToken.v; + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + assertThat(VectorSessionToken.tryCreate("-1#" + fasterReplicaLSN , sessionToken)).isTrue(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Mono> readResult = storeReader.readMultipleReplicaAsync( + dsr, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN */ true, + /* useSessionToken */ true, + /* readMode */ ReadMode.Any, + /* checkMinLsn */ true, + /* forceReadAll */ false); + + MultiStoreResultValidator validator = MultiStoreResultValidator.create() + .withSize(1) + .validateEachWith(StoreResultValidator.create() + .isValid() + .noException() + .withStoreResponse(StoreResponseValidator.create() + .isSameAs(storeResponse) + .build()) + .build()) + .build(); + validateSuccess(readResult, validator); + + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1); + } + + /** + * Reading with session consistency, replicas have session token with higher than requested and return not found + */ + @Test(groups = "unit") + public void sessionRead_LegitimateNotFound() { + long lsn = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read returns not found + .then(foundException) // 2nd replica read returns not found + .then(foundException) // 3rd replica read returns not found + .then(foundException) // 4th replica read returns not found + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + dsr.requestContext.sessionToken = sessionToken.v; + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + assertThat(VectorSessionToken.tryCreate("-1#" + (lsn - 1) , sessionToken)).isTrue(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Mono> readResult = storeReader.readMultipleReplicaAsync( + dsr, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN */ true, + /* useSessionToken */ true, + /* readMode */ ReadMode.Any, + /* checkMinLsn */ true, + /* forceReadAll */ false); + + MultiStoreResultValidator validator = MultiStoreResultValidator.create() + .withSize(1) + .validateEachWith(StoreResultValidator.create() + .isValid() + .withException(FailureValidator.builder().instanceOf(NotFoundException.class).build()) + .build()) + .build(); + validateSuccess(readResult, validator); + } + + /** + * reading in session consistency, none of the replicas can support the requested session token. + */ + @Test(groups = "unit") + public void sessionRead_ReplicasDoNotHaveTheRequestedLSN_NoResult() { + long lsn = 651175; + long globalCommittedLsn = 651174; + String partitionKeyRangeId = "73"; + + NotFoundException foundException = new NotFoundException(); + foundException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(lsn)); + foundException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(foundException) // 1st replica read returns not found + .then(foundException) // 2nd replica read returns not found + .then(foundException) // 3rd replica read returns not found + .then(foundException) // 4th replica read returns not found + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + dsr.requestContext.sessionToken = sessionToken.v; + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId(partitionKeyRangeId); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + assertThat(VectorSessionToken.tryCreate("-1#" + (lsn + 1) , sessionToken)).isTrue(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Mono> readResult = storeReader.readMultipleReplicaAsync( + dsr, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN */ true, + /* useSessionToken */ true, + /* readMode */ ReadMode.Any, + /* checkMinLsn */ true, + /* forceReadAll */ false); + + MultiStoreResultValidator validator = MultiStoreResultValidator.create() + .withSize(0) + .build(); + validateSuccess(readResult, validator); + } + + @Test(groups = "unit") + public void requestRateTooLarge_BubbleUp() { + long lsn = 1045395; + long globalCommittedLsn = 1045395; + String partitionKeyRangeId = "257"; + + RequestRateTooLargeException requestRateTooLargeException = new RequestRateTooLargeException(); + requestRateTooLargeException.responseHeaders().put(HttpConstants.HttpHeaders.LSN, Long.toString(lsn)); + requestRateTooLargeException.responseHeaders().put(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, Long.toString(globalCommittedLsn)); + requestRateTooLargeException.responseHeaders().put(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(lsn)); + requestRateTooLargeException.responseHeaders().put(HttpConstants.HttpHeaders.SESSION_TOKEN, partitionKeyRangeId + ":-1#" + lsn); + + TransportClientWrapper transportClientWrapper = new TransportClientWrapper.Builder.ReplicaResponseBuilder + .SequentialBuilder() + .then(requestRateTooLargeException) // 1st replica read returns 429 + .then(requestRateTooLargeException) // 2nd replica read returns 429 + .then(requestRateTooLargeException) // 3rd replica read returns 429 + .then(requestRateTooLargeException) // 4th replica read returns 429 + .build(); + + URI primaryUri = URI.create("primary"); + URI secondaryUri1 = URI.create("secondary1"); + URI secondaryUri2 = URI.create("secondary2"); + URI secondaryUri3 = URI.create("secondary3"); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryUri) + .withSecondary(ImmutableList.of(secondaryUri1, secondaryUri2, secondaryUri3)) + .build(); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + TimeoutHelper timeoutHelper = Mockito.mock(TimeoutHelper.class); + RxDocumentServiceRequest dsr = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + dsr.getHeaders().put(HttpConstants.HttpHeaders.CONSISTENCY_LEVEL, ConsistencyLevel.SESSION.toString()); + dsr.requestContext = new DocumentServiceRequestContext(); + Utils.ValueHolder sessionToken = Utils.ValueHolder.initialize(null); + dsr.requestContext.sessionToken = sessionToken.v; + dsr.requestContext.timeoutHelper = timeoutHelper; + dsr.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("1"); + dsr.requestContext.requestChargeTracker = new RequestChargeTracker(); + assertThat(VectorSessionToken.tryCreate("-1#" + (lsn - 1) , sessionToken)).isTrue(); + + Mockito.doReturn(sessionToken.v).when(sessionContainer).resolvePartitionLocalSessionToken(Mockito.eq(dsr), Mockito.anyString()); + + Mono> readResult = storeReader.readMultipleReplicaAsync( + dsr, + /* includePrimary */ true, + /* replicaCountToRead */ 1, + /* requiresValidLSN */ true, + /* useSessionToken */ true, + /* readMode */ ReadMode.Any, + /* checkMinLsn */ true, + /* forceReadAll */ false); + + MultiStoreResultValidator validator = MultiStoreResultValidator.create() + .withSize(1) + .validateEachWith(FailureValidator.builder().instanceOf(RequestRateTooLargeException.class).build()) + .build(); + validateSuccess(readResult, validator); + } + + @Test(groups = "unit") + public void readPrimaryAsync() { + TransportClient transportClient = Mockito.mock(TransportClient.class); + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + URI primaryURI = URI.create("primaryLoc"); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("12"); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(Mono.just(primaryURI)).when(addressSelector).resolvePrimaryUriAsync( + Mockito.eq(request) , Mockito.eq(false)); + + StoreResponse storeResponse = Mockito.mock(StoreResponse.class); + Mockito.doReturn(Mono.just(storeResponse)).when(transportClient).invokeResourceOperationAsync(Mockito.eq(primaryURI), Mockito.eq(request)); + + StoreReader storeReader = new StoreReader(transportClient, addressSelector, sessionContainer); + + Mono readResult = storeReader.readPrimaryAsync(request, true, true); + StoreResultValidator validator = StoreResultValidator.create() + .withStoreResponse(StoreResponseValidator.create().isSameAs(storeResponse).build()) + .build(); + validateSuccess(readResult, validator); + } + + @Test(groups = "unit") + public void readPrimaryAsync_GoneFromReplica() { + TransportClient transportClient = Mockito.mock(TransportClient.class); + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + URI primaryURI = URI.create("primaryLoc"); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("12"); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(Mono.just(primaryURI)).when(addressSelector).resolvePrimaryUriAsync( + Mockito.eq(request) , Mockito.eq(false)); + + Mockito.doReturn(Mono.error(ExceptionBuilder.create().asGoneException())).when(transportClient).invokeResourceOperationAsync(Mockito.eq(primaryURI), Mockito.eq(request)); + StoreReader storeReader = new StoreReader(transportClient, addressSelector, sessionContainer); + Mono readResult = storeReader.readPrimaryAsync(request, true, true); + + FailureValidator validator = FailureValidator.builder().instanceOf(GoneException.class).build(); + validateException(readResult, validator); + } + + @Test(groups = "unit") + public void readPrimaryAsync_GoneExceptionOnTimeout() { + TransportClient transportClient = Mockito.mock(TransportClient.class); + AddressSelector addressSelector = Mockito.mock(AddressSelector.class); + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + + URI primaryURI = URI.create("primaryLoc"); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + Mockito.doReturn(true).when(request.requestContext.timeoutHelper).isElapsed(); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("12"); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + Mockito.doReturn(Mono.just(primaryURI)).when(addressSelector).resolvePrimaryUriAsync( + Mockito.eq(request) , Mockito.eq(false)); + + StoreResponse storeResponse = Mockito.mock(StoreResponse.class); + Mockito.doReturn(Mono.just(storeResponse)).when(transportClient).invokeResourceOperationAsync(Mockito.eq(primaryURI), Mockito.eq(request)); + + StoreReader storeReader = new StoreReader(transportClient, addressSelector, sessionContainer); + + Mono readResult = storeReader.readPrimaryAsync(request, true, true); + FailureValidator validator = FailureValidator.builder().instanceOf(GoneException.class).build(); + validateException(readResult, validator); + } + + @DataProvider(name = "readPrimaryAsync_RetryOnGoneArgProvider") + public Object[][] readPrimaryAsync_RetryOnGoneArgProvider() { + return new Object[][]{ + // first exception from TransportClient, + // performLocalRefreshOnGoneException, + // retry with force refresh expected, + // validator for expected Exception from Single + // StoreResult has a successful StoreResponse + { + // partition moved, refresh replica address cache and retry + ExceptionBuilder.create().asGoneException(), true, true, null, true + }, + + { + // partition moved, refresh replica address cache is not requested, fail + ExceptionBuilder.create().asGoneException(), false, false, FailureValidator.builder().instanceOf(GoneException.class).build(), false + }, + + { + // invalid partition exception represents collection stale, cannot succeed, propagate failure + ExceptionBuilder.create().asInvalidPartitionException(), true, false, null, false + }, + + { + // cannot continue on partition key range gone, require address cache refresh + ExceptionBuilder.create().asPartitionKeyRangeGoneException(), true, false, + FailureValidator.builder().instanceOf(PartitionKeyRangeGoneException.class).build(), true + }, + + { + // cannot continue on partition split, require address cache refresh + ExceptionBuilder.create().asPartitionKeyRangeIsSplittingException(), true, false, + FailureValidator.builder().instanceOf(PartitionKeyRangeIsSplittingException.class).build(), true + }, + + { + // cannot continue on partition split, require address cache refresh + ExceptionBuilder.create().asPartitionIsMigratingException(), true, false, + FailureValidator.builder().instanceOf(PartitionIsMigratingException.class).build(), true + }, + }; + } + + @Test(groups = "unit", dataProvider = "readPrimaryAsync_RetryOnGoneArgProvider") + public void readPrimaryAsync_RetryOnPrimaryReplicaMove(Exception firstExceptionFromTransport, + boolean performLocalRefreshOnGoneException, + boolean retryWithForceRefreshExpected, + FailureValidator failureFromSingle, + boolean expectedStoreResponseInStoredReadResult) { + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + StoreResponse response = StoreResponseBuilder.create().build(); + + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.sequentialBuilder() + .then(firstExceptionFromTransport) + .then(response) + .build(); + + URI primaryURIPriorToRefresh = URI.create("stale"); + URI primaryURIAfterRefresh = URI.create("new"); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext.performLocalRefreshOnGoneException = performLocalRefreshOnGoneException; + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("12"); + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.PrimaryReplicaMoveBuilder.create(Protocol.HTTPS) + .withPrimaryReplicaMove(primaryURIPriorToRefresh, primaryURIAfterRefresh).build(); + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + Mono readResult = storeReader.readPrimaryAsync(request, true, true); + + if (failureFromSingle == null) { + StoreResultValidator validator; + if (expectedStoreResponseInStoredReadResult) { + validator = StoreResultValidator.create().withStoreResponse(StoreResponseValidator.create().isSameAs(response).build()).build(); + } else { + validator = StoreResultValidator.create().withException(FailureValidator.builder().sameAs(firstExceptionFromTransport).build()).build(); + } + + validateSuccess(readResult, validator); + } else { + validateException(readResult, failureFromSingle); + } + + int numberOfAttempts = 1 + (retryWithForceRefreshExpected ? 1: 0); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(numberOfAttempts); + + addressSelectorWrapper.validate() + .verifyResolveAddressesAsync(0) + .verifyResolveAllUriAsync(0) + .verifyVesolvePrimaryUriAsyncCount(numberOfAttempts) + .verifyNumberOfForceCachRefresh(retryWithForceRefreshExpected ? 1: 0); + } + + @DataProvider(name = "readMultipleReplicasAsyncArgProvider") + public Object[][] readMultipleReplicasAsyncArgProvider() { + return new Object[][]{ + // boolean includePrimary, int replicaCountToRead, ReadMode.STRONG + { false, 3, ReadMode.Strong }, + { true, 3, ReadMode.Strong }, + { false, 3, ReadMode.Any }, + { true, 3, ReadMode.Any }, + { true, 2, ReadMode.Any }, + { false, 2, ReadMode.Any }, + { true, 1, ReadMode.Any }, + { false, 1, ReadMode.Any }, + }; + } + + @Test(groups = "unit", dataProvider = "readMultipleReplicasAsyncArgProvider") + public void readMultipleReplicasAsync(boolean includePrimary, int replicaCountToRead, ReadMode readMode) { + // This adds basic tests for StoreReader.readMultipleReplicasAsync(.) without failure + // TODO: add some tests for readMultipleReplicasAsync which mock behaviour of failure of reading from a replica + ISessionContainer sessionContainer = Mockito.mock(ISessionContainer.class); + URI primaryReplicaURI = URI.create("primary"); + ImmutableList secondaryReplicaURIs = ImmutableList.of(URI.create("secondary1"), URI.create("secondary2"), URI.create("secondary3")); + AddressSelectorWrapper addressSelectorWrapper = AddressSelectorWrapper.Builder.Simple.create() + .withPrimary(primaryReplicaURI) + .withSecondary(secondaryReplicaURIs) + .build(); + + RxDocumentServiceRequest request = RxDocumentServiceRequest.createFromName( + OperationType.Read, "/dbs/db/colls/col/docs/docId", ResourceType.Document); + + request.requestContext = Mockito.mock(DocumentServiceRequestContext.class); + request.requestContext.timeoutHelper = Mockito.mock(TimeoutHelper.class); + request.requestContext.resolvedPartitionKeyRange = partitionKeyRangeWithId("12"); + + request.requestContext.requestChargeTracker = new RequestChargeTracker(); + + double requestChargePerRead = 1.1; + + StoreResponse primaryResponse = StoreResponseBuilder.create() + .withLSN(51) + .withLocalLSN(18) + .withRequestCharge(requestChargePerRead) + .build(); + StoreResponse secondaryResponse1 = StoreResponseBuilder.create() + .withLSN(50) + .withLocalLSN(17) + .withRequestCharge(requestChargePerRead) + .build(); + StoreResponse secondaryResponse2 = StoreResponseBuilder.create() + .withLSN(49) + .withLocalLSN(16) + .withRequestCharge(requestChargePerRead) + .build(); + StoreResponse secondaryResponse3 = StoreResponseBuilder.create() + .withLSN(48) + .withLocalLSN(15) + .withRequestCharge(requestChargePerRead) + .build(); + + List responseList = ImmutableList.of(primaryResponse, secondaryResponse1, secondaryResponse2, secondaryResponse3); + + TransportClientWrapper transportClientWrapper = TransportClientWrapper.Builder.uriToResultBuilder() + .storeResponseOn(primaryReplicaURI, OperationType.Read, ResourceType.Document, primaryResponse, false) + .storeResponseOn(secondaryReplicaURIs.get(0), OperationType.Read, ResourceType.Document, secondaryResponse1, false) + .storeResponseOn(secondaryReplicaURIs.get(1), OperationType.Read, ResourceType.Document, secondaryResponse2, false) + .storeResponseOn(secondaryReplicaURIs.get(2), OperationType.Read, ResourceType.Document, secondaryResponse3, false) + .build(); + + StoreReader storeReader = new StoreReader(transportClientWrapper.transportClient, addressSelectorWrapper.addressSelector, sessionContainer); + + Mono> readResult = storeReader.readMultipleReplicaAsync(request, includePrimary, replicaCountToRead, true, true, readMode); + + long expectedMinLsn = + responseList + .stream() + .filter(sr -> (sr != primaryResponse || includePrimary)) + .mapToLong(sr -> + { + String value = (ReadMode.Strong == readMode)? + sr.getHeaderValue(WFConstants.BackendHeaders.LSN) : + sr.getHeaderValue(WFConstants.BackendHeaders.LOCAL_LSN); + return Long.parseLong(value); + }) + .min().orElse(-1); + + + MultiStoreResultValidator validator = MultiStoreResultValidator.create() + .withSize(replicaCountToRead) + .withMinimumLSN(expectedMinLsn) + .noFailure() + .withTotalRequestCharge(requestChargePerRead * replicaCountToRead) + .build(); + validateSuccess(readResult, validator); + + transportClientWrapper.validate() + .verifyNumberOfInvocations(replicaCountToRead); + addressSelectorWrapper.validate() + .verifyNumberOfForceCachRefresh(0) + .verifyVesolvePrimaryUriAsyncCount(0) + .verifyTotalInvocations(1); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono> single, + MultiStoreResultValidator validator, long timeout) { + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + single.flux().subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateSuccess(Mono single, + StoreResultValidator validator) { + validateSuccess(single, validator, 10000); + } + + public static void validateSuccess(Mono single, + StoreResultValidator validator, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public static void validateException(Mono single, + FailureValidator validator, long timeout) { + TestSubscriber testSubscriber = new TestSubscriber<>(); + + single.flux().subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errorCount()).isEqualTo(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + public static void validateException(Mono single, + FailureValidator validator) { + validateException(single, validator, TIMEOUT); + } + + private PartitionKeyRange partitionKeyRangeWithId(String id) { + PartitionKeyRange partitionKeyRange = Mockito.mock(PartitionKeyRange.class); + Mockito.doReturn(id).when(partitionKeyRange).id(); + return partitionKeyRange; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderUnderTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderUnderTest.java new file mode 100644 index 0000000000000..8577010c40243 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreReaderUnderTest.java @@ -0,0 +1,70 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.ISessionContainer; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.tuple.Pair; +import reactor.core.publisher.Mono; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class StoreReaderUnderTest extends StoreReader { + + public List>> invocations = Collections.synchronizedList(new ArrayList<>()); + + public StoreReaderUnderTest(TransportClient transportClient, AddressSelector addressSelector, ISessionContainer sessionContainer) { + super(transportClient, addressSelector, sessionContainer); + } + + @Override + public Mono> readMultipleReplicaAsync(RxDocumentServiceRequest entity, boolean includePrimary, int replicaCountToRead, boolean requiresValidLsn, boolean useSessionToken, ReadMode readMode) { + Method method = new Object(){}.getClass().getEnclosingMethod(); + ImmutableList list = ImmutableList.of(entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode); + invocations.add(Pair.of(method, list)); + + return super.readMultipleReplicaAsync(entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode); + } + + @Override + public Mono> readMultipleReplicaAsync(RxDocumentServiceRequest entity, boolean includePrimary, int replicaCountToRead, boolean requiresValidLsn, boolean useSessionToken, ReadMode readMode, boolean checkMinLSN, boolean forceReadAll) { + Method method = new Object(){}.getClass().getEnclosingMethod(); + ImmutableList list = ImmutableList.of(entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode, checkMinLSN, forceReadAll); + invocations.add(Pair.of(method, list)); + return super.readMultipleReplicaAsync(entity, includePrimary, replicaCountToRead, requiresValidLsn, useSessionToken, readMode, checkMinLSN, forceReadAll); + } + + @Override + public Mono readPrimaryAsync(RxDocumentServiceRequest entity, boolean requiresValidLsn, boolean useSessionToken) { + Method method = new Object(){}.getClass().getEnclosingMethod(); + ImmutableList list = ImmutableList.of(entity, requiresValidLsn, useSessionToken); + invocations.add(Pair.of(method, list)); + return super.readPrimaryAsync(entity, requiresValidLsn, useSessionToken); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseTest.java new file mode 100644 index 0000000000000..0659edbb8f1bf --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseTest.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.StoreResponse; +import org.apache.commons.io.IOUtils; +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StoreResponseTest { + @Test(groups = { "unit" }) + public void stringContent() { + String content = "I am body"; + HashMap headerMap = new HashMap<>(); + headerMap.put("key1", "value1"); + headerMap.put("key2", "value2"); + + StoreResponse sp = new StoreResponse(200, new ArrayList<>(headerMap.entrySet()), content); + + assertThat(sp.getStatus()).isEqualTo(200); + assertThat(sp.getResponseStream()).isNull(); + assertThat(sp.getResponseBody()).isEqualTo(content); + assertThat(sp.getHeaderValue("key1")).isEqualTo("value1"); + } + + @Test(groups = { "unit" }) + public void streamContent() throws Exception { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(new byte[] { 3, 0, 1, 9, -1, 125 }); + HashMap headerMap = new HashMap<>(); + headerMap.put("key1", "value1"); + headerMap.put("key2", "value2"); + + StoreResponse sp = new StoreResponse(200, new ArrayList<>(headerMap.entrySet()), new ByteArrayInputStream(baos.toByteArray())); + + assertThat(sp.getStatus()).isEqualTo(200); + assertThat(sp.getResponseBody()).isNull(); + assertThat(sp.getResponseStream()).isNotNull(); + assertThat(IOUtils.contentEquals(new ByteArrayInputStream(baos.toByteArray()), sp.getResponseStream())); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseValidator.java new file mode 100644 index 0000000000000..d30e68de2fa64 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResponseValidator.java @@ -0,0 +1,210 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.HttpConstants; +import org.assertj.core.api.Condition; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface StoreResponseValidator { + + void validate(StoreResponse storeResponse); + + public static Builder create() { + return new Builder(); + } + + public class Builder { + private List validators = new ArrayList<>(); + + public StoreResponseValidator build() { + return new StoreResponseValidator() { + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void validate(StoreResponse resp) { + for (StoreResponseValidator validator : validators) { + validator.validate(resp); + } + } + }; + } + public Builder hasHeader(String headerKey) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(Arrays.asList(resp.getResponseHeaderNames())).asList().contains(headerKey); + } + }); + return this; + } + public Builder withHeader(String headerKey, String headerValue) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(Arrays.asList(resp.getResponseHeaderNames())).asList().contains(headerKey); + int index = Arrays.asList(resp.getResponseHeaderNames()).indexOf(headerKey); + assertThat(resp.getResponseHeaderValues()[index]).isEqualTo(headerValue); + } + }); + return this; + } + + public Builder withHeaderValueCondition(String headerKey, Condition condition) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(Arrays.asList(resp.getResponseHeaderNames())).asList().contains(headerKey); + int index = Arrays.asList(resp.getResponseHeaderNames()).indexOf(headerKey); + String value = resp.getResponseHeaderValues()[index]; + condition.matches(value); + } + }); + return this; + } + + public Builder isSameAs(StoreResponse storeResponse) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(resp).isSameAs(storeResponse); + } + }); + return this; + } + + public Builder withContent(String content) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(content).isEqualTo(resp.getResponseBody()); + } + }); + return this; + } + + public Builder withStatus(int status) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(status == resp.getStatus()).isTrue(); + } + }); + return this; + } + + public Builder in(StoreResponse... storeResponse) { + + validators.add(new StoreResponseValidator() { + @Override + public void validate(StoreResponse resp) { + assertThat(resp).isIn((Object[]) storeResponse); + } + }); + return this; + } + + public Builder withBEActivityId(String activityId) { + withHeader(WFConstants.BackendHeaders.ACTIVITY_ID, activityId); + return this; + } + + public Builder withRequestCharge(double value) { + withHeader(HttpConstants.HttpHeaders.REQUEST_CHARGE, Double.toString(value)); + return this; + } + + public Builder withRequestChargeGreaterThanOrEqualTo(double value) { + withHeaderValueCondition(HttpConstants.HttpHeaders.REQUEST_CHARGE, new Condition<>(s -> { + try { + double parsed = Double.parseDouble(s); + return parsed >= value; + } catch (Exception e) { + return false; + } + }, "request charge should be greater than or equal to " + value)); + return this; + } + + public Builder withRequestChargeLessThanOrEqualTo(double value) { + withHeaderValueCondition(HttpConstants.HttpHeaders.REQUEST_CHARGE, new Condition<>(s -> { + try { + double parsed = Double.parseDouble(s); + return parsed <= value; + } catch (Exception e) { + return false; + } + }, "request charge should be greater than or equal to " + value)); + return this; + } + + + public Builder withBELSN(long lsn) { + withHeader(WFConstants.BackendHeaders.LSN, Long.toString(lsn)); + return this; + } + + public Builder withBELocalLSN(long lsn) { + withHeader(WFConstants.BackendHeaders.LOCAL_LSN, Long.toString(lsn)); + return this; + } + + public Builder withBELSNGreaterThanOrEqualTo(long minLSN) { + Condition condition = new Condition<>(value -> { + try { + Long valueAsLong = Long.parseLong(value); + return valueAsLong > minLSN; + } catch (Exception e) { + return false; + } + }, "min lsn"); + withHeaderValueCondition(WFConstants.BackendHeaders.LSN, condition); + return this; + } + + public Builder withBEGlobalLSNGreaterThanOrEqualTo(long minLSN) { + Condition condition = new Condition<>(value -> { + try { + Long valueAsLong = Long.parseLong(value); + return valueAsLong > minLSN; + } catch (Exception e) { + return false; + } + }, "min global lsn"); + withHeaderValueCondition(WFConstants.BackendHeaders.GLOBAL_COMMITTED_LSN, condition); + return this; + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResultValidator.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResultValidator.java new file mode 100644 index 0000000000000..1a8afa6d324a7 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/StoreResultValidator.java @@ -0,0 +1,180 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.FailureValidator; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.fail; + + +public interface StoreResultValidator { + + static Builder create() { + return new Builder(); + } + + void validate(StoreResult storeResult); + + class Builder { + private List validators = new ArrayList<>(); + + public StoreResultValidator build() { + return new StoreResultValidator() { + + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void validate(StoreResult storeResult) { + for (StoreResultValidator validator : validators) { + validator.validate(storeResult); + } + } + }; + } + + public Builder withStoreResponse(StoreResponseValidator storeResponseValidator) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + try { + storeResponseValidator.validate(storeResult.toResponse()); + }catch (CosmosClientException e) { + fail(e.getMessage()); + } + } + }); + return this; + } + + public Builder withException(FailureValidator failureValidator) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + try { + failureValidator.validate(storeResult.getException()); + }catch (CosmosClientException e) { + fail(e.getMessage()); + } + } + }); + return this; + } + + public Builder withLSN(long lsn) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.lsn).isEqualTo(lsn); + } + }); + return this; + } + + public Builder withMinLSN(long minLSN) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.lsn).isGreaterThanOrEqualTo(minLSN); + } + }); + return this; + } + + public Builder withGlobalCommitedLSN(long globalLsn) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.globalCommittedLSN).isEqualTo(globalLsn); + } + }); + return this; + } + + public Builder withQuorumAckedLsn(long quorumAckedLsn) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.quorumAckedLSN).isEqualTo(quorumAckedLsn); + } + }); + return this; + } + + public Builder noException() { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult).hasFieldOrPropertyWithValue("exception", null); + assertThat(storeResult.isGoneException).isFalse(); + } + }); + return this; + } + + public Builder isValid() { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.isValid).isTrue(); + } + }); + return this; + } + + public Builder withReplicaSize(int count) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.currentReplicaSetSize).isEqualTo(count); + } + }); + return this; + } + + public Builder withStorePhysicalURI(URI expectedURi) { + validators.add(new StoreResultValidator() { + + @Override + public void validate(StoreResult storeResult) { + assertThat(storeResult.storePhysicalAddress).isEqualTo(expectedURi); + } + }); + return this; + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelperTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelperTest.java new file mode 100644 index 0000000000000..ed66930532334 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TimeoutHelperTest.java @@ -0,0 +1,58 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.TimeoutHelper; +import org.testng.annotations.Test; + +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TimeoutHelperTest { + + @Test(groups = "unit") + public void isElapsed() throws InterruptedException { + Duration duration1 = Duration.ofMillis(100); + TimeoutHelper timeoutHelper1 = new TimeoutHelper(duration1); + assertThat(timeoutHelper1.isElapsed()).isFalse(); + + Duration duration2 = Duration.ofMillis(100); + TimeoutHelper timeoutHelper2 = new TimeoutHelper(duration2); + Thread.sleep(100); + assertThat(timeoutHelper2.isElapsed()).isTrue(); + } + + @Test(groups = "unit") + public void getRemainingTime() throws InterruptedException { + for (int i = 1; i <= 5; i++) { + Duration duration = Duration.ofMillis(100); + TimeoutHelper timeoutHelper = new TimeoutHelper(duration); + Thread.sleep((10*i)); + Duration remainingTime1 = timeoutHelper.getRemainingTime(); + //Giving 5 ms extra buffer in case thread sleep complete early + assertThat(remainingTime1.toMillis()).isLessThanOrEqualTo(100-10*i+5); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TransportClientWrapper.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TransportClientWrapper.java new file mode 100644 index 0000000000000..2319209fbc23f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/TransportClientWrapper.java @@ -0,0 +1,327 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.*; +import org.apache.commons.lang3.tuple.Pair; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TransportClientWrapper { + private static Logger logger = LoggerFactory.getLogger(TransportClientWrapper.class); + public final TransportClient transportClient; + private final AtomicBoolean valid; + private final AtomicInteger cnt; + private final List> requests; + + TransportClientWrapper(TransportClient transportClient, AtomicInteger cnt, AtomicBoolean valid, List> requests) { + this.transportClient = transportClient; + this.valid = valid; + this.cnt = cnt; + this.requests = requests; + } + + public static class TransportClientWrapperVerificationBuilder { + private List> actions = new ArrayList<>(); + + public static TransportClientWrapperVerificationBuilder create() { + return new TransportClientWrapperVerificationBuilder(); + } + + public TransportClientWrapperVerificationBuilder verifyNumberOfInvocations(int count) { + actions.add(transportClientWrapper -> { + assertThat(transportClientWrapper.getNumberOfInvocations()).isEqualTo(count); + return null; + }); + return this; + } + + public void execute(TransportClientWrapper transportClientWrapper) { + for(Function action: actions) { + action.apply(transportClientWrapper); + } + } + } + + public TransportClientWrapper verifyNumberOfInvocations(int count) { + assertThat(cnt.get()).isEqualTo(count); + return this; + } + + public List> getCapturedArgs() { + return requests; + } + + public int getNumberOfInvocations() { + return cnt.get(); + } + + public TransportClientWrapper validate() { + assertThat(valid).isTrue(); + return this; + } + + public interface Builder { + + static void capture(List> capturedRequests, InvocationOnMock invocation) { + URI physicalUri = invocation.getArgumentAt(0, URI.class); + RxDocumentServiceRequest request = invocation.getArgumentAt(1, RxDocumentServiceRequest.class); + logger.debug("URI: {}, request {}", physicalUri, request); + capturedRequests.add(Pair.of(physicalUri, request)); + } + + TransportClientWrapper build(); + + public static ReplicaResponseBuilder replicaResponseBuilder() { + return new ReplicaResponseBuilder(); + } + + class ReplicaResponseBuilder implements Builder { + Map responseFunctionDictionary = new HashMap<>(); + + public ReplicaResponseBuilder addReplica(URI replicaURI, + Function2WithCheckedException invocationNumberToStoreResponse) { + + responseFunctionDictionary.put(replicaURI, invocationNumberToStoreResponse); + return this; + } + + public TransportClientWrapper build() { + + Map replicaResponseCounterDict = new HashMap<>(); + + AtomicInteger i = new AtomicInteger(0); + AtomicBoolean valid = new AtomicBoolean(true); + List> capturedArgs = Collections.synchronizedList(new ArrayList<>()); + + TransportClient transportClient = Mockito.mock(TransportClient.class); + Mockito.doAnswer(invocation -> { + i.incrementAndGet(); + URI physicalUri = invocation.getArgumentAt(0, URI.class); + RxDocumentServiceRequest request = invocation.getArgumentAt(1, RxDocumentServiceRequest.class); + Function2WithCheckedException function = responseFunctionDictionary.get(physicalUri); + if (function == null) { + valid.set(false); + return Mono.error(new IllegalStateException("no registered function for replica " + physicalUri)); + } + int current; + synchronized (transportClient) { + capture(capturedArgs, invocation); + + AtomicInteger cnt = replicaResponseCounterDict.get(physicalUri); + if (cnt == null) { + cnt = new AtomicInteger(0); + replicaResponseCounterDict.put(physicalUri, cnt); + } + + current = cnt.getAndIncrement(); + } + + try { + return Mono.just(function.apply(current, request)); + } catch (Exception e) { + return Mono.error(e); + } + + }).when(transportClient).invokeResourceOperationAsync(Mockito.any(URI.class), Mockito.any(RxDocumentServiceRequest.class)); + + return new TransportClientWrapper(transportClient, i, valid, capturedArgs); + } + } + + + static SequentialBuilder sequentialBuilder() { + return new SequentialBuilder(); + } + + class SequentialBuilder implements Builder { + private List list = new ArrayList<>(); + + public SequentialBuilder then(StoreResponse response) { + list.add(response); + return this; + } + + public SequentialBuilder then(Exception exception) { + list.add(exception); + return this; + } + + public TransportClientWrapper build() { + AtomicInteger i = new AtomicInteger(0); + AtomicBoolean valid = new AtomicBoolean(true); + List> capturedArgs = Collections.synchronizedList(new ArrayList<>()); + + TransportClient transportClient = Mockito.mock(TransportClient.class); + Mockito.doAnswer(invocation -> { + capture(capturedArgs, invocation); + + int current = i.getAndIncrement(); + if (current >= list.size()) { + valid.set(false); + return Mono.error(new IllegalStateException()); + } + Object obj = list.get(current); + StoreResponse response = Utils.as(obj, StoreResponse.class); + if (response != null) { + return Mono.just(response); + } else { + return Mono.error((Exception) obj); + } + + }).when(transportClient).invokeResourceOperationAsync(Mockito.any(URI.class), Mockito.any(RxDocumentServiceRequest.class)); + + return new TransportClientWrapper(transportClient, i, valid, capturedArgs); + } + } + + static UriToResultBuilder uriToResultBuilder() { + return new UriToResultBuilder(); + } + + class UriToResultBuilder implements Builder { + private static class Result { + StoreResponse storeResponse; + Exception exception; + boolean stickyResult; + + public Result(StoreResponse storeResponse, Exception exception, boolean stickyResult) { + this.storeResponse = storeResponse; + this.exception = exception; + this.stickyResult = stickyResult; + } + } + + private static class Tuple { + URI replicaURI; + OperationType operationType; + ResourceType resourceType; + + public Tuple(URI replicaURI, OperationType operationType, ResourceType resourceType) { + this.replicaURI = replicaURI; + this.operationType = operationType; + this.resourceType = resourceType; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Tuple tuple = (Tuple) o; + return Objects.equals(replicaURI, tuple.replicaURI) && + operationType == tuple.operationType && + resourceType == tuple.resourceType; + } + + @Override + public int hashCode() { + return Objects.hash(replicaURI, operationType, resourceType); + } + + @Override + public String toString() { + return "Tuple{" + + "replicaURI=" + replicaURI + + ", operationType=" + operationType + + ", resourceType=" + resourceType + + '}'; + } + } + private Map> uriToResult = new HashMap<>(); + + + private UriToResultBuilder resultOn(URI replicaURI, OperationType operationType, ResourceType resourceType, StoreResponse rsp, Exception ex, boolean stickyResult) { + Tuple key = new Tuple(replicaURI, operationType, resourceType); + List list = uriToResult.get(key); + if (list == null) { + list = new ArrayList<>(); + uriToResult.put(key, list); + } + list.add(new Result(rsp, ex, stickyResult)); + return this; + } + + public UriToResultBuilder storeResponseOn(URI replicaURI, OperationType operationType, ResourceType resourceType, StoreResponse response, boolean stickyResult) { + resultOn(replicaURI, operationType, resourceType, response, null, stickyResult); + return this; + } + + public UriToResultBuilder exceptionOn(URI replicaURI, OperationType operationType, ResourceType resourceType, Exception exception, boolean stickyResult) { + resultOn(replicaURI, operationType, resourceType, null, exception, stickyResult); + return this; + } + + public TransportClientWrapper build() { + AtomicBoolean valid = new AtomicBoolean(true); + AtomicInteger cnt = new AtomicInteger(0); + List> capturedArgs = Collections.synchronizedList(new ArrayList<>()); + TransportClient transportClient = Mockito.mock(TransportClient.class); + Mockito.doAnswer(invocation -> { + cnt.getAndIncrement(); + URI physicalUri = invocation.getArgumentAt(0, URI.class); + RxDocumentServiceRequest request = invocation.getArgumentAt(1, RxDocumentServiceRequest.class); + capture(capturedArgs, invocation); + + Tuple tuple = new Tuple(physicalUri, request.getOperationType(), request.getResourceType()); + List list = uriToResult.get(tuple); + if (list == null || list.isEmpty()) { + // unknown + valid.set(false); + return Mono.error(new IllegalStateException(tuple.toString())); + } + + Result result = list.get(0); + + if (!result.stickyResult) { + list.remove(0); + } + if (result.storeResponse != null) { + return Mono.just(result.storeResponse); + } else { + return Mono.error(result.exception); + } + + }).when(transportClient).invokeResourceOperationAsync(Mockito.any(URI.class), Mockito.any(RxDocumentServiceRequest.class)); + + return new TransportClientWrapper(transportClient, cnt, valid, capturedArgs); + } + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtilityTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtilityTest.java new file mode 100644 index 0000000000000..11fffa33b1b5f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/directconnectivity/WebExceptionUtilityTest.java @@ -0,0 +1,137 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.directconnectivity; + +import com.azure.data.cosmos.internal.directconnectivity.WebExceptionUtility; +import io.netty.channel.ChannelException; +import io.netty.channel.ConnectTimeoutException; +import io.netty.handler.timeout.ReadTimeoutException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; +import java.net.ConnectException; +import java.net.NoRouteToHostException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +/** + * validation tests for {@link WebExceptionUtility} + */ +public class WebExceptionUtilityTest { + + @DataProvider(name = "exceptionToIsRetriable") + public Object[][] exceptionToIsRetriable() { + return new Object[][]{ + // exception, is retriable + { + new RuntimeException(), false + }, + { + new ConnectException(), true + }, + { + new ConnectTimeoutException(), true + }, + { + new UnknownHostException(), true + }, + { + ReadTimeoutException.INSTANCE, false + }, + { + new SSLHandshakeException("dummy"), true + }, + { + new NoRouteToHostException(), true, + }, + { + new SSLPeerUnverifiedException("dummy"), true + }, + { + new SocketTimeoutException(), false + } + }; + } + + @Test(groups = "unit", dataProvider = "exceptionToIsRetriable") + public void isWebExceptionRetriable(Exception e, boolean isRetriable) { + boolean actualRes = WebExceptionUtility.isWebExceptionRetriable(e); + if (isRetriable) { + assertThat(actualRes).describedAs(e.toString()).isTrue(); + } else { + assertThat(actualRes).describedAs(e.toString()).isFalse(); + } + } + + @DataProvider(name = "networkFailure") + public Object[][] networkFailure() { + return new Object[][]{ + // exception, is retriable + { + new RuntimeException(), false + }, + { + new ConnectException(), true + }, + { + new ConnectTimeoutException(), true + }, + { + new UnknownHostException(), true + }, + { + ReadTimeoutException.INSTANCE, true + }, + { + new SSLHandshakeException("dummy"), true + }, + { + new NoRouteToHostException(), true, + }, + { + new SSLPeerUnverifiedException("dummy"), true + }, + { + new SocketTimeoutException(), true + }, + { + new ChannelException(), true + } + }; + } + + @Test(groups = "unit", dataProvider = "networkFailure") + public void isNetworkFailure(Exception e, boolean isNetworkFailure) { + boolean actualRes = WebExceptionUtility.isNetworkFailure(e); + if (isNetworkFailure) { + assertThat(actualRes).describedAs(e.toString()).isTrue(); + } else { + assertThat(actualRes).describedAs(e.toString()).isFalse(); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/DocumentProducerTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/DocumentProducerTest.java new file mode 100644 index 0000000000000..ae5f57aa55a93 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/DocumentProducerTest.java @@ -0,0 +1,942 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.CosmosError; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.azure.data.cosmos.internal.GlobalEndpointManager; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.IRetryPolicyFactory; +import com.azure.data.cosmos.internal.RetryPolicy; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import com.azure.data.cosmos.internal.caches.RxPartitionKeyRangeCache; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderByRowResult; +import com.azure.data.cosmos.internal.query.orderbyquery.OrderbyRowComparer; +import com.azure.data.cosmos.internal.routing.PartitionKeyRangeIdentity; +import com.azure.data.cosmos.internal.routing.Range; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.common.collect.LinkedListMultimap; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.RandomUtils; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; + +public class DocumentProducerTest { + private final static Logger logger = LoggerFactory.getLogger(DocumentProducerTest.class); + private static final long TIMEOUT = 10000; + private final static String OrderByPayloadFieldName = "payload"; + private final static String OrderByItemsFieldName = "orderByItems"; + + private final static String OrderByIntFieldName = "propInt"; + private final static String DocumentPartitionKeyRangeIdFieldName = "_pkrId"; + private final static String DocumentPartitionKeyRangeMinInclusiveFieldName = "_pkrMinInclusive"; + private final static String DocumentPartitionKeyRangeMaxExclusiveFieldName = "_pkrMaxExclusive"; + + private final String collectionRid = "myrid"; + private final String collectionLink = "/dbs/mydb/colls/mycol"; + + @DataProvider(name = "splitParamProvider") + public Object[][] splitParamProvider() { + return new Object[][]{ + // initial continuation token, + // # pages from parent before split, + // # pages from left child after split, + // # pages from right child after split + {"init-cp", 10, 5, 6}, {null, 10, 5, 6}, {null, 1000, 500, 600}, {"init-cp", 1000, 500, 600}, {"init" + + "-cp", 0, 10, 12}, {null, 0, 10, 12}, {null, 0, 1, 1}, {null, 10, 1, 1},}; + } + + private IRetryPolicyFactory mockDocumentClientIRetryPolicyFactory() { + URL url; + try { + url = new URL("http://localhost"); + } catch (Exception e) { + throw new IllegalStateException(e); + } + + GlobalEndpointManager globalEndpointManager = Mockito.mock(GlobalEndpointManager.class); + Mockito.doReturn(url).when(globalEndpointManager).resolveServiceEndpoint(Mockito.any(RxDocumentServiceRequest.class)); + doReturn(false).when(globalEndpointManager).isClosed(); + return new RetryPolicy(globalEndpointManager, ConnectionPolicy.defaultPolicy()); + } + + @Test(groups = {"unit"}, dataProvider = "splitParamProvider", timeOut = TIMEOUT) + public void partitionSplit(String initialContinuationToken, int numberOfResultPagesFromParentBeforeSplit, + int numberOfResultPagesFromLeftChildAfterSplit, int numberOfResultPagesFromRightChildAfterSplit) { + int initialPageSize = 7; + int top = -1; + + String parentPartitionId = "1"; + String leftChildPartitionId = "2"; + String rightChildPartitionId = "3"; + + List> resultFromParentPartition = mockFeedResponses(parentPartitionId, + numberOfResultPagesFromParentBeforeSplit, 3, false); + List> resultFromLeftChildPartition = mockFeedResponses(leftChildPartitionId, + numberOfResultPagesFromLeftChildAfterSplit, 3, true); + List> resultFromRightChildPartition = mockFeedResponses(rightChildPartitionId, + numberOfResultPagesFromRightChildAfterSplit, 3, true); + + // sanity check + sanityCheckSplitValidation(parentPartitionId, leftChildPartitionId, rightChildPartitionId, + numberOfResultPagesFromParentBeforeSplit, + numberOfResultPagesFromLeftChildAfterSplit, + numberOfResultPagesFromRightChildAfterSplit, resultFromParentPartition, + resultFromLeftChildPartition, resultFromRightChildPartition); + + // setting up behaviour + RequestExecutor.PartitionAnswer answerFromParentPartition = + RequestExecutor.PartitionAnswer.just(parentPartitionId, resultFromParentPartition); + RequestExecutor.PartitionAnswer splitAnswerFromParentPartition = + RequestExecutor.PartitionAnswer.alwaysPartitionSplit(parentPartitionId); + + RequestExecutor.PartitionAnswer answerFromLeftChildPartition = + RequestExecutor.PartitionAnswer.just(leftChildPartitionId, resultFromLeftChildPartition); + RequestExecutor.PartitionAnswer answerFromRightChildPartition = + RequestExecutor.PartitionAnswer.just(rightChildPartitionId, resultFromRightChildPartition); + + RequestCreator requestCreator = RequestCreator.simpleMock(); + RequestExecutor requestExecutor = RequestExecutor. + fromPartitionAnswer(ImmutableList.of(answerFromParentPartition, splitAnswerFromParentPartition, + answerFromLeftChildPartition, answerFromRightChildPartition)); + + PartitionKeyRange parentPartitionKeyRange = mockPartitionKeyRange(parentPartitionId); + PartitionKeyRange leftChildPartitionKeyRange = mockPartitionKeyRange(leftChildPartitionId); + PartitionKeyRange rightChildPartitionKeyRange = mockPartitionKeyRange(rightChildPartitionId); + + // this returns replacement ranges upon split detection + IDocumentQueryClient queryClient = mockQueryClient(ImmutableList.of(leftChildPartitionKeyRange, + rightChildPartitionKeyRange)); + + DocumentProducer documentProducer = new DocumentProducer<>( + queryClient, + collectionRid, + null, + requestCreator, + requestExecutor, + parentPartitionKeyRange, + collectionLink, + () -> mockDocumentClientIRetryPolicyFactory().getRequestPolicy(), + Document.class, + null, + initialPageSize, + initialContinuationToken, + top); + + TestSubscriber.DocumentProducerFeedResponse> subscriber = new TestSubscriber<>(); + + documentProducer.produceAsync().subscribe(subscriber); + subscriber.awaitTerminalEvent(); + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + + validateSplitCaptureRequests( + requestCreator.invocations, + initialContinuationToken, + parentPartitionId, + leftChildPartitionId, + rightChildPartitionId, + resultFromParentPartition, + resultFromLeftChildPartition, + resultFromRightChildPartition); + + // page size match + assertThat(requestCreator.invocations.stream().map(i -> i.maxItemCount) + .distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singleton(initialPageSize)); + + // expected results + validateSplitResults(subscriber.values(), + parentPartitionId, leftChildPartitionId, + rightChildPartitionId, resultFromParentPartition, resultFromLeftChildPartition, + resultFromRightChildPartition, false); + + Mockito.verify(queryClient, times(1)).getPartitionKeyRangeCache(); + } + + @Test(groups = {"unit"}, dataProvider = "splitParamProvider", timeOut = TIMEOUT) + public void orderByPartitionSplit(String initialContinuationToken, int numberOfResultPagesFromParentBeforeSplit, + int numberOfResultPagesFromLeftChildAfterSplit, int numberOfResultPagesFromRightChildAfterSplit) { + int initialPageSize = 7; + int top = -1; + + String parentPartitionId = "1"; + String leftChildPartitionId = "2"; + String rightChildPartitionId = "3"; + + Integer initialPropVal = 1; + List> resultFromParentPartition = mockFeedResponses(parentPartitionId, + numberOfResultPagesFromParentBeforeSplit, 3, initialPropVal, false); + Integer highestValInParentPage = getLastValueInAsc(initialPropVal, resultFromParentPartition); + + List> resultFromLeftChildPartition = mockFeedResponses(leftChildPartitionId, + numberOfResultPagesFromLeftChildAfterSplit, 3, highestValInParentPage, true); + + List> resultFromRightChildPartition = mockFeedResponses(rightChildPartitionId, + numberOfResultPagesFromRightChildAfterSplit, 3, highestValInParentPage, true); + + // sanity check + sanityCheckSplitValidation(parentPartitionId, leftChildPartitionId, rightChildPartitionId, + numberOfResultPagesFromParentBeforeSplit, + numberOfResultPagesFromLeftChildAfterSplit, + numberOfResultPagesFromRightChildAfterSplit, resultFromParentPartition, + resultFromLeftChildPartition, resultFromRightChildPartition); + + // setting up behaviour + RequestExecutor.PartitionAnswer answerFromParentPartition = + RequestExecutor.PartitionAnswer.just(parentPartitionId, resultFromParentPartition); + RequestExecutor.PartitionAnswer splitAnswerFromParentPartition = + RequestExecutor.PartitionAnswer.alwaysPartitionSplit(parentPartitionId); + + RequestExecutor.PartitionAnswer answerFromLeftChildPartition = + RequestExecutor.PartitionAnswer.just(leftChildPartitionId, resultFromLeftChildPartition); + RequestExecutor.PartitionAnswer answerFromRightChildPartition = + RequestExecutor.PartitionAnswer.just(rightChildPartitionId, resultFromRightChildPartition); + + RequestCreator requestCreator = RequestCreator.simpleMock(); + RequestExecutor requestExecutor = RequestExecutor. + fromPartitionAnswer(ImmutableList.of(answerFromParentPartition, splitAnswerFromParentPartition, + answerFromLeftChildPartition, answerFromRightChildPartition)); + + PartitionKeyRange parentPartitionKeyRange = mockPartitionKeyRange(parentPartitionId); + PartitionKeyRange leftChildPartitionKeyRange = mockPartitionKeyRange(leftChildPartitionId); + PartitionKeyRange rightChildPartitionKeyRange = mockPartitionKeyRange(rightChildPartitionId); + + // this returns replacement ranges upon split detection + IDocumentQueryClient queryCl = mockQueryClient(ImmutableList.of(leftChildPartitionKeyRange, + rightChildPartitionKeyRange)); + + OrderByDocumentProducer documentProducer = + new OrderByDocumentProducer<>(new OrderbyRowComparer<>(ImmutableList.of(SortOrder.Ascending)), + queryCl, collectionRid, null, requestCreator, requestExecutor, + parentPartitionKeyRange, collectionLink, null, Document.class, null, + initialPageSize, initialContinuationToken, top, + /*targetRangeToOrderByContinuationTokenMap*/new HashMap<>()); + + TestSubscriber.DocumentProducerFeedResponse> subscriber = new TestSubscriber<>(); + + documentProducer.produceAsync().subscribe(subscriber); + subscriber.awaitTerminalEvent(); + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + + validateSplitCaptureRequests(requestCreator.invocations, initialContinuationToken, parentPartitionId, + leftChildPartitionId, rightChildPartitionId, resultFromParentPartition, + resultFromLeftChildPartition, resultFromRightChildPartition); + + // page size match + assertThat(requestCreator.invocations.stream().map(i -> i.maxItemCount).distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singleton(initialPageSize)); + + // expected results + validateSplitResults(subscriber.values(), + parentPartitionId, leftChildPartitionId, + rightChildPartitionId, resultFromParentPartition, resultFromLeftChildPartition, + resultFromRightChildPartition, true); + + Mockito.verify(queryCl, times(1)).getPartitionKeyRangeCache(); + } + + @Test(groups = {"unit"}, timeOut = TIMEOUT) + public void simple() { + int initialPageSize = 7; + int top = -1; + + String partitionId = "1"; + + List requests = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + requests.add(mockRequest(partitionId)); + } + + List> responses = mockFeedResponses(partitionId, 10, 3, true); + + RequestCreator requestCreator = RequestCreator.give(requests); + RequestExecutor requestExecutor = RequestExecutor.fromPartitionAnswer(RequestExecutor.PartitionAnswer.just("1" + , responses)); + + PartitionKeyRange targetRange = mockPartitionKeyRange(partitionId); + + IDocumentQueryClient queryClient = Mockito.mock(IDocumentQueryClient.class); + String initialContinuationToken = "initial-cp"; + DocumentProducer documentProducer = new DocumentProducer<>(queryClient, collectionRid, null, + requestCreator, requestExecutor, + targetRange, collectionLink, + () -> mockDocumentClientIRetryPolicyFactory().getRequestPolicy(), Document.class, null, initialPageSize, initialContinuationToken, top); + + TestSubscriber subscriber = new TestSubscriber<>(); + + documentProducer.produceAsync().subscribe(subscriber); + subscriber.awaitTerminalEvent(); + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + + subscriber.assertValueCount(responses.size()); + + // requests match + assertThat(requestCreator.invocations.stream().map(i -> i.invocationResult).collect(Collectors.toList())).containsExactlyElementsOf(requests); + + // requested max page size match + assertThat(requestCreator.invocations.stream().map(i -> i.maxItemCount).distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singleton(7)); + + // continuation tokens + assertThat(requestCreator.invocations.get(0).continuationToken).isEqualTo(initialContinuationToken); + assertThat(requestCreator.invocations.stream().skip(1).map(i -> i.continuationToken).collect(Collectors.toList())).containsExactlyElementsOf(responses.stream().limit(9).map(r -> r.continuationToken()).collect(Collectors.toList())); + + // source partition + assertThat(requestCreator.invocations.stream().map(i -> i.sourcePartition).distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singletonList(targetRange)); + } + + @Test(groups = {"unit"}, timeOut = TIMEOUT) + public void retries() { + int initialPageSize = 7; + int top = -1; + + String partitionKeyRangeId = "1"; + + RequestCreator requestCreator = RequestCreator.simpleMock(); + + List> responsesBeforeThrottle = mockFeedResponses(partitionKeyRangeId, 2, 1, false); + Exception throttlingException = mockThrottlingException(10); + List> responsesAfterThrottle = mockFeedResponses(partitionKeyRangeId, 5, 1, true); + + RequestExecutor.PartitionAnswer behaviourBeforeException = + RequestExecutor.PartitionAnswer.just(partitionKeyRangeId, responsesBeforeThrottle); + RequestExecutor.PartitionAnswer exceptionBehaviour = + RequestExecutor.PartitionAnswer.errors(partitionKeyRangeId, + Collections.singletonList(throttlingException)); + RequestExecutor.PartitionAnswer behaviourAfterException = + RequestExecutor.PartitionAnswer.just(partitionKeyRangeId, responsesAfterThrottle); + + RequestExecutor requestExecutor = RequestExecutor.fromPartitionAnswer(behaviourBeforeException, + exceptionBehaviour, + behaviourAfterException); + + PartitionKeyRange targetRange = mockPartitionKeyRange(partitionKeyRangeId); + + IDocumentQueryClient queryClient = Mockito.mock(IDocumentQueryClient.class); + String initialContinuationToken = "initial-cp"; + DocumentProducer documentProducer = new DocumentProducer<>(queryClient, collectionRid, null, + requestCreator, requestExecutor, + targetRange, collectionLink, + () -> mockDocumentClientIRetryPolicyFactory().getRequestPolicy(), Document.class, null, initialPageSize, initialContinuationToken, top); + + TestSubscriber subscriber = new TestSubscriber<>(); + + documentProducer.produceAsync().subscribe(subscriber); + subscriber.awaitTerminalEvent(); + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + + subscriber.assertValueCount(responsesBeforeThrottle.size() + responsesAfterThrottle.size()); + + // requested max page size match + assertThat(requestCreator.invocations.stream().map(i -> i.maxItemCount).distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singleton(7)); + + // continuation tokens + assertThat(requestCreator.invocations.get(0).continuationToken).isEqualTo(initialContinuationToken); + + // source partition + assertThat(requestCreator.invocations.stream().map(i -> i.sourcePartition).distinct().collect(Collectors.toList())).containsExactlyElementsOf(Collections.singletonList(targetRange)); + + List resultContinuationToken = + subscriber.values().stream().map(r -> r.pageResult.continuationToken()).collect(Collectors.toList()); + List beforeExceptionContinuationTokens = + responsesBeforeThrottle.stream().map(FeedResponse::continuationToken).collect(Collectors.toList()); + List afterExceptionContinuationTokens = + responsesAfterThrottle.stream().map(FeedResponse::continuationToken).collect(Collectors.toList()); + + assertThat(resultContinuationToken).containsExactlyElementsOf(Iterables.concat(beforeExceptionContinuationTokens, afterExceptionContinuationTokens)); + + String continuationTokenOnException = Iterables.getLast(beforeExceptionContinuationTokens); + + assertThat(requestCreator.invocations.stream().map(cr -> cr.continuationToken)).containsExactlyElementsOf(Iterables.concat(ImmutableList.of(initialContinuationToken), Iterables.limit(resultContinuationToken, resultContinuationToken.size() - 1))); + + assertThat(requestExecutor.partitionKeyRangeIdToCapturedInvocation.get(partitionKeyRangeId).stream().map(cr -> cr.request.getContinuation())).containsExactlyElementsOf(Iterables.concat(ImmutableList.of(initialContinuationToken), beforeExceptionContinuationTokens, Collections.singletonList(continuationTokenOnException), Iterables.limit(afterExceptionContinuationTokens, afterExceptionContinuationTokens.size() - 1))); + } + + @Test(groups = {"unit"}, timeOut = TIMEOUT) + public void retriesExhausted() { + int initialPageSize = 7; + int top = -1; + + String partitionKeyRangeId = "1"; + + RequestCreator requestCreator = RequestCreator.simpleMock(); + + List> responsesBeforeThrottle = mockFeedResponses(partitionKeyRangeId, 1, 1, false); + Exception throttlingException = mockThrottlingException(10); + + RequestExecutor.PartitionAnswer behaviourBeforeException = + RequestExecutor.PartitionAnswer.just(partitionKeyRangeId, responsesBeforeThrottle); + RequestExecutor.PartitionAnswer exceptionBehaviour = + RequestExecutor.PartitionAnswer.errors(partitionKeyRangeId, Collections.nCopies(10, + throttlingException)); + + RequestExecutor requestExecutor = RequestExecutor.fromPartitionAnswer(behaviourBeforeException, + exceptionBehaviour); + + PartitionKeyRange targetRange = mockPartitionKeyRange(partitionKeyRangeId); + + IDocumentQueryClient queryClient = Mockito.mock(IDocumentQueryClient.class); + String initialContinuationToken = "initial-cp"; + DocumentProducer documentProducer = new DocumentProducer(queryClient, collectionRid, null, + requestCreator, requestExecutor, + targetRange, collectionRid, + () -> mockDocumentClientIRetryPolicyFactory().getRequestPolicy(), Document.class, null, initialPageSize, initialContinuationToken, top); + + TestSubscriber subscriber = new TestSubscriber<>(); + + documentProducer.produceAsync().subscribe(subscriber); + subscriber.awaitTerminalEvent(); + + subscriber.assertError(throttlingException); + subscriber.assertValueCount(responsesBeforeThrottle.size()); + } + + private CosmosClientException mockThrottlingException(long retriesAfter) { + CosmosClientException throttleException = mock(CosmosClientException.class); + doReturn(429).when(throttleException).statusCode(); + doReturn(retriesAfter).when(throttleException).retryAfterInMilliseconds(); + return throttleException; + } + + private List> mockFeedResponses(String partitionKeyRangeId, int numberOfPages, + int numberOfDocsPerPage, boolean completed) { + return mockFeedResponsesPartiallySorted(partitionKeyRangeId, numberOfPages, numberOfDocsPerPage, false, -1, + completed); + } + + private List> mockFeedResponses(String partitionKeyRangeId, int numberOfPages, + int numberOfDocsPerPage, int orderByFieldInitialVal, boolean completed) { + return mockFeedResponsesPartiallySorted(partitionKeyRangeId, numberOfPages, numberOfDocsPerPage, true, + orderByFieldInitialVal, completed); + } + + private List> mockFeedResponsesPartiallySorted(String partitionKeyRangeId, + int numberOfPages, int numberOfDocsPerPage, boolean isOrderby, int orderByFieldInitialVal, + boolean completed) { + String uuid = UUID.randomUUID().toString(); + List> responses = new ArrayList<>(); + for (int i = 0; i < numberOfPages; i++) { + FeedResponseBuilder rfb = FeedResponseBuilder.queryFeedResponseBuilder(Document.class); + List res = new ArrayList<>(); + + for (int j = 0; j < numberOfDocsPerPage; j++) { + + Document d = getDocumentDefinition(); + if (isOrderby) { + BridgeInternal.setProperty(d, OrderByIntFieldName, orderByFieldInitialVal + RandomUtils.nextInt(0, 3)); + BridgeInternal.setProperty(d, DocumentPartitionKeyRangeIdFieldName, partitionKeyRangeId); + PartitionKeyRange pkr = mockPartitionKeyRange(partitionKeyRangeId); + + BridgeInternal.setProperty(d, DocumentPartitionKeyRangeMinInclusiveFieldName, pkr.getMinInclusive()); + BridgeInternal.setProperty(d, DocumentPartitionKeyRangeMaxExclusiveFieldName, pkr.getMaxExclusive()); + + QueryItem qi = new QueryItem("{ \"item\": " + Integer.toString(d.getInt(OrderByIntFieldName)) + + " }"); + String json = + "{\"" + OrderByPayloadFieldName + "\" : " + d.toJson() + ", \"" + OrderByItemsFieldName + "\" : [ " + qi.toJson() + " ] }"; + + OrderByRowResult row = new OrderByRowResult<>(Document.class, json, + mockPartitionKeyRange(partitionKeyRangeId), "backend continuation token"); + res.add(row); + } else { + res.add(d); + } + } + rfb.withResults(res); + + if (!(completed && i == numberOfPages - 1)) { + rfb.withContinuationToken("cp:" + uuid + ":" + i); + } + + FeedResponse resp = rfb.build(); + responses.add(resp); + } + return responses; + } + + private int getLastValueInAsc(int initialValue, List> responsesList) { + Integer value = null; + for (FeedResponse page : responsesList) { + for (Document d : page.results()) { + Integer tmp = d.getInt(OrderByIntFieldName); + if (tmp != null) { + value = tmp; + } + } + } + if (value != null) { + return value; + } else { + return initialValue; + } + } + + private IDocumentQueryClient mockQueryClient(List replacementRanges) { + IDocumentQueryClient client = Mockito.mock(IDocumentQueryClient.class); + RxPartitionKeyRangeCache cache = Mockito.mock(RxPartitionKeyRangeCache.class); + doReturn(cache).when(client).getPartitionKeyRangeCache(); + doReturn(Mono.just(replacementRanges)).when(cache). + tryGetOverlappingRangesAsync(anyString(), any(Range.class), anyBoolean(), Matchers.anyMap()); + return client; + } + + private PartitionKeyRange mockPartitionKeyRange(String partitionKeyRangeId) { + PartitionKeyRange pkr = Mockito.mock(PartitionKeyRange.class); + doReturn(partitionKeyRangeId).when(pkr).id(); + doReturn(partitionKeyRangeId + ":AA").when(pkr).getMinInclusive(); + doReturn(partitionKeyRangeId + ":FF").when(pkr).getMaxExclusive(); + return pkr; + } + + private RxDocumentServiceRequest mockRequest(String partitionKeyRangeId) { + RxDocumentServiceRequest req = Mockito.mock(RxDocumentServiceRequest.class); + PartitionKeyRangeIdentity pkri = new PartitionKeyRangeIdentity(partitionKeyRangeId); + doReturn(pkri).when(req).getPartitionKeyRangeIdentity(); + return req; + } + + private static void validateSplitCaptureRequests(List capturedInvocationList, + String initialContinuationToken, String parentPartitionId, String leftChildPartitionId, + String rightChildPartitionId, + List> expectedResultPagesFromParentPartitionBeforeSplit, + List> expectedResultPagesFromLeftChildPartition, + List> expectedResultPagesFromRightChildPartition) { + + int numberOfResultPagesFromParentBeforeSplit = expectedResultPagesFromParentPartitionBeforeSplit.size(); + int numberOfResultPagesFromLeftChildAfterSplit = expectedResultPagesFromLeftChildPartition.size(); + int numberOfResultPagesFromRightChildAfterSplit = expectedResultPagesFromRightChildPartition.size(); + + // numberOfResultPagesFromParentBeforeSplit + 1 requests to parent partition + assertThat(capturedInvocationList.stream().limit(numberOfResultPagesFromParentBeforeSplit + 1).filter(i -> i.sourcePartition.id().equals(parentPartitionId))).hasSize(numberOfResultPagesFromParentBeforeSplit + 1); + + assertThat(capturedInvocationList.stream().skip(numberOfResultPagesFromParentBeforeSplit + 1).filter(i -> i.sourcePartition.id().equals(leftChildPartitionId))).hasSize(numberOfResultPagesFromLeftChildAfterSplit); + + assertThat(capturedInvocationList.stream().skip(numberOfResultPagesFromParentBeforeSplit + 1).filter(i -> i.sourcePartition.id().equals(rightChildPartitionId))).hasSize(numberOfResultPagesFromRightChildAfterSplit); + + BiFunction, String, Stream> filterByPartition = (stream, partitionId) -> stream.filter(i -> i.sourcePartition.id().equals(partitionId)); + + Function>, Stream> extractContinuationToken = + (list) -> list.stream().map(p -> p.continuationToken()); + + assertThat(filterByPartition.apply(capturedInvocationList.stream(), parentPartitionId).map(r -> r.continuationToken)).containsExactlyElementsOf(toList(Stream.concat(Stream.of(initialContinuationToken), extractContinuationToken.apply(expectedResultPagesFromParentPartitionBeforeSplit)))); + + String expectedInitialChildContinuationTokenInheritedFromParent = + expectedResultPagesFromParentPartitionBeforeSplit.size() > 0 ? + expectedResultPagesFromParentPartitionBeforeSplit.get(expectedResultPagesFromParentPartitionBeforeSplit.size() - 1).continuationToken() : initialContinuationToken; + + assertThat(filterByPartition.andThen(s -> s.map(r -> r.continuationToken)).apply(capturedInvocationList.stream(), leftChildPartitionId)).containsExactlyElementsOf(toList(Stream.concat(Stream.of(expectedInitialChildContinuationTokenInheritedFromParent), extractContinuationToken.apply(expectedResultPagesFromLeftChildPartition) + //drop last page with null cp which doesn't trigger any request + .limit(expectedResultPagesFromLeftChildPartition.size() - 1)))); + + assertThat(filterByPartition.andThen(s -> s.map(r -> r.continuationToken)).apply(capturedInvocationList.stream(), rightChildPartitionId)).containsExactlyElementsOf(toList(Stream.concat(Stream.of(expectedInitialChildContinuationTokenInheritedFromParent), extractContinuationToken.apply(expectedResultPagesFromRightChildPartition) + //drop last page with null cp which doesn't trigger any request + .limit(expectedResultPagesFromRightChildPartition.size() - 1)))); + } + + private static void sanityCheckSplitValidation(String parentPartitionId, String leftChildPartitionId, + String rightChildPartitionId, int numberOfResultPagesFromParentBeforeSplit, + int numberOfResultPagesFromLeftChildAfterSplit, int numberOfResultPagesFromRightChildAfterSplit, + List> resultFromParent, List> resultFromLeftChild, + List> resultFromRightChild) { + // test sanity check + assertThat(resultFromParent).hasSize(numberOfResultPagesFromParentBeforeSplit); + assertThat(resultFromLeftChild).hasSize(numberOfResultPagesFromLeftChildAfterSplit); + assertThat(resultFromRightChild).hasSize(numberOfResultPagesFromRightChildAfterSplit); + + //validate expected result continuation token + assertThat(toList(resultFromParent.stream().map(p -> p.continuationToken()).filter(cp -> Strings.isNullOrEmpty(cp)))).isEmpty(); + + assertThat(toList(resultFromLeftChild.stream().map(p -> p.continuationToken()).limit(resultFromLeftChild.size() - 1).filter(cp -> Strings.isNullOrEmpty(cp)))).isEmpty(); + + assertThat(resultFromLeftChild.get(resultFromLeftChild.size() - 1).continuationToken()).isNullOrEmpty(); + + assertThat(toList(resultFromRightChild.stream().map(p -> p.continuationToken()).limit(resultFromRightChild.size() - 1).filter(cp -> Strings.isNullOrEmpty(cp)))).isEmpty(); + + assertThat(resultFromRightChild.get(resultFromRightChild.size() - 1).continuationToken()).isNullOrEmpty(); + } + + private void validateSplitResults(List.DocumentProducerFeedResponse> actualPages, + String parentPartitionId, String leftChildPartitionId, String rightChildPartitionId, + List> resultFromParent, List> resultFromLeftChild, + List> resultFromRightChild, boolean isOrderby) { + + if (isOrderby) { + Supplier> getStreamOfActualDocuments = + () -> actualPages.stream().flatMap(p -> p.pageResult.results().stream()); + + Comparator comparator = new Comparator() { + @Override + public int compare(Document o1, Document o2) { + ObjectNode obj1 = (ObjectNode) o1.get(OrderByPayloadFieldName); + ObjectNode obj2 = (ObjectNode) o1.get(OrderByPayloadFieldName); + + int cmp = (obj1).get(OrderByIntFieldName).asInt() - (obj2).get(OrderByIntFieldName).asInt(); + if (cmp != 0) { + return cmp; + } + + return obj1.get(DocumentPartitionKeyRangeMinInclusiveFieldName).asText().compareTo(obj2.get(DocumentPartitionKeyRangeMinInclusiveFieldName).asText()); + } + }; + + List expectedDocuments = Stream.concat(Stream.concat(resultFromParent.stream(), + resultFromLeftChild.stream()), + resultFromRightChild.stream()).flatMap(p -> p.results().stream()).sorted(comparator).collect(Collectors.toList()); + + List actualDocuments = + getStreamOfActualDocuments.get().map(d -> d.id()).collect(Collectors.toList()); + assertThat(actualDocuments).containsExactlyElementsOf(expectedDocuments.stream().map(d -> d.id()).collect(Collectors.toList())); + + } else { + assertThat(actualPages).hasSize(resultFromParent.size() + resultFromLeftChild.size() + resultFromRightChild.size()); + + BiFunction> repeater = (v, cnt) -> { + return IntStream.range(0, cnt).mapToObj(i -> v); + }; + + List expectedCapturedPartitionIds = + toList(Stream.concat(Stream.concat(repeater.apply(parentPartitionId, resultFromParent.size()), + repeater.apply(leftChildPartitionId, + resultFromLeftChild.size())), + repeater.apply(rightChildPartitionId, resultFromRightChild.size()))); + + assertThat(toList(partitionKeyRangeIds(actualPages).stream())).containsExactlyInAnyOrderElementsOf(expectedCapturedPartitionIds); + + validateResults(feedResponses(actualPages), ImmutableList.of(resultFromParent, resultFromLeftChild, + resultFromRightChild)); + } + } + + private static List repeat(T t, int cnt) { + return IntStream.range(0, cnt).mapToObj(i -> t).collect(Collectors.toList()); + } + + private static List> feedResponses(List.DocumentProducerFeedResponse> responses) { + return responses.stream().map(dpFR -> dpFR.pageResult).collect(Collectors.toList()); + } + + private static List toList(Stream stream) { + return stream.collect(Collectors.toList()); + } + + private static List partitionKeyRangeIds(List.DocumentProducerFeedResponse> responses) { + return responses.stream().map(dpFR -> dpFR.sourcePartitionKeyRange.id()).collect(Collectors.toList()); + } + + private static void validateResults(List> captured, + List>> expectedResponsesFromPartitions) { + List> expected = + expectedResponsesFromPartitions.stream().flatMap(l -> l.stream()).collect(Collectors.toList()); + assertThat(captured).hasSameSizeAs(expected); + for (int i = 0; i < expected.size(); i++) { + FeedResponse actualPage = captured.get(i); + FeedResponse expectedPage = expected.get(i); + assertEqual(actualPage, expectedPage); + } + } + + private static void assertEqual(FeedResponse actualPage, FeedResponse expectedPage) { + assertThat(actualPage.results()).hasSameSizeAs(actualPage.results()); + assertThat(actualPage.continuationToken()).isEqualTo(expectedPage.continuationToken()); + + for (int i = 0; i < actualPage.results().size(); i++) { + Document actualDoc = actualPage.results().get(i); + Document expectedDoc = expectedPage.results().get(i); + assertThat(actualDoc.id()).isEqualTo(expectedDoc.id()); + assertThat(actualDoc.getString("prop")).isEqualTo(expectedDoc.getString("prop")); + } + } + + static abstract class RequestExecutor implements Function>> { + + LinkedListMultimap partitionKeyRangeIdToCapturedInvocation = + LinkedListMultimap.create(); + + class CapturedInvocation { + long time = System.nanoTime(); + RxDocumentServiceRequest request; + FeedResponse invocationResult; + Exception failureResult; + + public CapturedInvocation(RxDocumentServiceRequest request, Exception ex) { + this.request = request; + this.failureResult = ex; + } + + public CapturedInvocation(RxDocumentServiceRequest request, PartitionAnswer.Response resp) { + this.request = request; + this.invocationResult = resp.invocationResult; + this.failureResult = resp.failureResult; + } + } + + private static CosmosClientException partitionKeyRangeGoneException() { + Map headers = new HashMap<>(); + headers.put(HttpConstants.HttpHeaders.SUB_STATUS, + Integer.toString(HttpConstants.SubStatusCodes.PARTITION_KEY_RANGE_GONE)); + return BridgeInternal.createCosmosClientException(HttpConstants.StatusCodes.GONE, new CosmosError(), headers); + } + + protected void capture(String partitionId, CapturedInvocation captureInvocation) { + partitionKeyRangeIdToCapturedInvocation.put(partitionId, captureInvocation); + } + + public static RequestExecutor fromPartitionAnswer(List answers) { + return new RequestExecutor() { + @Override + public Flux> apply(RxDocumentServiceRequest request) { + synchronized (this) { + logger.debug("executing request: " + request + " cp is: " + request.getContinuation()); + for (PartitionAnswer a : answers) { + if (a.getPartitionKeyRangeId().equals(request.getPartitionKeyRangeIdentity().getPartitionKeyRangeId())) { + try { + PartitionAnswer.Response resp = a.onRequest(request); + if (resp != null) { + CapturedInvocation ci = new CapturedInvocation(request, resp); + capture(a.getPartitionKeyRangeId(), ci); + return resp.toSingle(); + } + + } catch (Exception e) { + capture(a.getPartitionKeyRangeId(), new CapturedInvocation(request, e)); + return Flux.error(e); + } + } + } + throw new RuntimeException(); + } + } + }; + } + + public static RequestExecutor fromPartitionAnswer(PartitionAnswer... answers) { + return fromPartitionAnswer(ImmutableList.copyOf(answers)); + } + + abstract static class PartitionAnswer { + class Response { + FeedResponse invocationResult; + Exception failureResult; + + public Response(FeedResponse invocationResult) { + this.invocationResult = invocationResult; + } + + public Response(Exception ex) { + this.failureResult = ex; + } + + public Flux> toSingle() { + if (invocationResult != null) { + return Flux.just(invocationResult); + } else { + return Flux.error(failureResult); + } + } + } + + private String partitionKeyRangeId; + + private static boolean targetsPartition(RxDocumentServiceRequest req, String partitionKeyRangeId) { + return partitionKeyRangeId.equals(req.getPartitionKeyRangeIdentity().getPartitionKeyRangeId()); + } + + protected PartitionAnswer(String partitionKeyRangeId) { + this.partitionKeyRangeId = partitionKeyRangeId; + } + + public String getPartitionKeyRangeId() { + return partitionKeyRangeId; + } + + public abstract Response onRequest(final RxDocumentServiceRequest req); + + public static PartitionAnswer just(String partitionId, List> resps) { + AtomicInteger index = new AtomicInteger(); + return new PartitionAnswer(partitionId) { + @Override + public Response onRequest(RxDocumentServiceRequest request) { + if (!PartitionAnswer.targetsPartition(request, partitionId)) { + return null; + } + synchronized (this) { + if (index.get() < resps.size()) { + return new Response(resps.get(index.getAndIncrement())); + } + } + return null; + } + }; + } + + public static PartitionAnswer always(String partitionId, final Exception ex) { + return new PartitionAnswer(partitionId) { + @Override + public Response onRequest(RxDocumentServiceRequest request) { + if (!PartitionAnswer.targetsPartition(request, partitionId)) { + return null; + } + + return new Response(ex); + } + }; + } + + public static PartitionAnswer errors(String partitionId, List exs) { + AtomicInteger index = new AtomicInteger(); + return new PartitionAnswer(partitionId) { + @Override + public Response onRequest(RxDocumentServiceRequest request) { + if (!PartitionAnswer.targetsPartition(request, partitionId)) { + return null; + } + synchronized (this) { + if (index.get() < exs.size()) { + return new Response(exs.get(index.getAndIncrement())); + } + } + return null; + } + }; + } + + public static PartitionAnswer alwaysPartitionSplit(String partitionId) { + return new PartitionAnswer(partitionId) { + @Override + public Response onRequest(RxDocumentServiceRequest request) { + if (!PartitionAnswer.targetsPartition(request, partitionId)) { + return null; + } + return new Response(partitionKeyRangeGoneException()); + } + }; + } + } + } + + static abstract class RequestCreator implements TriFunction { + + public static RequestCreator give(List requests) { + AtomicInteger i = new AtomicInteger(0); + return new RequestCreator() { + + @Override + public RxDocumentServiceRequest apply(PartitionKeyRange pkr, String cp, Integer ps) { + synchronized (this) { + RxDocumentServiceRequest req = requests.get(i.getAndIncrement()); + invocations.add(new CapturedInvocation(pkr, cp, ps, req)); + return req; + } + } + }; + } + + public static RequestCreator simpleMock() { + return new RequestCreator() { + @Override + public RxDocumentServiceRequest apply(PartitionKeyRange pkr, String cp, Integer ps) { + synchronized (this) { + RxDocumentServiceRequest req = Mockito.mock(RxDocumentServiceRequest.class); + PartitionKeyRangeIdentity pkri = new PartitionKeyRangeIdentity(pkr.id()); + doReturn(pkri).when(req).getPartitionKeyRangeIdentity(); + doReturn(cp).when(req).getContinuation(); + invocations.add(new CapturedInvocation(pkr, cp, ps, req)); + logger.debug("creating request: " + req + " cp is " + cp); + return req; + } + } + }; + } + + class CapturedInvocation { + PartitionKeyRange sourcePartition; + String continuationToken; + Integer maxItemCount; + RxDocumentServiceRequest invocationResult; + + public CapturedInvocation(PartitionKeyRange sourcePartition, String continuationToken, + Integer maxItemCount, RxDocumentServiceRequest invocationResult) { + this.sourcePartition = sourcePartition; + this.continuationToken = continuationToken; + this.maxItemCount = maxItemCount; + this.invocationResult = invocationResult; + } + } + + List invocations = Collections.synchronizedList(new ArrayList<>()); + +// abstract public RxDocumentServiceRequest call(PartitionKeyRange pkr, String cp, Integer ps); + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": " + + "[[6519456, 1471916863], [2498434, 1455671440]], " + + "\"prop\": \"%s\"" + "}", uuid, uuid, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FeedResponseBuilder.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FeedResponseBuilder.java new file mode 100644 index 0000000000000..22112ff6e8206 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FeedResponseBuilder.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.RxDocumentServiceResponse; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FeedResponseBuilder { + private final boolean isChangeFeed; + private final Class klass; + + private Map headers = new HashMap<>(); + private boolean noMoreChangesInChangeFeed = false; + private List results; + + private FeedResponseBuilder(Class klass, boolean isChangeFeed) { + this.klass = klass; + this.isChangeFeed = isChangeFeed; + } + + public FeedResponseBuilder withContinuationToken(String continuationToken) { + + if (isChangeFeed) { + headers.put(HttpConstants.HttpHeaders.E_TAG, continuationToken); + } else { + headers.put(HttpConstants.HttpHeaders.CONTINUATION, continuationToken); + } + return this; + } + + public FeedResponseBuilder withResults(List results) { + this.results = results; + return this; + } + + public FeedResponseBuilder withResults(T... results) { + this.results = Arrays.asList(results); + return this; + } + + public FeedResponseBuilder lastChangeFeedPage() { + this.noMoreChangesInChangeFeed = true; + return this; + } + + public FeedResponse build() { + RxDocumentServiceResponse rsp = mock(RxDocumentServiceResponse.class); + when(rsp.getResponseHeaders()).thenReturn(headers); + when(rsp.getQueryResponse(klass)).thenReturn(results); + if (isChangeFeed) { + when(rsp.getStatusCode()).thenReturn(noMoreChangesInChangeFeed? + HttpConstants.StatusCodes.NOT_MODIFIED : 200); + return BridgeInternal.toChaneFeedResponsePage(rsp, klass); + } else { + return BridgeInternal.toFeedResponsePage(rsp, klass); + } + } + + public static FeedResponseBuilder queryFeedResponseBuilder(Class klass) { + return new FeedResponseBuilder(klass, false); + } + + public static FeedResponseBuilder changeFeedResponseBuilder(Class klass) { + return new FeedResponseBuilder(klass, true); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FetcherTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FetcherTest.java new file mode 100644 index 0000000000000..3260d52d6f2e4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/query/FetcherTest.java @@ -0,0 +1,231 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.query; + +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.RxDocumentServiceRequest; +import io.reactivex.subscribers.TestSubscriber; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class FetcherTest { + + @DataProvider(name = "queryParams") + public static Object[][] queryParamProvider() { + + FeedOptions options1 = new FeedOptions(); + options1.maxItemCount(100); + options1.requestContinuation("cp-init"); // initial continuation token + int top1 = -1; // no top + + // no continuation token + FeedOptions options2 = new FeedOptions(); + options2.maxItemCount(100); + int top2 = -1; // no top + + // top more than max item count + FeedOptions options3 = new FeedOptions(); + options3.maxItemCount(100); + int top3 = 200; + + // top less than max item count + FeedOptions options4 = new FeedOptions(); + options4.maxItemCount(100); + int top4 = 20; + + return new Object[][] { + { options1, top1 }, + { options2, top2 }, + { options3, top3 }, + { options4, top4 }}; + } + + @Test(groups = { "unit" }, dataProvider = "queryParams") + public void query(FeedOptions options, int top) { + + FeedResponse fp1 = FeedResponseBuilder.queryFeedResponseBuilder(Document.class) + .withContinuationToken("cp1") + .withResults(new Document(), new Document(), new Document()) + .build(); + + FeedResponse fp2 = FeedResponseBuilder.queryFeedResponseBuilder(Document.class) + .withContinuationToken(null) + .withResults(new Document()) + .build(); + + List> feedResponseList = Arrays.asList(fp1, fp2); + + AtomicInteger totalResultsReceived = new AtomicInteger(0); + + AtomicInteger requestIndex = new AtomicInteger(0); + + BiFunction createRequestFunc = (token, maxItemCount) -> { + assertThat(maxItemCount).describedAs("max item count").isEqualTo( + getExpectedMaxItemCountInRequest(options, top, feedResponseList, requestIndex.get())); + assertThat(token).describedAs("continuation token").isEqualTo( + getExpectedContinuationTokenInRequest(options.requestContinuation(), feedResponseList, requestIndex.get())); + requestIndex.getAndIncrement(); + + return mock(RxDocumentServiceRequest.class); + }; + + AtomicInteger executeIndex = new AtomicInteger(0); + + Function>> executeFunc = request -> { + FeedResponse rsp = feedResponseList.get(executeIndex.getAndIncrement()); + totalResultsReceived.addAndGet(rsp.results().size()); + return Flux.just(rsp); + }; + + Fetcher fetcher = + new Fetcher<>(createRequestFunc, executeFunc, options.requestContinuation(), false, top, + options.maxItemCount()); + + validateFetcher(fetcher, options, top, feedResponseList); + } + + private void validateFetcher(Fetcher fetcher, + FeedOptions options, + int top, + List> feedResponseList) { + + int totalNumberOfDocs = 0; + + int index = 0; + while(index < feedResponseList.size()) { + assertThat(fetcher.shouldFetchMore()).describedAs("should fetch more pages").isTrue(); + totalNumberOfDocs += validate(fetcher.nextPage()).results().size(); + + if ((top != -1) && (totalNumberOfDocs >= top)) { + break; + } + index++; + } + assertThat(fetcher.shouldFetchMore()).describedAs("should not fetch more pages").isFalse(); + } + + @Test(groups = { "unit" }) + public void changeFeed() { + + ChangeFeedOptions options = new ChangeFeedOptions(); + options.maxItemCount(100); + + boolean isChangeFeed = true; + int top = -1; + + FeedResponse fp1 = FeedResponseBuilder.changeFeedResponseBuilder(Document.class) + .withContinuationToken("cp1") + .withResults(new Document()) + .build(); + + FeedResponse fp2 = FeedResponseBuilder.changeFeedResponseBuilder(Document.class) + .withContinuationToken("cp2") + .lastChangeFeedPage() + .build(); + + List> feedResponseList = Arrays.asList(fp1, fp2); + + AtomicInteger requestIndex = new AtomicInteger(0); + + BiFunction createRequestFunc = (token, maxItemCount) -> { + assertThat(maxItemCount).describedAs("max item count").isEqualTo(options.maxItemCount()); + assertThat(token).describedAs("continuation token").isEqualTo( + getExpectedContinuationTokenInRequest(options.requestContinuation(), feedResponseList, requestIndex.getAndIncrement())); + + return mock(RxDocumentServiceRequest.class); + }; + + AtomicInteger executeIndex = new AtomicInteger(0); + + Function>> executeFunc = request -> { + return Flux.just(feedResponseList.get(executeIndex.getAndIncrement())); + }; + + Fetcher fetcher = + new Fetcher<>(createRequestFunc, executeFunc, options.requestContinuation(), isChangeFeed, top, + options.maxItemCount()); + + validateFetcher(fetcher, options, feedResponseList); + } + + private void validateFetcher(Fetcher fetcher, + ChangeFeedOptions options, + List> feedResponseList) { + + + for(FeedResponse change: feedResponseList) { + assertThat(fetcher.shouldFetchMore()).describedAs("should fetch more pages").isTrue(); + validate(fetcher.nextPage()); + } + + assertThat(fetcher.shouldFetchMore()).describedAs("should not fetch more pages").isFalse(); + } + + private FeedResponse validate(Flux> page) { + TestSubscriber> subscriber = new TestSubscriber<>(); + page.subscribe(subscriber); + subscriber.awaitTerminalEvent(); + subscriber.assertComplete(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + return subscriber.values().get(0); + } + + private String getExpectedContinuationTokenInRequest(String continuationToken, + List> feedResponseList, + int requestIndex) { + if (requestIndex == 0) { + return continuationToken; + } + + return feedResponseList.get(requestIndex - 1).continuationToken(); + } + + private int getExpectedMaxItemCountInRequest(FeedOptions options, + int top, + List> feedResponseList, + int requestIndex) { + if (top == -1) { + return options.maxItemCount(); + } + + int numberOfReceivedItemsSoFar = + feedResponseList.subList(0, requestIndex).stream().mapToInt(rsp -> rsp.results().size()).sum(); + + return Math.min(top - numberOfReceivedItemsSoFar, options.maxItemCount()); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMapTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMapTest.java new file mode 100644 index 0000000000000..944d32f179dca --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/InMemoryCollectionRoutingMapTest.java @@ -0,0 +1,270 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; +import com.google.common.collect.ImmutableList; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import static org.assertj.core.api.Assertions.assertThat; + +public class InMemoryCollectionRoutingMapTest { + + static class ServerIdentityImp implements IServerIdentity { + private int value; + public ServerIdentityImp(int value) { + this.value = value; + } + + static ServerIdentityImp of(int value) { + return new ServerIdentityImp(value); + } + } + + @Test(groups = { "unit" }) + public void collectionRoutingMap() { + InMemoryCollectionRoutingMap routingMap = InMemoryCollectionRoutingMap + .tryCreateCompleteRoutingMap(Arrays.asList( + new ImmutablePair<>( + new PartitionKeyRange("2", "0000000050", "0000000070"), ServerIdentityImp.of(2)), + new ImmutablePair<>(new PartitionKeyRange("0", "", "0000000030"), + ServerIdentityImp.of(0)), + new ImmutablePair<>( + new PartitionKeyRange("1", "0000000030", "0000000050"), ServerIdentityImp.of(1)), + new ImmutablePair<>(new PartitionKeyRange("3", "0000000070", "FF"), + ServerIdentityImp.of(3))), + StringUtils.EMPTY); + + assertThat("0").isEqualTo(routingMap.getOrderedPartitionKeyRanges().get(0).id()); + assertThat("1").isEqualTo(routingMap.getOrderedPartitionKeyRanges().get(1).id()); + assertThat("2").isEqualTo(routingMap.getOrderedPartitionKeyRanges().get(2).id()); + assertThat("3").isEqualTo(routingMap.getOrderedPartitionKeyRanges().get(3).id()); + + + assertThat("0").isEqualTo(routingMap.getRangeByEffectivePartitionKey("").id()); + assertThat("0").isEqualTo(routingMap.getRangeByEffectivePartitionKey("0000000000").id()); + assertThat("1").isEqualTo(routingMap.getRangeByEffectivePartitionKey("0000000030").id()); + assertThat("1").isEqualTo(routingMap.getRangeByEffectivePartitionKey("0000000031").id()); + assertThat("3").isEqualTo(routingMap.getRangeByEffectivePartitionKey("0000000071").id()); + + assertThat("0").isEqualTo(routingMap.getRangeByPartitionKeyRangeId("0").id()); + assertThat("1").isEqualTo(routingMap.getRangeByPartitionKeyRangeId("1").id()); + + assertThat(4).isEqualTo( + routingMap + .getOverlappingRanges(Collections.singletonList(new Range(PartitionKeyRange.MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY, + PartitionKeyRange.MAXIMUM_EXCLUSIVE_EFFECTIVE_PARTITION_KEY, true, false))) + .size()); + assertThat(0).isEqualTo( + routingMap + .getOverlappingRanges(Collections.singletonList(new Range(PartitionKeyRange.MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY, + PartitionKeyRange.MINIMUM_INCLUSIVE_EFFECTIVE_PARTITION_KEY, false, false))) + .size()); + + Collection partitionKeyRanges = routingMap + .getOverlappingRanges(Collections.singletonList(new Range("0000000040", "0000000040", true, true))); + + assertThat(1).isEqualTo(partitionKeyRanges.size()); + Iterator iterator = partitionKeyRanges.iterator(); + assertThat("1").isEqualTo(iterator.next().id()); + + Collection partitionKeyRanges1 = routingMap + .getOverlappingRanges(Arrays.asList(new Range("0000000040", "0000000045", true, true), + new Range("0000000045", "0000000046", true, true), + new Range("0000000046", "0000000050", true, true))); + + assertThat(2).isEqualTo(partitionKeyRanges1.size()); + Iterator iterator1 = partitionKeyRanges1.iterator(); + assertThat("1").isEqualTo(iterator1.next().id()); + assertThat("2").isEqualTo(iterator1.next().id()); + } + + @Test(groups = { "unit" }, expectedExceptions = IllegalStateException.class) + public void invalidRoutingMap() { + InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(Arrays.asList( + new ImmutablePair<>(new PartitionKeyRange("1", "0000000020", "0000000030"), + ServerIdentityImp.of(2)), + new ImmutablePair<>(new PartitionKeyRange("2", "0000000025", "0000000035"), + ServerIdentityImp.of(2))), + StringUtils.EMPTY); + } + + @Test(groups = { "unit" }) + public void incompleteRoutingMap() { + InMemoryCollectionRoutingMap routingMap = InMemoryCollectionRoutingMap + .tryCreateCompleteRoutingMap(Arrays.asList( + new ImmutablePair<>(new PartitionKeyRange("2", "", "0000000030"), + ServerIdentityImp.of(2)), + new ImmutablePair<>(new PartitionKeyRange("3", "0000000031", "FF"), + ServerIdentityImp.of(2))), + StringUtils.EMPTY); + + assertThat(routingMap).isNull(); + + routingMap = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(Arrays.asList( + new ImmutablePair<>(new PartitionKeyRange("2", "", "0000000030"), ServerIdentityImp.of(2)), + new ImmutablePair<>(new PartitionKeyRange("3", "0000000030", "FF"), ServerIdentityImp.of(2))), + StringUtils.EMPTY); + + assertThat(routingMap).isNotNull(); + } + + @Test(groups = {"unit"}) + public void goneRanges() { + CollectionRoutingMap routingMap = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap( + ImmutableList.of( + new ImmutablePair(new PartitionKeyRange("2", "", "0000000030", ImmutableList.of("1", "0")), null), + new ImmutablePair(new PartitionKeyRange("3", "0000000030", "0000000032", ImmutableList.of("5")), null), + new ImmutablePair(new PartitionKeyRange("4", "0000000032", "FF"), null)), + StringUtils.EMPTY); + + assertThat(routingMap.IsGone("1")).isTrue(); + assertThat(routingMap.IsGone("0")).isTrue(); + assertThat(routingMap.IsGone("5")).isTrue(); + + assertThat(routingMap.IsGone("2")).isFalse(); + assertThat(routingMap.IsGone("3")).isFalse(); + assertThat(routingMap.IsGone("4")).isFalse(); + assertThat(routingMap.IsGone("100")).isFalse(); + } + + @Test(groups = {"unit"}) + public void tryCombineRanges() { + CollectionRoutingMap routingMap = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap( + ImmutableList.of( + new ImmutablePair( + new PartitionKeyRange( + "2", + "0000000050", + "0000000070"), + null), + + new ImmutablePair( + new PartitionKeyRange( + "0", + "", + "0000000030"), + null), + + new ImmutablePair( + new PartitionKeyRange( + "1", + "0000000030", + "0000000050"), + null), + + new ImmutablePair( + new PartitionKeyRange( + "3", + "0000000070", + "FF"), + null) + ), StringUtils.EMPTY); + + CollectionRoutingMap newRoutingMap = routingMap.tryCombine( + ImmutableList.of( + new ImmutablePair( + new PartitionKeyRange( + "4", + "", + "0000000010", + ImmutableList.of("0") + ), + null), + + new ImmutablePair( + new PartitionKeyRange( + "5", + "0000000010", + "0000000030", + ImmutableList.of("0") + ), + null) + )); + + assertThat(newRoutingMap).isNotNull(); + + newRoutingMap = routingMap.tryCombine( + ImmutableList.of( + new ImmutablePair( + new PartitionKeyRange( + "6", + "", + "0000000005", + ImmutableList.of("0", "4") + ), + null), + + new ImmutablePair( + new PartitionKeyRange( + "7", + "0000000005", + "0000000010", + ImmutableList.of("0", "4") + ), + null), + + new ImmutablePair( + new PartitionKeyRange( + "8", + "0000000010", + "0000000015", + ImmutableList.of("0", "5") + ), + null), + + new ImmutablePair( + new PartitionKeyRange( + "9", + "0000000015", + "0000000030", + ImmutableList.of("0", "5") + ), + null) + )); + + assertThat(newRoutingMap).isNotNull(); + + newRoutingMap = routingMap.tryCombine( + ImmutableList.of( + new ImmutablePair( + new PartitionKeyRange( + "10", + "", + "0000000002", + ImmutableList.of("0", "4", "6") + ), + null) + )); + + assertThat(newRoutingMap).isNull(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/LocationCacheTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/LocationCacheTest.java new file mode 100644 index 0000000000000..a61f303c754e6 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/LocationCacheTest.java @@ -0,0 +1,439 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.BridgeUtils; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.internal.DatabaseAccount; +import com.azure.data.cosmos.internal.DatabaseAccountLocation; +import com.azure.data.cosmos.internal.DatabaseAccountManagerInternal; +import com.azure.data.cosmos.internal.*; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import org.apache.commons.collections4.list.UnmodifiableList; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import static com.azure.data.cosmos.BridgeUtils.createDatabaseAccountLocation; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link LocationCache} + */ +public class LocationCacheTest { + private final static URL DefaultEndpoint = createUrl("https://default.documents.azure.com"); + private final static URL Location1Endpoint = createUrl("https://location1.documents.azure.com"); + private final static URL Location2Endpoint = createUrl("https://location2.documents.azure.com"); + private final static URL Location3Endpoint = createUrl("https://location3.documents.azure.com"); + private final static URL Location4Endpoint = createUrl("https://location4.documents.azure.com"); + + private static HashMap EndpointByLocation = new HashMap<>(); + + static { + EndpointByLocation.put("location1", LocationCacheTest.Location1Endpoint); + EndpointByLocation.put("location2", LocationCacheTest.Location2Endpoint); + EndpointByLocation.put("location3", LocationCacheTest.Location3Endpoint); + EndpointByLocation.put("location4", LocationCacheTest.Location4Endpoint); + } + + private final Configs configs = new Configs() { + @Override + public int getUnavailableLocationsExpirationTimeInSeconds() { + return 3; + } + }; + + private UnmodifiableList preferredLocations; + private DatabaseAccount databaseAccount; + private LocationCache cache; + private GlobalEndpointManager endpointManager; + private DatabaseAccountManagerInternalMock mockedClient; + + @DataProvider(name = "paramsProvider") + public Object[][] paramsProvider() { + // provides all possible combinations for + // useMultipleWriteEndpoints, endpointDiscoveryEnabled, isPreferredListEmpty + List list = new ArrayList<>(); + for (int i = 0; i < 8; i++) { + boolean useMultipleWriteEndpoints = (i & 1) > 0; + boolean endpointDiscoveryEnabled = (i & 2) > 0; + boolean isPreferredListEmpty = (i & 4) > 0; + list.add(new Object[]{useMultipleWriteEndpoints, endpointDiscoveryEnabled, isPreferredListEmpty}); + } + + return list.toArray(new Object[][]{}); + } + + @Test(groups = "long", dataProvider = "paramsProvider") + public void validateAsync(boolean useMultipleWriteEndpoints, + boolean endpointDiscoveryEnabled, + boolean isPreferredListEmpty) throws Exception { + validateLocationCacheAsync(useMultipleWriteEndpoints, + endpointDiscoveryEnabled, + isPreferredListEmpty); + } + + @Test(groups = "long") + public void validateWriteEndpointOrderWithClientSideDisableMultipleWriteLocation() throws Exception { + this.initialize(false, true, false); + assertThat(this.cache.getWriteEndpoints().get(0)).isEqualTo(LocationCacheTest.Location1Endpoint); + assertThat(this.cache.getWriteEndpoints().get(1)).isEqualTo(LocationCacheTest.Location2Endpoint); + assertThat(this.cache.getWriteEndpoints().get(2)).isEqualTo(LocationCacheTest.Location3Endpoint); + } + + private static DatabaseAccount createDatabaseAccount(boolean useMultipleWriteLocations) { + DatabaseAccount databaseAccount = BridgeUtils.createDatabaseAccount( + // read endpoints + ImmutableList.of( + createDatabaseAccountLocation("location1", LocationCacheTest.Location1Endpoint.toString()), + createDatabaseAccountLocation("location2", LocationCacheTest.Location2Endpoint.toString()), + createDatabaseAccountLocation("location4", LocationCacheTest.Location4Endpoint.toString())), + + // write endpoints + ImmutableList.of( + createDatabaseAccountLocation("location1", LocationCacheTest.Location1Endpoint.toString()), + createDatabaseAccountLocation("location2", LocationCacheTest.Location2Endpoint.toString()), + createDatabaseAccountLocation("location3", LocationCacheTest.Location3Endpoint.toString())), + // if the account supports multi master multi muster + useMultipleWriteLocations); + + return databaseAccount; + } + + private void initialize( + boolean useMultipleWriteLocations, + boolean enableEndpointDiscovery, + boolean isPreferredLocationsListEmpty) throws Exception { + + this.mockedClient = new DatabaseAccountManagerInternalMock(); + this.databaseAccount = LocationCacheTest.createDatabaseAccount(useMultipleWriteLocations); + + this.preferredLocations = isPreferredLocationsListEmpty ? + new UnmodifiableList<>(Collections.emptyList()) : + new UnmodifiableList<>(ImmutableList.of("location1", "location2", "location3")); + + this.cache = new LocationCache( + this.preferredLocations, + LocationCacheTest.DefaultEndpoint, + enableEndpointDiscovery, + useMultipleWriteLocations, + configs); + + this.cache.onDatabaseAccountRead(this.databaseAccount); + + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.enableEndpointDiscovery(enableEndpointDiscovery); + BridgeInternal.setUseMultipleWriteLocations(connectionPolicy, useMultipleWriteLocations); + connectionPolicy.preferredLocations(this.preferredLocations); + + this.endpointManager = new GlobalEndpointManager(mockedClient, connectionPolicy, configs); + } + + class DatabaseAccountManagerInternalMock implements DatabaseAccountManagerInternal { + private final AtomicInteger counter = new AtomicInteger(0); + + private void reset() { + counter.set(0); + } + + private int getInvocationCounter() { + return counter.get(); + } + + @Override + public Flux getDatabaseAccountFromEndpoint(URI endpoint) { + return Flux.just(LocationCacheTest.this.databaseAccount); + } + + @Override + public ConnectionPolicy getConnectionPolicy() { + throw new RuntimeException("not supported"); + } + + @Override + public URI getServiceEndpoint() { + try { + return LocationCacheTest.DefaultEndpoint.toURI(); + } catch (Exception e) { + throw new RuntimeException(); + } + } + } + + private static Stream toStream(Iterable iterable) { + return StreamSupport.stream(iterable.spliterator(), false); + } + + private void validateLocationCacheAsync( + boolean useMultipleWriteLocations, + boolean endpointDiscoveryEnabled, + boolean isPreferredListEmpty) throws Exception { + for (int writeLocationIndex = 0; writeLocationIndex < 3; writeLocationIndex++) { + for (int readLocationIndex = 0; readLocationIndex < 2; readLocationIndex++) { + this.initialize( + useMultipleWriteLocations, + endpointDiscoveryEnabled, + isPreferredListEmpty); + + UnmodifiableList currentWriteEndpoints = this.cache.getWriteEndpoints(); + UnmodifiableList currentReadEndpoints = this.cache.getReadEndpoints(); + for (int i = 0; i < readLocationIndex; i++) { + this.cache.markEndpointUnavailableForRead(createUrl(Iterables.get(this.databaseAccount.getReadableLocations(), i).getEndpoint())); + this.endpointManager.markEndpointUnavailableForRead(createUrl(Iterables.get(this.databaseAccount.getReadableLocations(), i).getEndpoint()));; + } + for (int i = 0; i < writeLocationIndex; i++) { + this.cache.markEndpointUnavailableForWrite(createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), i).getEndpoint())); + this.endpointManager.markEndpointUnavailableForWrite(createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), i).getEndpoint())); + } + + Map writeEndpointByLocation = toStream(this.databaseAccount.getWritableLocations()) + .collect(Collectors.toMap(i -> i.getName(), i -> createUrl(i.getEndpoint()))); + + Map readEndpointByLocation = toStream(this.databaseAccount.getReadableLocations()) + .collect(Collectors.toMap(i -> i.getName(), i -> createUrl(i.getEndpoint()))); + + URL[] preferredAvailableWriteEndpoints = toStream(this.preferredLocations).skip(writeLocationIndex) + .filter(location -> writeEndpointByLocation.containsKey(location)) + .map(location -> writeEndpointByLocation.get(location)) + .collect(Collectors.toList()).toArray(new URL[0]); + + URL[] preferredAvailableReadEndpoints = toStream(this.preferredLocations).skip(readLocationIndex) + .filter(location -> readEndpointByLocation.containsKey(location)) + .map(location -> readEndpointByLocation.get(location)) + .collect(Collectors.toList()).toArray(new URL[0]); + + this.validateEndpointRefresh( + useMultipleWriteLocations, + endpointDiscoveryEnabled, + preferredAvailableWriteEndpoints, + preferredAvailableReadEndpoints, + writeLocationIndex > 0); + + this.validateGlobalEndpointLocationCacheRefreshAsync(); + + this.validateRequestEndpointResolution( + useMultipleWriteLocations, + endpointDiscoveryEnabled, + preferredAvailableWriteEndpoints, + preferredAvailableReadEndpoints); + + // wait for TTL on unavailability info + + TimeUnit.SECONDS.sleep(configs.getUnavailableLocationsExpirationTimeInSeconds() + 1); + + assertThat(currentWriteEndpoints.toArray()).containsExactly(this.cache.getWriteEndpoints().toArray()); + assertThat(currentReadEndpoints.toArray()).containsExactly(this.cache.getReadEndpoints().toArray()); + } + } + } + + private void validateEndpointRefresh( + boolean useMultipleWriteLocations, + boolean endpointDiscoveryEnabled, + URL[] preferredAvailableWriteEndpoints, + URL[] preferredAvailableReadEndpoints, + boolean isFirstWriteEndpointUnavailable) { + + Utils.ValueHolder canRefreshInBackgroundHolder = new Utils.ValueHolder<>(); + canRefreshInBackgroundHolder.v = false; + + boolean shouldRefreshEndpoints = this.cache.shouldRefreshEndpoints(canRefreshInBackgroundHolder); + + boolean isMostPreferredLocationUnavailableForRead = false; + boolean isMostPreferredLocationUnavailableForWrite = useMultipleWriteLocations ? + false : isFirstWriteEndpointUnavailable; + if (this.preferredLocations.size() > 0) { + String mostPreferredReadLocationName = this.preferredLocations.stream() + .filter(location -> toStream(databaseAccount.getReadableLocations()) + .anyMatch(readLocation -> readLocation.getName().equals(location))) + .findFirst().orElse(null); + + URL mostPreferredReadEndpoint = LocationCacheTest.EndpointByLocation.get(mostPreferredReadLocationName); + isMostPreferredLocationUnavailableForRead = preferredAvailableReadEndpoints.length == 0 ? + true : (!areEqual(preferredAvailableReadEndpoints[0], mostPreferredReadEndpoint)); + + String mostPreferredWriteLocationName = this.preferredLocations.stream() + .filter(location -> toStream(databaseAccount.getWritableLocations()) + .anyMatch(writeLocation -> writeLocation.getName().equals(location))) + .findFirst().orElse(null); + + URL mostPreferredWriteEndpoint = LocationCacheTest.EndpointByLocation.get(mostPreferredWriteLocationName); + + if (useMultipleWriteLocations) { + isMostPreferredLocationUnavailableForWrite = preferredAvailableWriteEndpoints.length == 0 ? + true : (!areEqual(preferredAvailableWriteEndpoints[0], mostPreferredWriteEndpoint)); + } + } + + if (!endpointDiscoveryEnabled) { + assertThat(shouldRefreshEndpoints).isFalse(); + } else { + assertThat(shouldRefreshEndpoints).isEqualTo( + isMostPreferredLocationUnavailableForRead || isMostPreferredLocationUnavailableForWrite); + } + + if (shouldRefreshEndpoints) { + assertThat(canRefreshInBackgroundHolder.v).isTrue(); + } + } + + private boolean areEqual(URL url1, URL url2) { + return url1.equals(url2); + } + + private void validateGlobalEndpointLocationCacheRefreshAsync() throws Exception { + + mockedClient.reset(); + List> list = IntStream.range(0, 10) + .mapToObj(index -> this.endpointManager.refreshLocationAsync(null)) + .collect(Collectors.toList()); + + Flux.merge(list).then().block(); + + assertThat(mockedClient.getInvocationCounter()).isLessThanOrEqualTo(1); + mockedClient.reset(); + + IntStream.range(0, 10) + .mapToObj(index -> this.endpointManager.refreshLocationAsync(null)) + .collect(Collectors.toList()); + for (Mono completable : list) { + completable.block(); + } + + assertThat(mockedClient.getInvocationCounter()).isLessThanOrEqualTo(1); + } + + private void validateRequestEndpointResolution( + boolean useMultipleWriteLocations, + boolean endpointDiscoveryEnabled, + URL[] availableWriteEndpoints, + URL[] availableReadEndpoints) throws MalformedURLException { + URL firstAvailableWriteEndpoint; + URL secondAvailableWriteEndpoint; + + if (!endpointDiscoveryEnabled) { + firstAvailableWriteEndpoint = LocationCacheTest.DefaultEndpoint; + secondAvailableWriteEndpoint = LocationCacheTest.DefaultEndpoint; + } else if (!useMultipleWriteLocations) { + firstAvailableWriteEndpoint = createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), 0).getEndpoint()); + secondAvailableWriteEndpoint = createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), 1).getEndpoint()); + } else if (availableWriteEndpoints.length > 1) { + firstAvailableWriteEndpoint = availableWriteEndpoints[0]; + secondAvailableWriteEndpoint = availableWriteEndpoints[1]; + } else if (availableWriteEndpoints.length > 0) { + firstAvailableWriteEndpoint = availableWriteEndpoints[0]; + Iterator writeLocationsIterator = databaseAccount.getWritableLocations().iterator(); + String writeEndpoint = writeLocationsIterator.next().getEndpoint(); + secondAvailableWriteEndpoint = writeEndpoint != firstAvailableWriteEndpoint.toString() + ? new URL(writeEndpoint) + : new URL(writeLocationsIterator.next().getEndpoint()); + } else { + firstAvailableWriteEndpoint = LocationCacheTest.DefaultEndpoint; + secondAvailableWriteEndpoint = LocationCacheTest.DefaultEndpoint; + } + + URL firstAvailableReadEndpoint; + + if (!endpointDiscoveryEnabled) { + firstAvailableReadEndpoint = LocationCacheTest.DefaultEndpoint; + } else if (this.preferredLocations.size() == 0) { + firstAvailableReadEndpoint = firstAvailableWriteEndpoint; + } else if (availableReadEndpoints.length > 0) { + firstAvailableReadEndpoint = availableReadEndpoints[0]; + } else { + firstAvailableReadEndpoint = LocationCacheTest.EndpointByLocation.get(this.preferredLocations.get(0)); + } + + URL firstWriteEnpoint = !endpointDiscoveryEnabled ? + LocationCacheTest.DefaultEndpoint : + createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), 0).getEndpoint()); + + URL secondWriteEnpoint = !endpointDiscoveryEnabled ? + LocationCacheTest.DefaultEndpoint : + createUrl(Iterables.get(this.databaseAccount.getWritableLocations(), 1).getEndpoint()); + + // If current write endpoint is unavailable, write endpoints order doesn't change + // ALL write requests flip-flop between current write and alternate write endpoint + UnmodifiableList writeEndpoints = this.cache.getWriteEndpoints(); + + assertThat(firstAvailableWriteEndpoint).isEqualTo(writeEndpoints.get(0)); + assertThat(secondAvailableWriteEndpoint).isEqualTo(this.resolveEndpointForWriteRequest(ResourceType.Document, true)); + assertThat(firstAvailableWriteEndpoint).isEqualTo(this.resolveEndpointForWriteRequest(ResourceType.Document, false)); + + // Writes to other resource types should be directed to first/second write endpoint + assertThat(firstWriteEnpoint).isEqualTo(this.resolveEndpointForWriteRequest(ResourceType.Database, false)); + assertThat(secondWriteEnpoint).isEqualTo(this.resolveEndpointForWriteRequest(ResourceType.Database, true)); + + // Reads should be directed to available read endpoints regardless of resource type + assertThat(firstAvailableReadEndpoint).isEqualTo(this.resolveEndpointForReadRequest(true)); + assertThat(firstAvailableReadEndpoint).isEqualTo(this.resolveEndpointForReadRequest(false)); + } + + private URL resolveEndpointForReadRequest(boolean masterResourceType) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Read, + masterResourceType ? ResourceType.Database : ResourceType.Document); + return this.cache.resolveServiceEndpoint(request); + } + + private URL resolveEndpointForWriteRequest(ResourceType resourceType, boolean useAlternateWriteEndpoint) { + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Create, resourceType); + request.requestContext.RouteToLocation(useAlternateWriteEndpoint ? 1 : 0, resourceType.isCollectionChild()); + return this.cache.resolveServiceEndpoint(request); + } + + private RxDocumentServiceRequest CreateRequest(boolean isReadRequest, boolean isMasterResourceType) + { + if (isReadRequest) { + return RxDocumentServiceRequest.create(OperationType.Read, isMasterResourceType ? ResourceType.Database : ResourceType.Document); + } else { + return RxDocumentServiceRequest.create(OperationType.Create, isMasterResourceType ? ResourceType.Database : ResourceType.Document); + } + } + private static URL createUrl(String url) { + try { + return new URL(url); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalUtils.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalUtils.java new file mode 100644 index 0000000000000..5751d70a08d51 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/PartitionKeyInternalUtils.java @@ -0,0 +1,35 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.google.common.collect.ImmutableList; + +public class PartitionKeyInternalUtils { + + public static PartitionKeyInternal createPartitionKeyInternal(String str) { + return new PartitionKeyInternal(ImmutableList.of( + new StringPartitionKeyComponent(str))); + + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelperTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelperTest.java new file mode 100644 index 0000000000000..e8ed44a2fca5e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/RoutingMapProviderHelperTest.java @@ -0,0 +1,149 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.internal.routing; + +import com.azure.data.cosmos.internal.PartitionKeyRange; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RoutingMapProviderHelperTest { + private static final MockRoutingMapProvider ROUTING_MAP_PROVIDER = new MockRoutingMapProvider( + Arrays.asList(new PartitionKeyRange("0", "", "000A"), new PartitionKeyRange("1", "000A", "000D"), + new PartitionKeyRange("2", "000D", "0012"), new PartitionKeyRange("3", "0012", "0015"), + new PartitionKeyRange("4", "0015", "0020"), new PartitionKeyRange("5", "0020", "0040"), + new PartitionKeyRange("6", "0040", "FF"))); + + private static class MockRoutingMapProvider implements RoutingMapProvider { + private final CollectionRoutingMap routingMap; + + public MockRoutingMapProvider(Collection ranges) { + List> pairs = new ArrayList<>( + ranges.size()); + for (PartitionKeyRange range : ranges) { + pairs.add(new ImmutablePair<>(range, null)); + } + + this.routingMap = InMemoryCollectionRoutingMap.tryCreateCompleteRoutingMap(pairs, StringUtils.EMPTY); + } + + @Override + public Collection getOverlappingRanges(String collectionIdOrNameBasedLink, + Range range, boolean forceRefresh) { + return this.routingMap.getOverlappingRanges(range); + } + + @Override + public PartitionKeyRange tryGetRangeByEffectivePartitionKey(String collectionRid, String effectivePartitionKey) { + return null; + } + + @Override + public PartitionKeyRange getPartitionKeyRangeById(String collectionLink, String partitionKeyRangeId, boolean forceRefresh) { + return null; + } + } + + @Test(groups = { "unit" }, expectedExceptions = IllegalArgumentException.class) + public void nonSortedRanges() { + RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Arrays.asList(new Range("0B", "0B", true, true), new Range("0A", "0A", true, true))); + } + + @Test(groups = { "unit" }, expectedExceptions = IllegalArgumentException.class) + public void overlappingRanges1() { + RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Arrays.asList(new Range("0A", "0D", true, true), new Range("0B", "0E", true, true))); + } + + @Test(groups = { "unit" }, expectedExceptions = IllegalArgumentException.class) + public void overlappingRanges2() { + RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Arrays.asList(new Range("0A", "0D", true, true), new Range("0D", "0E", true, true))); + } + + @Test(groups = { "unit" }) + public void getOverlappingRanges() { + Collection ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, + "dbs/db1/colls/coll1", + Arrays.asList(new Range("000B", "000E", true, false), + new Range("000E", "000F", true, false), new Range("000F", "0010", true, true), + new Range("0015", "0015", true, true))); + + Function func = new Function() { + @Override + public String apply(PartitionKeyRange range) { + return range.id(); + } + }; + + assertThat("1,2,4").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + + // query for minimal point + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Collections.singletonList(new Range("", "", true, true))); + + assertThat("0").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + + // query for empty range + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Collections.singletonList(new Range("", "", true, false))); + + assertThat(0).isEqualTo(ranges.size()); + + // entire range + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Collections.singletonList(new Range("", "FF", true, false))); + + assertThat("0,1,2,3,4,5,6").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + + // matching range + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Collections.singletonList(new Range("0012", "0015", true, false))); + + assertThat("3").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + + // matching range with empty ranges + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Arrays.asList(new Range("", "", true, false), new Range("0012", "0015", true, false))); + + assertThat("3").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + + // matching range and a little bit more. + ranges = RoutingMapProviderHelper.getOverlappingRanges(ROUTING_MAP_PROVIDER, "dbs/db1/colls/coll1", + Collections.singletonList(new Range("0012", "0015", false, true))); + + assertThat("3,4").isEqualTo(ranges.stream().map(func).collect(Collectors.joining(","))); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponentTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponentTest.java new file mode 100644 index 0000000000000..fb8eccd8aed03 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/internal/routing/StringPartitionKeyComponentTest.java @@ -0,0 +1,25 @@ +package com.azure.data.cosmos.internal.routing; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StringPartitionKeyComponentTest { + @DataProvider(name = "paramProvider") + public Object[][] paramProvider() { + return new Object[][] { + {"Friday", "Friday", 0}, + {"Friday", "Venerdì", -1}, + {"Fri", "Ven", -1}, + }; + } + + @Test(groups = { "unit" }, dataProvider = "paramProvider") + public void compare(String str1, String str2, int expectedCompare) { + StringPartitionKeyComponent spkc1 = new StringPartitionKeyComponent(str1); + StringPartitionKeyComponent spkc2 = new StringPartitionKeyComponent(str2); + + assertThat(Integer.signum(spkc1.CompareTo(spkc2))).isEqualTo(Integer.signum(expectedCompare)); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/AggregateQueryTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/AggregateQueryTests.java new file mode 100644 index 0000000000000..f206d107c2283 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/AggregateQueryTests.java @@ -0,0 +1,214 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.UUID; + +public class AggregateQueryTests extends TestSuiteBase { + + public static class QueryConfig { + String testName; + String query; + Object expected; + + public QueryConfig (String testName, String query, Object expected) { + this.testName = testName; + this.query = query; + this.expected = expected; + } + } + + public static class AggregateConfig { + String operator; + Object expected; + String condition; + + public AggregateConfig(String operator, Object expected, String condition) { + this.operator = operator; + this.expected = expected; + this.condition = condition; + } + } + + private CosmosContainer createdCollection; + private ArrayList docs = new ArrayList(); + private ArrayList queryConfigs = new ArrayList(); + + private String partitionKey = "mypk"; + private String uniquePartitionKey = "uniquePartitionKey"; + private String field = "field"; + private int sum; + private int numberOfDocuments = 800; + private int numberOfDocumentsWithNumericId; + private int numberOfDocsWithSamePartitionKey = 400; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public AggregateQueryTests(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = 2 * TIMEOUT, dataProvider = "queryMetricsArgProvider") + public void queryDocumentsWithAggregates(boolean qmEnabled) throws Exception { + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(qmEnabled); + options.maxDegreeOfParallelism(2); + + for (QueryConfig queryConfig : queryConfigs) { + + Flux> queryObservable = createdCollection.queryItems(queryConfig.query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .withAggregateValue(queryConfig.expected) + .numberOfPages(1) + .hasValidQueryMetrics(qmEnabled) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + } + + public void bulkInsert() { + generateTestData(); + voidBulkInsertBlocking(createdCollection, docs); + } + + public void generateTestData() { + + Object[] values = new Object[]{null, false, true, "abc", "cdfg", "opqrs", "ttttttt", "xyz", "oo", "ppp"}; + for (int i = 0; i < values.length; i++) { + CosmosItemProperties d = new CosmosItemProperties(); + d.id(UUID.randomUUID().toString()); + BridgeInternal.setProperty(d, partitionKey, values[i]); + docs.add(d); + } + + for (int i = 0; i < numberOfDocsWithSamePartitionKey; i++) { + CosmosItemProperties d = new CosmosItemProperties(); + BridgeInternal.setProperty(d, partitionKey, uniquePartitionKey); + BridgeInternal.setProperty(d, "resourceId", Integer.toString(i)); + BridgeInternal.setProperty(d, field, i + 1); + d.id(UUID.randomUUID().toString()); + docs.add(d); + } + + numberOfDocumentsWithNumericId = numberOfDocuments - values.length - numberOfDocsWithSamePartitionKey; + for (int i = 0; i < numberOfDocumentsWithNumericId; i++) { + CosmosItemProperties d = new CosmosItemProperties(); + BridgeInternal.setProperty(d, partitionKey, i + 1); + d.id(UUID.randomUUID().toString()); + docs.add(d); + } + + sum = (int) (numberOfDocumentsWithNumericId * (numberOfDocumentsWithNumericId + 1) / 2.0); + + } + + public void generateTestConfigs() { + + String aggregateQueryFormat = "SELECT VALUE %s(r.%s) FROM r WHERE %s"; + AggregateConfig[] aggregateConfigs = new AggregateConfig[] { + new AggregateConfig("AVG", sum / numberOfDocumentsWithNumericId, String.format("IS_NUMBER(r.%s)", partitionKey)), + new AggregateConfig("AVG", null, "true"), + new AggregateConfig("COUNT", numberOfDocuments, "true"), + new AggregateConfig("MAX","xyz","true"), + new AggregateConfig("MIN", null, "true"), + new AggregateConfig("SUM", sum, String.format("IS_NUMBER(r.%s)", partitionKey)), + new AggregateConfig("SUM", null, "true") + }; + + for (AggregateConfig config: aggregateConfigs) { + String query = String.format(aggregateQueryFormat, config.operator, partitionKey, config.condition); + String testName = String.format("%s %s", config.operator, config.condition); + queryConfigs.add(new QueryConfig(testName, query, config.expected)); + } + + String aggregateSinglePartitionQueryFormat = "SELECT VALUE %s(r.%s) FROM r WHERE r.%s = '%s'"; + String aggregateSinglePartitionQueryFormatSelect = "SELECT %s(r.%s) FROM r WHERE r.%s = '%s'"; + double samePartitionSum = numberOfDocsWithSamePartitionKey * (numberOfDocsWithSamePartitionKey + 1) / 2.0; + + AggregateConfig[] aggregateSinglePartitionConfigs = new AggregateConfig[] { + new AggregateConfig("AVG", samePartitionSum / numberOfDocsWithSamePartitionKey, null), + new AggregateConfig("COUNT", numberOfDocsWithSamePartitionKey, null), + new AggregateConfig("MAX", numberOfDocsWithSamePartitionKey, null), + new AggregateConfig("MIN", 1, null), + new AggregateConfig("SUM", samePartitionSum, null) + }; + + for (AggregateConfig config: aggregateSinglePartitionConfigs) { + String query = String.format(aggregateSinglePartitionQueryFormat, config.operator, field, partitionKey, uniquePartitionKey); + String testName = String.format("%s SinglePartition %s", config.operator, "SELECT VALUE"); + queryConfigs.add(new QueryConfig(testName, query, config.expected)); + + query = String.format(aggregateSinglePartitionQueryFormatSelect, config.operator, field, partitionKey, uniquePartitionKey); + testName = String.format("%s SinglePartition %s", config.operator, "SELECT"); + queryConfigs.add(new QueryConfig(testName, query, new Document("{'$1':" + removeTrailingZerosIfInteger(config.expected) + "}"))); + } + } + + private Object removeTrailingZerosIfInteger(Object obj) { + if (obj instanceof Number) { + Number num = (Number) obj; + if (num.doubleValue() == num.intValue()) { + return num.intValue(); + } + } + return obj; + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT * 2) + public void beforeClass() throws Exception { + client = this.clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + bulkInsert(); + generateTestConfigs(); + + waitIfNeededForReplicasToCatchUp(this.clientBuilder()); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureCrossPartitionTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureCrossPartitionTest.java new file mode 100644 index 0000000000000..91b1a8d53952c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureCrossPartitionTest.java @@ -0,0 +1,229 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ClientUnderTestBuilder; +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RxDocumentClientUnderTest; +import com.azure.data.cosmos.internal.TestUtils; +import io.reactivex.subscribers.TestSubscriber; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; +import reactor.util.concurrent.Queues; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BackPressureCrossPartitionTest extends TestSuiteBase { + private final Logger log = LoggerFactory.getLogger(BackPressureCrossPartitionTest.class); + + private static final int TIMEOUT = 1800000; + private static final int SETUP_TIMEOUT = 60000; + + private int numberOfDocs = 4000; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; + private int numberOfPartitions; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + static protected CosmosContainerProperties getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties( + UUID.randomUUID().toString(), + partitionKeyDef); + collectionDefinition.indexingPolicy(indexingPolicy); + + return collectionDefinition; + } + + @Factory(dataProvider = "simpleClientBuildersWithDirectHttps") + public BackPressureCrossPartitionTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + private void warmUp() { + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + // ensure collection is cached + createdCollection.queryItems("SELECT * FROM r", options).blockFirst(); + } + + @DataProvider(name = "queryProvider") + public Object[][] queryProvider() { + return new Object[][] { + // query, maxItemCount, max expected back pressure buffered, total number of expected query results + { "SELECT * FROM r", 1, 2 * Queues.SMALL_BUFFER_SIZE, numberOfDocs}, + { "SELECT * FROM r", 100, 2 * Queues.SMALL_BUFFER_SIZE, numberOfDocs}, + { "SELECT * FROM r ORDER BY r.prop", 100, 2 * Queues.SMALL_BUFFER_SIZE + 3 * numberOfPartitions, numberOfDocs}, + { "SELECT TOP 1000 * FROM r", 1, 2 * Queues.SMALL_BUFFER_SIZE, 1000}, + { "SELECT TOP 1000 * FROM r", 100, 2 * Queues.SMALL_BUFFER_SIZE, 1000}, + { "SELECT TOP 1000 * FROM r ORDER BY r.prop", 100, 2 * Queues.SMALL_BUFFER_SIZE + 3 * numberOfPartitions , 1000}, + }; + } + + // TODO: DANOBLE: Investigate DIRECT TCP performance issue + // Links: https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028 + + @Test(groups = { "long" }, dataProvider = "queryProvider", timeOut = 2 * TIMEOUT) + public void query(String query, int maxItemCount, int maxExpectedBufferedCountForBackPressure, int expectedNumberOfResults) throws Exception { + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(maxItemCount); + options.maxDegreeOfParallelism(2); + Flux> queryObservable = createdCollection.queryItems(query, options); + + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); + + log.info("instantiating subscriber ..."); + TestSubscriber> subscriber = new TestSubscriber<>(1); + queryObservable.publishOn(Schedulers.elastic(), 1).subscribe(subscriber); + int sleepTimeInMillis = 40000; + int i = 0; + + // use a test subscriber and request for more result and sleep in between + while (subscriber.completions() == 0 && subscriber.errorCount() == 0) { + log.debug("loop " + i); + + TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); + sleepTimeInMillis /= 2; + + if (sleepTimeInMillis > 4000) { + // validate that only one item is returned to subscriber in each iteration + assertThat(subscriber.valueCount() - i).isEqualTo(1); + } + + log.debug("subscriber.getValueCount(): " + subscriber.valueCount()); + log.debug("client.httpRequests.size(): " + rxClient.httpRequests.size()); + // validate that the difference between the number of requests to backend + // and the number of returned results is always less than a fixed threshold + assertThat(rxClient.httpRequests.size() - subscriber.valueCount()) + .isLessThanOrEqualTo(maxExpectedBufferedCountForBackPressure); + + log.debug("requesting more"); + subscriber.requestMore(1); + i++; + } + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + assertThat(subscriber.values().stream().mapToInt(p -> p.results().size()).sum()).isEqualTo(expectedNumberOfResults); + } + + @BeforeClass(groups = { "long" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + client = new ClientUnderTestBuilder(clientBuilder()).build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = createCollection(createdDatabase, getCollectionDefinition(), options, 20000); + + ArrayList docDefList = new ArrayList<>(); + for(int i = 0; i < numberOfDocs; i++) { + docDefList.add(getDocumentDefinition(i)); + } + + createdDocuments = bulkInsertBlocking( + createdCollection, + docDefList); + + numberOfPartitions = CosmosBridgeInternal.getAsyncDocumentClient(client).readPartitionKeyRanges(getCollectionLink(), null) + .flatMap(p -> Flux.fromIterable(p.results())).collectList().single().block().size(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + warmUp(); + } + + // TODO: DANOBLE: Investigate DIRECT TCP performance issue + // Links: https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028 + + @AfterClass(groups = { "long" }, timeOut = 2 * SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteCollection(createdCollection); + safeClose(client); + } + + private static CosmosItemProperties getDocumentDefinition(int cnt) { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"prop\" : %d, " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, cnt, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureTest.java new file mode 100644 index 0000000000000..fca0b1e68e5d2 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/BackPressureTest.java @@ -0,0 +1,224 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.ClientUnderTestBuilder; +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.Offer; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.RxDocumentClientUnderTest; +import com.azure.data.cosmos.internal.TestUtils; +import io.reactivex.subscribers.TestSubscriber; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; +import reactor.util.concurrent.Queues; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class BackPressureTest extends TestSuiteBase { + + private static final int TIMEOUT = 200000; + private static final int SETUP_TIMEOUT = 60000; + + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + private static CosmosContainerProperties getSinglePartitionCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + return collectionDefinition; + } + + @Factory(dataProvider = "simpleClientBuildersWithDirectHttps") + public BackPressureTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "long" }, timeOut = 3 * TIMEOUT) + public void readFeed() throws Exception { + FeedOptions options = new FeedOptions(); + options.maxItemCount(1); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.readAllItems(options); + + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); + + TestSubscriber> subscriber = new TestSubscriber>(1); + queryObservable.publishOn(Schedulers.elastic(), 1).subscribe(subscriber); + int sleepTimeInMillis = 10000; // 10 seconds + + int i = 0; + // use a test subscriber and request for more result and sleep in between + while (subscriber.completions() == 0 && subscriber.getEvents().get(1).isEmpty()) { + TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); + sleepTimeInMillis /= 2; + + if (sleepTimeInMillis > 1000) { + // validate that only one item is returned to subscriber in each iteration + assertThat(subscriber.valueCount() - i).isEqualTo(1); + } + // validate that only one item is returned to subscriber in each iteration + // validate that the difference between the number of requests to backend + // and the number of returned results is always less than a fixed threshold + assertThat(rxClient.httpRequests.size() - subscriber.valueCount()) + .isLessThanOrEqualTo(Queues.SMALL_BUFFER_SIZE); + + subscriber.requestMore(1); + i++; + } + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + assertThat(subscriber.valueCount()).isEqualTo(createdDocuments.size()); + } + + @Test(groups = { "long" }, timeOut = 3 * TIMEOUT) + public void query() throws Exception { + FeedOptions options = new FeedOptions(); + options.maxItemCount(1); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems("SELECT * from r", options); + + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); + + TestSubscriber> subscriber = new TestSubscriber>(1); + queryObservable.publishOn(Schedulers.elastic(), 1).subscribe(subscriber); + int sleepTimeInMillis = 10000; + + int i = 0; + // use a test subscriber and request for more result and sleep in between + while(subscriber.completions() == 0 && subscriber.getEvents().get(1).isEmpty()) { + TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); + sleepTimeInMillis /= 2; + + if (sleepTimeInMillis > 1000) { + // validate that only one item is returned to subscriber in each iteration + assertThat(subscriber.valueCount() - i).isEqualTo(1); + } + // validate that the difference between the number of requests to backend + // and the number of returned results is always less than a fixed threshold + assertThat(rxClient.httpRequests.size() - subscriber.valueCount()) + .isLessThanOrEqualTo(Queues.SMALL_BUFFER_SIZE); + + subscriber.requestMore(1); + i++; + } + + subscriber.assertNoErrors(); + subscriber.assertComplete(); + + assertThat(subscriber.valueCount()).isEqualTo(createdDocuments.size()); + } + + @BeforeClass(groups = { "long" }, timeOut = 2 * SETUP_TIMEOUT) + public void beforeClass() throws Exception { + + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + client = new ClientUnderTestBuilder(clientBuilder()).build(); + createdDatabase = getSharedCosmosDatabase(client); + + createdCollection = createCollection(createdDatabase, getSinglePartitionCollectionDefinition(), options, 1000); + + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + + // increase throughput to max for a single partition collection to avoid throttling + // for bulk insert and later queries. + Offer offer = rxClient.queryOffers( + String.format("SELECT * FROM r WHERE r.offerResourceId = '%s'", + createdCollection.read().block().properties().resourceId()) + , null).take(1).map(FeedResponse::results).single().block().get(0); + offer.setThroughput(6000); + offer = rxClient.replaceOffer(offer).single().block().getResource(); + assertThat(offer.getThroughput()).isEqualTo(6000); + + ArrayList docDefList = new ArrayList<>(); + for(int i = 0; i < 1000; i++) { + docDefList.add(getDocumentDefinition(i)); + } + + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + warmUp(); + } + + private void warmUp() { + // ensure collection is cached + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + createdCollection.queryItems("SELECT * from r", options).blockFirst(); + } + + // TODO: DANOBLE: Investigate DIRECT TCP performance issue + // NOTE: This method requires multiple SHUTDOWN_TIMEOUT intervals + // SEE: https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028https://msdata.visualstudio.com/CosmosDB/_workitems/edit/367028 + + @AfterClass(groups = { "long" }, timeOut = 2 * SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteCollection(createdCollection); + safeClose(client); + } + + private static CosmosItemProperties getDocumentDefinition(int cnt) { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"prop\" : %d, " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, cnt, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedProcessorTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedProcessorTest.java new file mode 100644 index 0000000000000..136a4789f6ee5 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedProcessorTest.java @@ -0,0 +1,297 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.ChangeFeedProcessor; +import com.azure.data.cosmos.ChangeFeedProcessorOptions; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.SerializationFormattingPolicy; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.scheduler.Schedulers; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ChangeFeedProcessorTest extends TestSuiteBase { + private final static Logger log = LoggerFactory.getLogger(ChangeFeedProcessorTest.class); + + private CosmosDatabase createdDatabase; + private CosmosContainer createdFeedCollection; + private CosmosContainer createdLeaseCollection; + private List createdDocuments; + private static Map receivedDocuments; +// private final String databaseId = "testdb1"; +// private final String hostName = "TestHost1"; + private final String hostName = RandomStringUtils.randomAlphabetic(6); + private final int FEED_COUNT = 10; + private final int CHANGE_FEED_PROCESSOR_TIMEOUT = 5000; + + private CosmosClient client; + + private ChangeFeedProcessor changeFeedProcessor; + + @Factory(dataProvider = "clientBuilders") + public ChangeFeedProcessorTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readFeedDocumentsStartFromBeginning() { + setupReadFeedDocuments(); + + changeFeedProcessor = ChangeFeedProcessor.Builder() + .hostName(hostName) + .handleChanges(docs -> { + ChangeFeedProcessorTest.log.info("START processing from thread {}", Thread.currentThread().getId()); + for (CosmosItemProperties item : docs) { + processItem(item); + } + ChangeFeedProcessorTest.log.info("END processing from thread {}", Thread.currentThread().getId()); + }) + .feedContainer(createdFeedCollection) + .leaseContainer(createdLeaseCollection) + .options(new ChangeFeedProcessorOptions() + .leaseRenewInterval(Duration.ofSeconds(20)) + .leaseAcquireInterval(Duration.ofSeconds(10)) + .leaseExpirationInterval(Duration.ofSeconds(30)) + .feedPollDelay(Duration.ofSeconds(2)) + .leasePrefix("TEST") + .maxItemCount(10) + .startFromBeginning(true) + .maxScaleCount(0) // unlimited + .discardExistingLeases(true) + ) + .build(); + + try { + changeFeedProcessor.start().subscribeOn(Schedulers.elastic()) + .timeout(Duration.ofMillis(CHANGE_FEED_PROCESSOR_TIMEOUT)) + .subscribe(); + } catch (Exception ex) { + log.error("Change feed processor did not start in the expected time", ex); + } + + // Wait for the feed processor to receive and process the documents. + try { + Thread.sleep(2 * CHANGE_FEED_PROCESSOR_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + changeFeedProcessor.stop().subscribeOn(Schedulers.elastic()).timeout(Duration.ofMillis(CHANGE_FEED_PROCESSOR_TIMEOUT)).subscribe(); + + for (CosmosItemProperties item : createdDocuments) { + assertThat(receivedDocuments.containsKey(item.id())).as("Document with id: " + item.id()).isTrue(); + } + + // Wait for the feed processor to shutdown. + try { + Thread.sleep(CHANGE_FEED_PROCESSOR_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + receivedDocuments.clear(); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readFeedDocumentsStartFromCustomDate() { + ChangeFeedProcessor changeFeedProcessor = ChangeFeedProcessor.Builder() + .hostName(hostName) + .handleChanges(docs -> { + ChangeFeedProcessorTest.log.info("START processing from thread {}", Thread.currentThread().getId()); + for (CosmosItemProperties item : docs) { + processItem(item); + } + ChangeFeedProcessorTest.log.info("END processing from thread {}", Thread.currentThread().getId()); + }) + .feedContainer(createdFeedCollection) + .leaseContainer(createdLeaseCollection) + .options(new ChangeFeedProcessorOptions() + .leaseRenewInterval(Duration.ofSeconds(20)) + .leaseAcquireInterval(Duration.ofSeconds(10)) + .leaseExpirationInterval(Duration.ofSeconds(30)) + .feedPollDelay(Duration.ofSeconds(1)) + .leasePrefix("TEST") + .maxItemCount(10) + .startTime(OffsetDateTime.now().minusDays(1)) + .minScaleCount(1) + .maxScaleCount(3) + .discardExistingLeases(true) + ) + .build(); + + try { + changeFeedProcessor.start().subscribeOn(Schedulers.elastic()) + .timeout(Duration.ofMillis(CHANGE_FEED_PROCESSOR_TIMEOUT)) + .subscribe(); + } catch (Exception ex) { + log.error("Change feed processor did not start in the expected time", ex); + } + + setupReadFeedDocuments(); + + // Wait for the feed processor to receive and process the documents. + long remainingWork = FEED_TIMEOUT; + while (remainingWork > 0 && receivedDocuments.size() < FEED_COUNT) { + remainingWork -= CHANGE_FEED_PROCESSOR_TIMEOUT; + try { + Thread.sleep(CHANGE_FEED_PROCESSOR_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + assertThat(remainingWork >= 0).as("Failed to receive all the feed documents").isTrue(); + + changeFeedProcessor.stop().subscribeOn(Schedulers.elastic()).timeout(Duration.ofMillis(2 * CHANGE_FEED_PROCESSOR_TIMEOUT)).subscribe(); + + for (CosmosItemProperties item : createdDocuments) { + assertThat(receivedDocuments.containsKey(item.id())).as("Document with id: " + item.id()).isTrue(); + } + + // Wait for the feed processor to shutdown. + try { + Thread.sleep(CHANGE_FEED_PROCESSOR_TIMEOUT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + receivedDocuments.clear(); + } + + @BeforeMethod(groups = { "emulator" }, timeOut = 2 * SETUP_TIMEOUT, alwaysRun = true) + public void beforeMethod() { + createdFeedCollection = createFeedCollection(); + createdLeaseCollection = createLeaseCollection(); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT, alwaysRun = true) + public void beforeClass() { + client = clientBuilder().build(); + +// try { +// client.getDatabase(databaseId).read() +// .map(cosmosDatabaseResponse -> cosmosDatabaseResponse.database()) +// .flatMap(database -> database.delete()) +// .onErrorResume(throwable -> { +// if (throwable instanceof com.azure.data.cosmos.CosmosClientException) { +// com.azure.data.cosmos.CosmosClientException clientException = (com.azure.data.cosmos.CosmosClientException) throwable; +// if (clientException.statusCode() == 404) { +// return Mono.empty(); +// } +// } +// return Mono.error(throwable); +// }).block(); +// Thread.sleep(500); +// } catch (Exception e){ +// log.warn("Database delete", e); +// } +// createdDatabase = createDatabase(client, databaseId); + createdDatabase = getSharedCosmosDatabase(client); + } + + @AfterMethod(groups = { "emulator" }, timeOut = 3 * SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterMethod() { + safeDeleteCollection(createdFeedCollection); + safeDeleteCollection(createdLeaseCollection); + + // Allow some time for the collections and the database to be deleted before exiting. + try { + Thread.sleep(500); + } catch (Exception e){ } + } + + @AfterClass(groups = { "emulator" }, timeOut = 2 * SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { +// try { +// client.readAllDatabases() +// .flatMap(cosmosDatabaseSettingsFeedResponse -> reactor.core.publisher.Flux.fromIterable(cosmosDatabaseSettingsFeedResponse.results())) +// .flatMap(cosmosDatabaseSettings -> { +// CosmosDatabase cosmosDatabase = client.getDatabase(cosmosDatabaseSettings.id()); +// return cosmosDatabase.delete(); +// }).blockLast(); +// Thread.sleep(500); +// } catch (Exception e){ } + + safeClose(client); + } + + private void setupReadFeedDocuments() { + receivedDocuments = new ConcurrentHashMap<>(); + List docDefList = new ArrayList<>(); + + for(int i = 0; i < FEED_COUNT; i++) { + docDefList.add(getDocumentDefinition()); + } + + createdDocuments = bulkInsertBlocking(createdFeedCollection, docDefList); + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + private CosmosContainer createFeedCollection() { + CosmosContainerRequestOptions optionsFeedCollection = new CosmosContainerRequestOptions(); + return createCollection(createdDatabase, getCollectionDefinition(), optionsFeedCollection, 10100); + } + + private CosmosContainer createLeaseCollection() { + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), "/id"); + return createCollection(createdDatabase, collectionDefinition, options, 400); + } + + private static synchronized void processItem(CosmosItemProperties item) { + ChangeFeedProcessorTest.log.info("RECEIVED {}", item.toJson(SerializationFormattingPolicy.INDENTED)); + receivedDocuments.put(item.id(), item); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedTest.java new file mode 100644 index 0000000000000..60c81ce3ac11e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ChangeFeedTest.java @@ -0,0 +1,313 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.TestSuiteBase; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.lang.reflect.Method; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import static com.azure.data.cosmos.CommonsBridgeInternal.partitionKeyRangeIdInternal; +import static org.assertj.core.api.Assertions.assertThat; + +//TODO: change to use external TestSuiteBase +public class ChangeFeedTest extends TestSuiteBase { + + private static final int SETUP_TIMEOUT = 40000; + private static final int TIMEOUT = 30000; + private static final String PartitionKeyFieldName = "mypk"; + private Database createdDatabase; + private DocumentCollection createdCollection; + private Multimap partitionKeyToDocuments = ArrayListMultimap.create(); + + private AsyncDocumentClient client; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + static protected DocumentCollection getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/" + PartitionKeyFieldName); + partitionKeyDef.paths(paths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + public ChangeFeedTest() { + super(createGatewayRxDocumentClient()); + subscriberValidationTimeout = TIMEOUT; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void changeFeed_fromBeginning() throws Exception { + String partitionKey = partitionKeyToDocuments.keySet().iterator().next(); + Collection expectedDocuments = partitionKeyToDocuments.get(partitionKey); + + ChangeFeedOptions changeFeedOption = new ChangeFeedOptions(); + changeFeedOption.maxItemCount(3); + changeFeedOption.partitionKey(new PartitionKey(partitionKey)); + changeFeedOption.startFromBeginning(true); + + List> changeFeedResultList = client.queryDocumentChangeFeed(getCollectionLink(), changeFeedOption) + .collectList().block(); + + int count = 0; + for (int i = 0; i < changeFeedResultList.size(); i++) { + FeedResponse changeFeedPage = changeFeedResultList.get(i); + assertThat(changeFeedPage.continuationToken()).as("Response continuation should not be null").isNotNull(); + + count += changeFeedPage.results().size(); + assertThat(changeFeedPage.results().size()) + .as("change feed should contain all the previously created documents") + .isLessThanOrEqualTo(changeFeedOption.maxItemCount()); + } + assertThat(count).as("the number of changes").isEqualTo(expectedDocuments.size()); + } + + @Test(groups = { "simple" }, timeOut = 5 * TIMEOUT) + public void changesFromPartitionKeyRangeId_FromBeginning() throws Exception { + List partitionKeyRangeIds = client.readPartitionKeyRanges(getCollectionLink(), null) + .flatMap(p -> Flux.fromIterable(p.results()), 1) + .map(Resource::id) + .collectList() + .block(); + + assertThat(partitionKeyRangeIds.size()).isGreaterThan(1); + + String pkRangeId = partitionKeyRangeIds.get(0); + + ChangeFeedOptions changeFeedOption = new ChangeFeedOptions(); + changeFeedOption.maxItemCount(3); + partitionKeyRangeIdInternal(changeFeedOption, pkRangeId); + changeFeedOption.startFromBeginning(true); + List> changeFeedResultList = client.queryDocumentChangeFeed(getCollectionLink(), changeFeedOption) + .collectList().block(); + + int count = 0; + for(int i = 0; i < changeFeedResultList.size(); i++) { + FeedResponse changeFeedPage = changeFeedResultList.get(i); + assertThat(changeFeedPage.continuationToken()).as("Response continuation should not be null").isNotNull(); + + count += changeFeedPage.results().size(); + assertThat(changeFeedPage.results().size()) + .as("change feed should contain all the previously created documents") + .isLessThanOrEqualTo(changeFeedOption.maxItemCount()); + + assertThat(changeFeedPage.continuationToken()).as("Response continuation should not be null").isNotNull(); + assertThat(changeFeedPage.continuationToken()).as("Response continuation should not be empty").isNotEmpty(); + } + assertThat(changeFeedResultList.size()).as("has at least one page").isGreaterThanOrEqualTo(1); + assertThat(count).as("the number of changes").isGreaterThan(0); + assertThat(count).as("the number of changes").isLessThan(partitionKeyToDocuments.size()); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void changeFeed_fromNow() throws Exception { + // READ change feed from current. + ChangeFeedOptions changeFeedOption = new ChangeFeedOptions(); + String partitionKey = partitionKeyToDocuments.keySet().iterator().next(); + changeFeedOption.partitionKey(new PartitionKey(partitionKey)); + + List> changeFeedResultsList = client.queryDocumentChangeFeed(getCollectionLink(), changeFeedOption) + .collectList() + .block(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder().totalSize(0).build(); + validator.validate(changeFeedResultsList); + assertThat(changeFeedResultsList.get(changeFeedResultsList.size() -1 ). + continuationToken()).as("Response continuation should not be null").isNotNull(); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void changeFeed_fromStartDate() throws Exception { + + //setStartDateTime is not currently supported in multimaster mode. So skipping the test + if(BridgeInternal.isEnableMultipleWriteLocations(client.getDatabaseAccount().single().block())){ + throw new SkipException("StartTime/IfModifiedSince is not currently supported when EnableMultipleWriteLocations is set"); + } + + // READ change feed from current. + ChangeFeedOptions changeFeedOption = new ChangeFeedOptions(); + String partitionKey = partitionKeyToDocuments.keySet().iterator().next(); + + changeFeedOption.partitionKey(new PartitionKey(partitionKey)); + OffsetDateTime befTime = OffsetDateTime.now(); + // Waiting for at-least a second to ensure that new document is created after we took the time stamp + waitAtleastASecond(befTime); + + OffsetDateTime dateTimeBeforeCreatingDoc = OffsetDateTime.now(); + changeFeedOption.startDateTime(dateTimeBeforeCreatingDoc); + + // Waiting for at-least a second to ensure that new document is created after we took the time stamp + waitAtleastASecond(dateTimeBeforeCreatingDoc); + client.createDocument(getCollectionLink(), getDocumentDefinition(partitionKey), null, true).single().block(); + + List> changeFeedResultList = client.queryDocumentChangeFeed(getCollectionLink(), + changeFeedOption).collectList().block(); + + int count = 0; + for(int i = 0; i < changeFeedResultList.size(); i++) { + FeedResponse changeFeedPage = changeFeedResultList.get(i); + count += changeFeedPage.results().size(); + assertThat(changeFeedPage.continuationToken()).as("Response continuation should not be null").isNotNull(); + } + assertThat(count).as("Change feed should have one newly created document").isEqualTo(1); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void changesFromPartitionKey_AfterInsertingNewDocuments() throws Exception { + ChangeFeedOptions changeFeedOption = new ChangeFeedOptions(); + changeFeedOption.maxItemCount(3); + String partitionKey = partitionKeyToDocuments.keySet().iterator().next(); + changeFeedOption.partitionKey(new PartitionKey(partitionKey)); + + List> changeFeedResultsList = client.queryDocumentChangeFeed(getCollectionLink(), changeFeedOption) + .collectList().block(); + + assertThat(changeFeedResultsList).as("only one page").hasSize(1); + assertThat(changeFeedResultsList.get(0).results()).as("no recent changes").isEmpty(); + + String changeFeedContinuation = changeFeedResultsList.get(changeFeedResultsList.size()-1).continuationToken(); + assertThat(changeFeedContinuation).as("continuation token is not null").isNotNull(); + assertThat(changeFeedContinuation).as("continuation token is not empty").isNotEmpty(); + + // create some documents + client.createDocument(getCollectionLink(), getDocumentDefinition(partitionKey), null, true).single().block(); + client.createDocument(getCollectionLink(), getDocumentDefinition(partitionKey), null, true).single().block(); + + // READ change feed from continuation + changeFeedOption.requestContinuation(changeFeedContinuation); + + + FeedResponse changeFeedResults2 = client.queryDocumentChangeFeed(getCollectionLink(), changeFeedOption) + .blockFirst(); + + assertThat(changeFeedResults2.results()).as("change feed should contain newly inserted docs.").hasSize(2); + assertThat(changeFeedResults2.continuationToken()).as("Response continuation should not be null").isNotNull(); + } + + public void createDocument(AsyncDocumentClient client, String partitionKey) { + Document docDefinition = getDocumentDefinition(partitionKey); + + Document createdDocument = client + .createDocument(getCollectionLink(), docDefinition, null, false).single().block().getResource(); + partitionKeyToDocuments.put(partitionKey, createdDocument); + } + + public List bulkInsert(AsyncDocumentClient client, List docs) { + ArrayList>> result = new ArrayList>>(); + for (int i = 0; i < docs.size(); i++) { + result.add(client.createDocument("dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(), docs.get(i), null, false)); + } + + return Flux.merge(Flux.fromIterable(result), 100).map(ResourceResponse::getResource).collectList().block(); + } + + @AfterMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void removeCollection() { + if (createdCollection != null) { + deleteCollection(client, getCollectionLink()); + } + } + + @BeforeMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void populateDocuments(Method method) { + + partitionKeyToDocuments.clear(); + + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10100); + createdCollection = createCollection(client, createdDatabase.id(), getCollectionDefinition(), options); + + List docs = new ArrayList<>(); + + for (int i = 0; i < 200; i++) { + String partitionKey = UUID.randomUUID().toString(); + for(int j = 0; j < 7; j++) { + docs.add(getDocumentDefinition(partitionKey)); + } + } + + List insertedDocs = bulkInsert(client, docs); + for(Document doc: insertedDocs) { + partitionKeyToDocuments.put(doc.getString(PartitionKeyFieldName), doc); + } + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + // set up the client + client = clientBuilder().build(); + createdDatabase = SHARED_DATABASE; + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static Document getDocumentDefinition(String partitionKey) { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(); + doc.id(uuid); + BridgeInternal.setProperty(doc, "mypk", partitionKey); + BridgeInternal.setProperty(doc, "prop", uuid); + return doc; + } + + private static void waitAtleastASecond(OffsetDateTime befTime) throws InterruptedException { + while (befTime.plusSeconds(1).isAfter(OffsetDateTime.now())) { + Thread.sleep(100); + } + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionCrudTest.java new file mode 100644 index 0000000000000..63de9f5e16f36 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionCrudTest.java @@ -0,0 +1,334 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.CompositePathSortOrder; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerResponse; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.IndexingMode; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.RetryAnalyzer; +import com.azure.data.cosmos.SpatialSpec; +import com.azure.data.cosmos.SpatialType; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CollectionCrudTest extends TestSuiteBase { + + private static final int TIMEOUT = 50000; + private static final int SETUP_TIMEOUT = 20000; + private static final int SHUTDOWN_TIMEOUT = 20000; + private final String databaseId = CosmosDatabaseForTest.generateId(); + + private CosmosClient client; + private CosmosDatabase database; + + @Factory(dataProvider = "clientBuildersWithDirect") + public CollectionCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + this.subscriberValidationTimeout = TIMEOUT; + } + + @DataProvider(name = "collectionCrudArgProvider") + public Object[][] collectionCrudArgProvider() { + return new Object[][] { + // collection name, is name base + {UUID.randomUUID().toString()} , + + // with special characters in the name. + {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~"} , + }; + } + + private CosmosContainerProperties getCollectionDefinition(String collectionName) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties( + collectionName, + partitionKeyDef); + + return collectionDefinition; + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void createCollection(String collectionName) throws InterruptedException { + CosmosContainerProperties collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database + .createContainer(collectionDefinition); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collectionDefinition.id()).build(); + + validateSuccess(createObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createCollectionWithCompositeIndexAndSpatialSpec() throws InterruptedException { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collection = new CosmosContainerProperties( + UUID.randomUUID().toString(), + partitionKeyDef); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + CompositePath compositePath1 = new CompositePath(); + compositePath1.path("/path1"); + compositePath1.order(CompositePathSortOrder.ASCENDING); + CompositePath compositePath2 = new CompositePath(); + compositePath2.path("/path2"); + compositePath2.order(CompositePathSortOrder.DESCENDING); + CompositePath compositePath3 = new CompositePath(); + compositePath3.path("/path3"); + CompositePath compositePath4 = new CompositePath(); + compositePath4.path("/path4"); + compositePath4.order(CompositePathSortOrder.ASCENDING); + CompositePath compositePath5 = new CompositePath(); + compositePath5.path("/path5"); + compositePath5.order(CompositePathSortOrder.DESCENDING); + CompositePath compositePath6 = new CompositePath(); + compositePath6.path("/path6"); + + ArrayList compositeIndex1 = new ArrayList(); + compositeIndex1.add(compositePath1); + compositeIndex1.add(compositePath2); + compositeIndex1.add(compositePath3); + + ArrayList compositeIndex2 = new ArrayList(); + compositeIndex2.add(compositePath4); + compositeIndex2.add(compositePath5); + compositeIndex2.add(compositePath6); + + List> compositeIndexes = new ArrayList<>(); + compositeIndexes.add(compositeIndex1); + compositeIndexes.add(compositeIndex2); + indexingPolicy.compositeIndexes(compositeIndexes); + + SpatialType[] spatialTypes = new SpatialType[] { + SpatialType.POINT, + SpatialType.LINE_STRING, + SpatialType.POLYGON, + SpatialType.MULTI_POLYGON + }; + List spatialIndexes = new ArrayList(); + for (int index = 0; index < 2; index++) { + List collectionOfSpatialTypes = new ArrayList(); + + SpatialSpec spec = new SpatialSpec(); + spec.path("/path" + index + "/*"); + + for (int i = index; i < index + 3; i++) { + collectionOfSpatialTypes.add(spatialTypes[i]); + } + spec.spatialTypes(collectionOfSpatialTypes); + spatialIndexes.add(spec); + } + + indexingPolicy.spatialIndexes(spatialIndexes); + + collection.indexingPolicy(indexingPolicy); + + Mono createObservable = database + .createContainer(collection, new CosmosContainerRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collection.id()) + .withCompositeIndexes(compositeIndexes) + .withSpatialIndexes(spatialIndexes) + .build(); + + validateSuccess(createObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void readCollection(String collectionName) throws InterruptedException { + CosmosContainerProperties collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().container(); + + Mono readObservable = collection.read(); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collection.id()).build(); + validateSuccess(readObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void readCollection_DoesntExist(String collectionName) throws Exception { + + Mono readObservable = database + .getContainer("I don't exist").read(); + + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void deleteCollection(String collectionName) throws InterruptedException { + CosmosContainerProperties collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().container(); + + Mono deleteObservable = collection.delete(); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void replaceCollection(String collectionName) throws InterruptedException { + // create a collection + CosmosContainerProperties collectionDefinition = getCollectionDefinition(collectionName); + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().container(); + CosmosContainerProperties collectionSettings = collection.read().block().properties(); + // sanity check + assertThat(collectionSettings.indexingPolicy().indexingMode()).isEqualTo(IndexingMode.CONSISTENT); + + // replace indexing mode + IndexingPolicy indexingMode = new IndexingPolicy(); + indexingMode.indexingMode(IndexingMode.LAZY); + collectionSettings.indexingPolicy(indexingMode); + Mono readObservable = collection.replace(collectionSettings, new CosmosContainerRequestOptions()); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .indexingMode(IndexingMode.LAZY).build(); + validateSuccess(readObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = 10 * TIMEOUT, retryAnalyzer = RetryAnalyzer.class) + public void sessionTokenConsistencyCollectionDeleteCreateSameName() { + CosmosClient client1 = clientBuilder().build(); + CosmosClient client2 = clientBuilder().build(); + + String dbId = CosmosDatabaseForTest.generateId(); + String collectionId = "coll"; + CosmosDatabase db = null; + try { + Database databaseDefinition = new Database(); + databaseDefinition.id(dbId); + db = createDatabase(client1, dbId); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(collectionId, partitionKeyDef); + CosmosContainer collection = createCollection(db, collectionDefinition, new CosmosContainerRequestOptions()); + + CosmosItemProperties document = new CosmosItemProperties(); + document.id("doc"); + BridgeInternal.setProperty(document, "name", "New Document"); + BridgeInternal.setProperty(document, "mypk", "mypkValue"); + CosmosItem item = createDocument(collection, document); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey("mypkValue")); + CosmosItemResponse readDocumentResponse = item.read(options).block(); + logger.info("Client 1 READ Document Client Side Request Statistics {}", readDocumentResponse.cosmosResponseDiagnosticsString()); + logger.info("Client 1 READ Document Latency {}", readDocumentResponse.requestLatency()); + + BridgeInternal.setProperty(document, "name", "New Updated Document"); + CosmosItemResponse upsertDocumentResponse = collection.upsertItem(document).block(); + logger.info("Client 1 Upsert Document Client Side Request Statistics {}", upsertDocumentResponse.cosmosResponseDiagnosticsString()); + logger.info("Client 1 Upsert Document Latency {}", upsertDocumentResponse.requestLatency()); + + // DELETE the existing collection + deleteCollection(client2, dbId, collectionId); + // Recreate the collection with the same name but with different client + CosmosContainer collection2 = createCollection(client2, dbId, collectionDefinition); + + CosmosItemProperties newDocument = new CosmosItemProperties(); + newDocument.id("doc"); + BridgeInternal.setProperty(newDocument, "name", "New Created Document"); + BridgeInternal.setProperty(newDocument, "mypk", "mypk"); + createDocument(collection2, newDocument); + + readDocumentResponse = client1.getDatabase(dbId).getContainer(collectionId).getItem(newDocument.id(), newDocument.get("mypk")).read().block(); + logger.info("Client 2 READ Document Client Side Request Statistics {}", readDocumentResponse.cosmosResponseDiagnosticsString()); + logger.info("Client 2 READ Document Latency {}", readDocumentResponse.requestLatency()); + + CosmosItemProperties readDocument = readDocumentResponse.properties(); + + assertThat(readDocument.id().equals(newDocument.id())).isTrue(); + assertThat(readDocument.get("name").equals(newDocument.get("name"))).isTrue(); + } finally { + safeDeleteDatabase(db); + safeClose(client1); + safeClose(client2); + } + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + database = createDatabase(client, databaseId); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(database); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionQueryTest.java new file mode 100644 index 0000000000000..3e4a71a71c85e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CollectionQueryTest.java @@ -0,0 +1,153 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CollectionQueryTest extends TestSuiteBase { + private final static int TIMEOUT = 30000; + private final String databaseId = CosmosDatabaseForTest.generateId(); + private List createdCollections = new ArrayList<>(); + private CosmosClient client; + private CosmosDatabase createdDatabase; + + @Factory(dataProvider = "clientBuilders") + public CollectionQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + this.subscriberValidationTimeout = TIMEOUT; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryCollectionsWithFilter() throws Exception { + + String filterCollectionId = createdCollections.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterCollectionId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + Flux> queryObservable = createdDatabase.queryContainers(query, options); + + List expectedCollections = createdCollections.stream() + .filter(c -> StringUtils.equals(filterCollectionId, c.id()) ).collect(Collectors.toList()); + + assertThat(expectedCollections).isNotEmpty(); + + int expectedPageSize = (expectedCollections.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedCollections.size()) + .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.read().block().properties().resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAllCollections() throws Exception { + + String query = "SELECT * from c"; + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + Flux> queryObservable = createdDatabase.queryContainers(query, options); + + List expectedCollections = createdCollections; + + assertThat(expectedCollections).isNotEmpty(); + + int expectedPageSize = (expectedCollections.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedCollections.size()) + .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.read().block().properties().resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryCollections_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdDatabase.queryContainers(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collection = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + createdCollections.add(createCollection(client, databaseId, collection)); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CosmosConflictTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CosmosConflictTest.java new file mode 100644 index 0000000000000..62d6d330a21b4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/CosmosConflictTest.java @@ -0,0 +1,98 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosConflictProperties; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.HttpConstants; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.Iterator; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CosmosConflictTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public CosmosConflictTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void readConflicts_toBlocking_toIterator() { + + int requestPageSize = 3; + FeedOptions options = new FeedOptions(); + options.maxItemCount(requestPageSize); + + Flux> conflictReadFeedFlux = createdCollection.readAllConflicts(options); + + Iterator> it = conflictReadFeedFlux.toIterable().iterator(); + + int expectedNumberOfConflicts = 0; + + int numberOfResults = 0; + while (it.hasNext()) { + FeedResponse page = it.next(); + String pageSizeAsString = page.responseHeaders().get(HttpConstants.HttpHeaders.ITEM_COUNT); + assertThat(pageSizeAsString).isNotNull(); + // assertThat("header item count must be present", pageSizeAsString, notNullValue()); + int pageSize = Integer.valueOf(pageSizeAsString); + // Assert that Result size must match header item count + assertThat(page.results().size()).isEqualTo(pageSize); + numberOfResults += pageSize; + } + assertThat(numberOfResults).isEqualTo(expectedNumberOfConflicts); + } + + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeMethod() { + safeClose(client); + client = clientBuilder().build(); + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseCrudTest.java new file mode 100644 index 0000000000000..a651197fbf2b3 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseCrudTest.java @@ -0,0 +1,145 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosDatabaseProperties; +import com.azure.data.cosmos.CosmosDatabaseRequestOptions; +import com.azure.data.cosmos.CosmosDatabaseResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.internal.FailureValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.List; + +public class DatabaseCrudTest extends TestSuiteBase { + private final String preExistingDatabaseId = CosmosDatabaseForTest.generateId(); + private final List databases = new ArrayList<>(); + private CosmosClient client; + private CosmosDatabase createdDatabase; + + @Factory(dataProvider = "clientBuilders") + public DatabaseCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createDatabase() throws Exception { + CosmosDatabaseProperties databaseDefinition = new CosmosDatabaseProperties(CosmosDatabaseForTest.generateId()); + databases.add(databaseDefinition.id()); + + // create the database + Mono createObservable = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(databaseDefinition.id()).build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createDatabase_AlreadyExists() throws Exception { + CosmosDatabaseProperties databaseDefinition = new CosmosDatabaseProperties(CosmosDatabaseForTest.generateId()); + databases.add(databaseDefinition.id()); + + client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()).block(); + + // attempt to create the database + Mono createObservable = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()); + + // validate + FailureValidator validator = new FailureValidator.Builder().resourceAlreadyExists().build(); + validateFailure(createObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readDatabase() throws Exception { + // read database + Mono readObservable = client.getDatabase(preExistingDatabaseId).read(); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(preExistingDatabaseId).build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readDatabase_DoesntExist() throws Exception { + // read database + Mono readObservable = client.getDatabase("I don't exist").read(); + + // validate + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, validator); + } + + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void deleteDatabase() throws Exception { + // create the database + CosmosDatabaseProperties databaseDefinition = new CosmosDatabaseProperties(CosmosDatabaseForTest.generateId()); + databases.add(databaseDefinition.id()); + CosmosDatabase database = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()).block().database(); + + // delete the database + Mono deleteObservable = database.delete(); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void deleteDatabase_DoesntExist() throws Exception { + // delete the database + Mono deleteObservable = client.getDatabase("I don't exist").delete(); + + // validate + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(deleteObservable, validator); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, preExistingDatabaseId); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + for(String dbId: databases) { + safeDeleteDatabase(client.getDatabase(dbId)); + } + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseQueryTest.java new file mode 100644 index 0000000000000..7e5d94953edf4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DatabaseQueryTest.java @@ -0,0 +1,146 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosDatabaseProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DatabaseQueryTest extends TestSuiteBase { + + public final String databaseId1 = CosmosDatabaseForTest.generateId(); + public final String databaseId2 = CosmosDatabaseForTest.generateId(); + + private List createdDatabases = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public DatabaseQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDatabaseWithFilter() throws Exception { + String query = String.format("SELECT * from c where c.id = '%s'", databaseId1); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + Flux> queryObservable = client.queryDatabases(query, options); + + List expectedDatabases = createdDatabases.stream() + .filter(d -> StringUtils.equals(databaseId1, d.id()) ).map(d -> d.read().block().properties()).collect(Collectors.toList()); + + assertThat(expectedDatabases).isNotEmpty(); + + int expectedPageSize = (expectedDatabases.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDatabases.size()) + .exactlyContainsInAnyOrder(expectedDatabases.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAllDatabase() throws Exception { + + String query = String.format("SELECT * from c where c.id in ('%s', '%s')", + databaseId1, + databaseId2); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + Flux> queryObservable = client.queryDatabases(query, options); + + List expectedDatabases = createdDatabases.stream().map(d -> d.read().block().properties()).collect(Collectors.toList()); + + assertThat(expectedDatabases).isNotEmpty(); + + int expectedPageSize = (expectedDatabases.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDatabases.size()) + .exactlyContainsInAnyOrder(expectedDatabases.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDatabases_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = client.queryDatabases(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdDatabases.add(createDatabase(client, databaseId1)); + createdDatabases.add(createDatabase(client, databaseId2)); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabases.get(0)); + safeDeleteDatabase(createdDatabases.get(1)); + + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentClientResourceLeakTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentClientResourceLeakTest.java new file mode 100644 index 0000000000000..5ff9d51ee28cc --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentClientResourceLeakTest.java @@ -0,0 +1,104 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.google.common.base.Strings; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.apache.commons.io.FileUtils.ONE_MB; +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentClientResourceLeakTest extends TestSuiteBase { + + private static final int TIMEOUT = 2400000; + private static final int MAX_NUMBER = 1000; + + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + + @Factory(dataProvider = "simpleClientBuildersWithDirect") + public DocumentClientResourceLeakTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(enabled = false, groups = {"emulator"}, timeOut = TIMEOUT) + public void resourceLeak() throws Exception { + + System.gc(); + TimeUnit.SECONDS.sleep(10); + long usedMemoryInBytesBefore = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); + + for (int i = 0; i < MAX_NUMBER; i++) { + logger.info("CLIENT {}", i); + CosmosClient client = this.clientBuilder().build(); + try { + logger.info("creating document"); + createDocument(client.getDatabase(createdDatabase.id()).getContainer(createdCollection.id()), + getDocumentDefinition()); + } finally { + logger.info("closing client"); + client.close(); + } + } + + System.gc(); + TimeUnit.SECONDS.sleep(10); + + long usedMemoryInBytesAfter = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()); + + logger.info("Memory delta: {} - {} = {} MB", + usedMemoryInBytesAfter / (double)ONE_MB, + usedMemoryInBytesBefore / (double)ONE_MB, + (usedMemoryInBytesAfter - usedMemoryInBytesBefore) / (double)ONE_MB); + + assertThat(usedMemoryInBytesAfter - usedMemoryInBytesBefore).isLessThan(125 * ONE_MB); + } + + @BeforeClass(groups = {"emulator"}, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + CosmosClient client = this.clientBuilder().build(); + try { + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } finally { + client.close(); + } + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + return new CosmosItemProperties(Strings.lenientFormat( + "{\"id\":\"%s\",\"mypk\":\"%s\",\"sgmts\":[[6519456,1471916863],[2498434,1455671440]]}", uuid, uuid + )); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentCrudTest.java new file mode 100644 index 0000000000000..6ae3c8c730f65 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/DocumentCrudTest.java @@ -0,0 +1,365 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.FailureValidator; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.UUID; +import java.util.concurrent.TimeoutException; + +import static org.apache.commons.io.FileUtils.ONE_MB; +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentCrudTest extends TestSuiteBase { + + private CosmosClient client; + private CosmosContainer container; + + @Factory(dataProvider = "clientBuildersWithDirect") + public DocumentCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @DataProvider(name = "documentCrudArgProvider") + public Object[][] documentCrudArgProvider() { + return new Object[][] { + // collection name, is name base + { UUID.randomUUID().toString() }, + // with special characters in the name. + { "+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~" }, + }; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocument(String documentId) throws InterruptedException { + + CosmosItemProperties properties = getDocumentDefinition(documentId); + Mono createObservable = container.createItem(properties, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(properties.id()) + .build(); + + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createLargeDocument(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + //Keep size as ~ 1.5MB to account for size of other props + int size = (int) (ONE_MB * 1.5); + BridgeInternal.setProperty(docDefinition, "largeString", StringUtils.repeat("x", size)); + + Mono createObservable = container.createItem(docDefinition, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()) + .build(); + + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocumentWithVeryLargePartitionKey(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 100; i++) { + sb.append(i).append("x"); + } + BridgeInternal.setProperty(docDefinition, "mypk", sb.toString()); + + Mono createObservable = container.createItem(docDefinition, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()) + .withProperty("mypk", sb.toString()) + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocumentWithVeryLargePartitionKey(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 100; i++) { + sb.append(i).append("x"); + } + BridgeInternal.setProperty(docDefinition, "mypk", sb.toString()); + + CosmosItem createdDocument = TestSuiteBase.createDocument(container, docDefinition); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(sb.toString())); + Mono readObservable = createdDocument.read(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()) + .withProperty("mypk", sb.toString()) + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocument_AlreadyExists(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + container.createItem(docDefinition, new CosmosItemRequestOptions()).block(); + Mono createObservable = container.createItem(docDefinition, new CosmosItemRequestOptions()); + FailureValidator validator = new FailureValidator.Builder().resourceAlreadyExists().build(); + validateFailure(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocumentTimeout(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + Mono createObservable = container.createItem(docDefinition, new CosmosItemRequestOptions()).timeout(Duration.ofMillis(1)); + FailureValidator validator = new FailureValidator.Builder().instanceOf(TimeoutException.class).build(); + validateFailure(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocument(String documentId) throws InterruptedException { + + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + Mono readObservable = document.read(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(document.id()) + .build(); + + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void timestamp(String documentId) throws Exception { + OffsetDateTime before = OffsetDateTime.now(); + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + Thread.sleep(1000); + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + CosmosItemProperties readDocument = document.read(options).block().properties(); + Thread.sleep(1000); + OffsetDateTime after = OffsetDateTime.now(); + + assertThat(readDocument.timestamp()).isAfterOrEqualTo(before); + assertThat(readDocument.timestamp()).isBeforeOrEqualTo(after); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocument_DoesntExist(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + document.delete(options).block(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + options.partitionKey(new PartitionKey("looloo")); + Mono readObservable = document.read(options); + + FailureValidator validator = new FailureValidator.Builder().instanceOf(CosmosClientException.class) + .statusCode(404).build(); + validateFailure(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + Mono deleteObservable = document.delete(options); + + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + + // attempt to read document which was deleted + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + Mono readObservable = document.read(options); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument_undefinedPK(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = new CosmosItemProperties(); + docDefinition.id(documentId); + + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(PartitionKey.None); + Mono deleteObservable = document.delete(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + + // attempt to read document which was deleted + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + Mono readObservable = document.read(options); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument_DoesntExist(String documentId) throws InterruptedException { + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + document.delete(options).block(); + + // delete again + Mono deleteObservable = document.delete(options); + + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(deleteObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void replaceDocument(String documentId) throws InterruptedException { + // create a document + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = container.createItem(docDefinition, new CosmosItemRequestOptions()).block().item(); + + String newPropValue = UUID.randomUUID().toString(); + BridgeInternal.setProperty(docDefinition, "newProp", newPropValue); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(docDefinition.get("mypk"))); + // replace document + Mono replaceObservable = document.replace(docDefinition, options); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withProperty("newProp", newPropValue).build(); + validateSuccess(replaceObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void upsertDocument_CreateDocument(String documentId) throws Throwable { + // create a document + CosmosItemProperties docDefinition = getDocumentDefinition(documentId); + + + // replace document + Mono upsertObservable = container.upsertItem(docDefinition, new CosmosItemRequestOptions()); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + + validateSuccess(upsertObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void upsertDocument_ReplaceDocument(String documentId) throws Throwable { + + CosmosItemProperties properties = getDocumentDefinition(documentId); + properties = container.createItem(properties, new CosmosItemRequestOptions()).block().properties(); + + String newPropValue = UUID.randomUUID().toString(); + BridgeInternal.setProperty(properties, "newProp", newPropValue); + + // Replace document + + Mono readObservable = container.upsertItem(properties, new CosmosItemRequestOptions()); + System.out.println(properties); + + // Validate result + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withProperty("newProp", newPropValue).build(); + + validateSuccess(readObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + assertThat(this.client).isNull(); + this.client = this.clientBuilder().build(); + this.container = getSharedMultiPartitionCosmosContainer(this.client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + assertThat(this.client).isNotNull(); + this.client.close(); + } + + private CosmosItemProperties getDocumentDefinition(String documentId) { + final String uuid = UUID.randomUUID().toString(); + final CosmosItemProperties properties = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , documentId, uuid)); + return properties; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/LogLevelTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/LogLevelTest.java new file mode 100644 index 0000000000000..290526847e061 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/LogLevelTest.java @@ -0,0 +1,295 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.WriterAppender; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LogLevelTest extends TestSuiteBase { + public final static String COSMOS_DB_LOGGING_CATEGORY = "com.azure.data.cosmos"; + public final static String NETWORK_LOGGING_CATEGORY = "com.azure.data.cosmos.netty-network"; + public final static String LOG_PATTERN_1 = "HTTP/1.1 200 Ok."; + public final static String LOG_PATTERN_2 = "| 0 1 2 3 4 5 6 7 8 9 a b c d e f |"; + public final static String LOG_PATTERN_3 = "USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)"; + public final static String LOG_PATTERN_4 = "CONNECT: "; + + private static CosmosContainer createdCollection; + private static CosmosClient client; + + public LogLevelTest() { + super(createGatewayRxDocumentClient()); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + /** + * This test will try to create document with netty wire DEBUG logging and + * validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithDebugLevel() throws Exception { + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).setLevel(Level.DEBUG); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).isEmpty(); + + } finally { + safeClose(client); + } + } + + /** + * This test will try to create document with netty wire WARN logging and + * validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithWarningLevel() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).setLevel(Level.WARN); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).isEmpty(); + } finally { + safeClose(client); + } + } + + /** + * This test will try to create document with netty wire TRACE logging and + * validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithTraceLevel() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).setLevel(Level.TRACE); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_1); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_2); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_3); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_4); + + } finally { + safeClose(client); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithTraceLevelAtRoot() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(COSMOS_DB_LOGGING_CATEGORY).setLevel(Level.TRACE); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_1); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_2); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_3); + assertThat(consoleWriter.toString()).contains(LOG_PATTERN_4); + } finally { + safeClose(client); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithDebugLevelAtRoot() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(COSMOS_DB_LOGGING_CATEGORY).setLevel(Level.DEBUG); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).isEmpty(); + } finally { + safeClose(client); + } + } + + /** + * This test will try to create document with netty wire ERROR logging and + * validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithErrorClient() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).setLevel(Level.ERROR); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).isEmpty(); + } finally { + safeClose(client); + } + } + + /** + * This test will try to create document with netty wire INFO logging and + * validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithInfoLevel() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(NETWORK_LOGGING_CATEGORY).setLevel(Level.INFO); + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); + + CosmosClient client = clientBuilder().build(); + try { + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, + new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()).build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).isEmpty(); + } finally { + safeClose(client); + } + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties( + String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + "}", uuid, uuid)); + return doc; + } + + @BeforeMethod(groups = { "simple" }) + public void beforeMethod(Method method) { + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } + + @AfterMethod(groups = { "simple" }) + public void afterMethod() { + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT) + public void afterClass() { + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiMasterConflictResolutionTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiMasterConflictResolutionTest.java new file mode 100644 index 0000000000000..cf3879466ee7c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiMasterConflictResolutionTest.java @@ -0,0 +1,216 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeUtils; +import com.azure.data.cosmos.ConflictResolutionMode; +import com.azure.data.cosmos.ConflictResolutionPolicy; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerResponse; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.TestUtils; +import com.azure.data.cosmos.internal.Utils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +// assumes multi master is enabled in endpoint +public class MultiMasterConflictResolutionTest extends TestSuiteBase { + private static final int TIMEOUT = 40000; + + private final String databaseId = CosmosDatabaseForTest.generateId(); + + private PartitionKeyDefinition partitionKeyDef; + private CosmosClient client; + private CosmosDatabase database; + + @Factory(dataProvider = "clientBuilders") + public MultiMasterConflictResolutionTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = "multi-master", timeOut = 10 * TIMEOUT) + public void conflictResolutionPolicyCRUD() { + + // default last writer wins, path _ts + CosmosContainerProperties collectionSettings = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + CosmosContainer collection = database.createContainer(collectionSettings, new CosmosContainerRequestOptions()).block().container(); + collectionSettings = collection.read().block().properties(); + + assertThat(collectionSettings.conflictResolutionPolicy().mode()).isEqualTo(ConflictResolutionMode.LAST_WRITER_WINS); + + // LWW without path specified, should default to _ts + collectionSettings.conflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy()); + collectionSettings = collection.replace(collectionSettings, null).block().properties(); + + assertThat(collectionSettings.conflictResolutionPolicy().mode()).isEqualTo(ConflictResolutionMode.LAST_WRITER_WINS); + assertThat(collectionSettings.conflictResolutionPolicy().conflictResolutionPath()).isEqualTo("/_ts"); + + // Tests the following scenarios + // 1. LWW with valid path + // 2. LWW with null path, should default to _ts + // 3. LWW with empty path, should default to _ts + testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.LAST_WRITER_WINS, + new String[] { "/a", null, "" }, new String[] { "/a", "/_ts", "/_ts" }); + + // LWW invalid path + collectionSettings.conflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("/a/b")); + + try { + collectionSettings = collection.replace(collectionSettings, null).block().properties(); + fail("Expected exception on invalid path."); + } catch (Exception e) { + + // when (e.StatusCode == HttpStatusCode.BadRequest) + CosmosClientException dce = Utils.as(e.getCause(), CosmosClientException.class); + if (dce != null && dce.statusCode() == 400) { + assertThat(dce.getMessage()).contains("Invalid path '\\/a\\/b' for last writer wins conflict resolution"); + } else { + throw e; + } + } + + // LWW invalid path + + collectionSettings.conflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("someText")); + + try { + collectionSettings = collection.replace(collectionSettings, null).block().properties(); + fail("Expected exception on invalid path."); + } catch (Exception e) { + // when (e.StatusCode == HttpStatusCode.BadRequest) + CosmosClientException dce = Utils.as(e.getCause(), CosmosClientException.class); + if (dce != null && dce.statusCode() == 400) { + assertThat(dce.getMessage()).contains("Invalid path 'someText' for last writer wins conflict resolution"); + } else { + throw e; + } + } + + // Tests the following scenarios + // 1. CUSTOM with valid sprocLink + // 2. CUSTOM with null sprocLink, should default to empty string + // 3. CUSTOM with empty sprocLink, should default to empty string + testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.CUSTOM, + new String[] { "randomSprocName", null, "" }, new String[] { "randomSprocName", "", "" }); + } + + private void testConflictResolutionPolicyRequiringPath(ConflictResolutionMode conflictResolutionMode, + String[] paths, String[] expectedPaths) { + for (int i = 0; i < paths.length; i++) { + CosmosContainerProperties collectionSettings = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + + if (conflictResolutionMode == ConflictResolutionMode.LAST_WRITER_WINS) { + collectionSettings.conflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy(paths[i])); + } else { + collectionSettings.conflictResolutionPolicy(ConflictResolutionPolicy.createCustomPolicy(paths[i])); + } + collectionSettings = database.createContainer(collectionSettings, new CosmosContainerRequestOptions()).block().properties(); + assertThat(collectionSettings.conflictResolutionPolicy().mode()).isEqualTo(conflictResolutionMode); + + if (conflictResolutionMode == ConflictResolutionMode.LAST_WRITER_WINS) { + assertThat(collectionSettings.conflictResolutionPolicy().conflictResolutionPath()).isEqualTo(expectedPaths[i]); + } else { + assertThat(collectionSettings.conflictResolutionPolicy().conflictResolutionProcedure()).isEqualTo(expectedPaths[i]); + } + } + } + + @Test(groups = "multi-master", timeOut = TIMEOUT) + public void invalidConflictResolutionPolicy_LastWriterWinsWithStoredProc() throws Exception { + CosmosContainerProperties collection = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + + // LWW without path specified, should default to _ts + ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); + BridgeUtils.setMode(policy, ConflictResolutionMode.LAST_WRITER_WINS); + BridgeUtils.setStoredProc(policy,"randomSprocName"); + collection.conflictResolutionPolicy(policy); + + Mono createObservable = database.createContainer( + collection, + new CosmosContainerRequestOptions()); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .errorMessageContains("LastWriterWins conflict resolution mode should not have conflict resolution procedure set.") + .build(); + validateFailure(createObservable, validator); + } + + @Test(groups = "multi-master", timeOut = TIMEOUT) + public void invalidConflictResolutionPolicy_CustomWithPath() throws Exception { + CosmosContainerProperties collection = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + + // LWW without path specified, should default to _ts + ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); + BridgeUtils.setMode(policy, ConflictResolutionMode.CUSTOM); + BridgeUtils.setPath(policy,"/mypath"); + collection.conflictResolutionPolicy(policy); + + Mono createObservable = database.createContainer( + collection, + new CosmosContainerRequestOptions()); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .errorMessageContains("Custom conflict resolution mode should not have conflict resolution path set.") + .build(); + validateFailure(createObservable, validator); + } + + @BeforeClass(groups = {"multi-master"}, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + // set up the client + + client = clientBuilder().build(); + database = createDatabase(client, databaseId); + partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + } + + @AfterClass(groups = {"multi-master"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(database); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiOrderByQueryTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiOrderByQueryTests.java new file mode 100644 index 0000000000000..7aecad17ddea4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/MultiOrderByQueryTests.java @@ -0,0 +1,344 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.CompositePathSortOrder; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.collections4.ComparatorUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.UUID; + +public class MultiOrderByQueryTests extends TestSuiteBase { + + private static final int TIMEOUT = 35000; + private static final String NUMBER_FIELD = "numberField"; + private static final String STRING_FIELD = "stringField"; + private static final String NUMBER_FIELD_2 = "numberField2"; + private static final String STRING_FIELD_2 = "stringField2"; + private static final String BOOL_FIELD = "boolField"; + private static final String NULL_FIELD = "nullField"; + private static final String OBJECT_FIELD = "objectField"; + private static final String ARRAY_FIELD = "arrayField"; + private static final String SHORT_STRING_FIELD = "shortStringField"; + private static final String MEDIUM_STRING_FIELD = "mediumStringField"; + private static final String LONG_STRING_FIELD = "longStringField"; + private static final String PARTITION_KEY = "pk"; + private List documents = new ArrayList(); + private CosmosContainer documentCollection; + private CosmosClient client; + + class CustomComparator implements Comparator { + String path; + CompositePathSortOrder order; + boolean isNumericPath = false; + boolean isStringPath = false; + boolean isBooleanPath = false; + boolean isNullPath = false; + + public CustomComparator(String path, CompositePathSortOrder order) { + this.path = path; + this.order = order; + if (this.path.contains("number")) { + isNumericPath = true; + } else if (this.path.toLowerCase().contains("string")) { + isStringPath = true; + } else if (this.path.contains("bool")) { + isBooleanPath = true; + } else if (this.path.contains("null")) { + isNullPath = true; + } + } + + @Override + public int compare(CosmosItemProperties doc1, CosmosItemProperties doc2) { + boolean isAsc = order == CompositePathSortOrder.ASCENDING; + if (isNumericPath) { + if (doc1.getInt(path) < doc2.getInt(path)) + return isAsc ? -1 : 1; + else if (doc1.getInt(path) > doc2.getInt(path)) + return isAsc ? 1 : -1; + else + return 0; + } else if (isStringPath) { + if (!isAsc) { + CosmosItemProperties temp = doc1; + doc1 = doc2; + doc2 = temp; + } + return doc1.getString(path).compareTo(doc2.getString(path)); + } else if (isBooleanPath) { + if (doc1.getBoolean(path) == false && doc2.getBoolean(path) == true) + return isAsc ? -1 : 1; + else if (doc1.getBoolean(path) == true && doc2.getBoolean(path) == false) + return isAsc ? 1 : -1; + else + return 0; + } else if (isNullPath) { + // all nulls are equal + return 0; + } else { + throw new IllegalStateException("data type not handled by comparator!"); + } + } + } + + @Factory(dataProvider = "clientBuilders") + public MultiOrderByQueryTests(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + documentCollection = getSharedMultiPartitionCosmosContainerWithCompositeAndSpatialIndexes(client); + truncateCollection(documentCollection); + + int numberOfDocuments = 4; + + Random random = new Random(); + for (int i = 0; i < numberOfDocuments; ++i) { + CosmosItemProperties multiOrderByDocument = generateMultiOrderByDocument(); + String multiOrderByDocumentString = multiOrderByDocument.toJson(); + int numberOfDuplicates = 5; + + for (int j = 0; j < numberOfDuplicates; j++) { + // Add the document itself for exact duplicates + CosmosItemProperties initialDocument = new CosmosItemProperties(multiOrderByDocumentString); + initialDocument.id(UUID.randomUUID().toString()); + this.documents.add(initialDocument); + + // Permute all the fields so that there are duplicates with tie breaks + CosmosItemProperties numberClone = new CosmosItemProperties(multiOrderByDocumentString); + BridgeInternal.setProperty(numberClone, NUMBER_FIELD, random.nextInt(5)); + numberClone.id(UUID.randomUUID().toString()); + this.documents.add(numberClone); + + CosmosItemProperties stringClone = new CosmosItemProperties(multiOrderByDocumentString); + BridgeInternal.setProperty(stringClone, STRING_FIELD, Integer.toString(random.nextInt(5))); + stringClone.id(UUID.randomUUID().toString()); + this.documents.add(stringClone); + + CosmosItemProperties boolClone = new CosmosItemProperties(multiOrderByDocumentString); + BridgeInternal.setProperty(boolClone, BOOL_FIELD, random.nextInt(2) % 2 == 0); + boolClone.id(UUID.randomUUID().toString()); + this.documents.add(boolClone); + + // Also fuzz what partition it goes to + CosmosItemProperties partitionClone = new CosmosItemProperties(multiOrderByDocumentString); + BridgeInternal.setProperty(partitionClone, PARTITION_KEY, random.nextInt(5)); + partitionClone.id(UUID.randomUUID().toString()); + this.documents.add(partitionClone); + } + } + + voidBulkInsertBlocking(documentCollection, documents); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + private CosmosItemProperties generateMultiOrderByDocument() { + Random random = new Random(); + CosmosItemProperties document = new CosmosItemProperties(); + document.id(UUID.randomUUID().toString()); + BridgeInternal.setProperty(document, NUMBER_FIELD, random.nextInt(5)); + BridgeInternal.setProperty(document, NUMBER_FIELD_2, random.nextInt(5)); + BridgeInternal.setProperty(document, BOOL_FIELD, (random.nextInt() % 2) == 0); + BridgeInternal.setProperty(document, STRING_FIELD, Integer.toString(random.nextInt(5))); + BridgeInternal.setProperty(document, STRING_FIELD_2, Integer.toString(random.nextInt(5))); + BridgeInternal.setProperty(document, NULL_FIELD, null); + BridgeInternal.setProperty(document, OBJECT_FIELD, ""); + BridgeInternal.setProperty(document, ARRAY_FIELD, (new ObjectMapper()).createArrayNode()); + BridgeInternal.setProperty(document, SHORT_STRING_FIELD, "a" + random.nextInt(100)); + BridgeInternal.setProperty(document, MEDIUM_STRING_FIELD, "a" + random.nextInt(128) + 100); + BridgeInternal.setProperty(document, LONG_STRING_FIELD, "a" + random.nextInt(255) + 128); + BridgeInternal.setProperty(document, PARTITION_KEY, random.nextInt(5)); + return document; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocumentsWithMultiOrder() throws CosmosClientException, InterruptedException { + FeedOptions feedOptions = new FeedOptions(); + feedOptions.enableCrossPartitionQuery(true); + + boolean[] booleanValues = new boolean[] {true, false}; + CosmosContainerProperties containerSettings = documentCollection.read().block().properties(); + Iterator> compositeIndexesIterator = containerSettings.indexingPolicy().compositeIndexes().iterator(); + while (compositeIndexesIterator.hasNext()) { + List compositeIndex = compositeIndexesIterator.next(); + // for every order + for (boolean invert : booleanValues) { + // for normal and inverted order + for (boolean hasTop : booleanValues) { + // with and without top + for (boolean hasFilter : booleanValues) { + // with and without filter + // Generate a multi order by from that index + List orderByItems = new ArrayList(); + List selectItems = new ArrayList(); + boolean isDesc; + Iterator compositeIndexiterator = compositeIndex.iterator(); + while (compositeIndexiterator.hasNext()) { + CompositePath compositePath = compositeIndexiterator.next(); + isDesc = compositePath.order() == CompositePathSortOrder.DESCENDING ? true : false; + if (invert) { + isDesc = !isDesc; + } + + String isDescString = isDesc ? "DESC" : "ASC"; + String compositePathName = compositePath.path().replaceAll("/", ""); + String orderByItemsString = "root." + compositePathName + " " + isDescString; + String selectItemsString = "root." + compositePathName; + orderByItems.add(orderByItemsString); + selectItems.add(selectItemsString); + } + + int topCount = 10; + StringBuilder selectItemStringBuilder = new StringBuilder(); + for (String selectItem: selectItems) { + selectItemStringBuilder.append(selectItem); + selectItemStringBuilder.append(","); + } + selectItemStringBuilder.deleteCharAt(selectItemStringBuilder.length() - 1); + StringBuilder orderByItemStringBuilder = new StringBuilder(); + for (String orderByItem : orderByItems) { + orderByItemStringBuilder.append(orderByItem); + orderByItemStringBuilder.append(","); + } + orderByItemStringBuilder.deleteCharAt(orderByItemStringBuilder.length() - 1); + + String topString = hasTop ? "TOP " + topCount : ""; + String whereString = hasFilter ? "WHERE root." + NUMBER_FIELD + " % 2 = 0" : ""; + String query = "SELECT " + topString + " [" + selectItemStringBuilder.toString() + "] " + + "FROM root " + whereString + " " + + "ORDER BY " + orderByItemStringBuilder.toString(); + + List expectedOrderedList = top(sort(filter(this.documents, hasFilter), compositeIndex, invert), hasTop, topCount) ; + + Flux> queryObservable = documentCollection.queryItems(query, feedOptions); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .withOrderedResults(expectedOrderedList, compositeIndex) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + } + } + } + + // CREATE document with numberField not set. + // This query would then be invalid. + CosmosItemProperties documentWithEmptyField = generateMultiOrderByDocument(); + BridgeInternal.remove(documentWithEmptyField, NUMBER_FIELD); + documentCollection.createItem(documentWithEmptyField, new CosmosItemRequestOptions()).block(); + String query = "SELECT [root." + NUMBER_FIELD + ",root." + STRING_FIELD + "] FROM root ORDER BY root." + NUMBER_FIELD + " ASC ,root." + STRING_FIELD + " DESC"; + Flux> queryObservable = documentCollection.queryItems(query, feedOptions); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(UnsupportedOperationException.class) + .build(); + + validateQueryFailure(queryObservable, validator); + } + + private List top(List arrayList, boolean hasTop, int topCount) { + List result = new ArrayList(); + int counter = 0; + if (hasTop) { + while (counter < topCount && counter < arrayList.size()) { + result.add(arrayList.get(counter)); + counter++; + } + } else { + result.addAll(arrayList); + } + return result; + } + + private List sort(List arrayList, List compositeIndex, + boolean invert) { + Collection> comparators = new ArrayList>(); + Iterator compositeIndexIterator = compositeIndex.iterator(); + while (compositeIndexIterator.hasNext()) { + CompositePath compositePath = compositeIndexIterator.next(); + CompositePathSortOrder order = compositePath.order(); + if (invert) { + if (order == CompositePathSortOrder.DESCENDING) { + order = CompositePathSortOrder.ASCENDING; + } else { + order = CompositePathSortOrder.DESCENDING; + } + } + String path = compositePath.path().replace("/", ""); + comparators.add(new CustomComparator(path, order)); + } + Collections.sort(arrayList, ComparatorUtils.chainedComparator(comparators)); + return arrayList; + } + + private List filter(List cosmosItemSettings, boolean hasFilter) { + List result = new ArrayList(); + if (hasFilter) { + for (CosmosItemProperties document : cosmosItemSettings) { + if (document.getInt(NUMBER_FIELD) % 2 == 0) { + result.add(document); + } + } + } else { + result.addAll(cosmosItemSettings); + } + return result; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferQueryTest.java new file mode 100644 index 0000000000000..131a83dfeba3c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferQueryTest.java @@ -0,0 +1,169 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.AsyncDocumentClient.Builder; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.assertj.core.util.Strings; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +//TODO: change to use external TestSuiteBase +public class OfferQueryTest extends TestSuiteBase { + + public final static int SETUP_TIMEOUT = 40000; + public final String databaseId = DatabaseForTest.generateId(); + + private List createdCollections = new ArrayList<>(); + + private AsyncDocumentClient client; + + private String getDatabaseLink() { + return TestUtils.getDatabaseNameLink(databaseId); + } + + @Factory(dataProvider = "clientBuilders") + public OfferQueryTest(Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void queryOffersWithFilter() throws Exception { + String collectionResourceId = createdCollections.get(0).resourceId(); + String query = String.format("SELECT * from c where c.offerResourceId = '%s'", collectionResourceId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + Flux> queryObservable = client.queryOffers(query, null); + + List allOffers = client.readOffers(null).flatMap(f -> Flux.fromIterable(f.results())).collectList().single().block(); + List expectedOffers = allOffers.stream().filter(o -> collectionResourceId.equals(o.getString("offerResourceId"))).collect(Collectors.toList()); + + assertThat(expectedOffers).isNotEmpty(); + + int expectedPageSize = (expectedOffers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedOffers.size()) + .exactlyContainsInAnyOrder(expectedOffers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT * 100) + public void queryOffersFilterMorePages() throws Exception { + + List collectionResourceIds = createdCollections.stream().map(c -> c.resourceId()).collect(Collectors.toList()); + String query = String.format("SELECT * from c where c.offerResourceId in (%s)", + Strings.join(collectionResourceIds.stream().map(s -> "'" + s + "'").collect(Collectors.toList())).with(",")); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(1); + Flux> queryObservable = client.queryOffers(query, options); + + List expectedOffers = client.readOffers(null).flatMap(f -> Flux.fromIterable(f.results())) + .collectList() + .single().block() + .stream().filter(o -> collectionResourceIds.contains(o.getOfferResourceId())) + .collect(Collectors.toList()); + + assertThat(expectedOffers).hasSize(createdCollections.size()); + + int expectedPageSize = (expectedOffers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedOffers.size()) + .exactlyContainsInAnyOrder(expectedOffers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void queryCollections_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + Flux> queryObservable = client.queryCollections(getDatabaseLink(), query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + + Database d1 = new Database(); + d1.id(databaseId); + createDatabase(client, d1); + + for(int i = 0; i < 3; i++) { + DocumentCollection collection = new DocumentCollection(); + collection.id(UUID.randomUUID().toString()); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collection.setPartitionKey(partitionKeyDef); + + createdCollections.add(createCollection(client, databaseId, collection)); + } + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, databaseId); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferReadReplaceTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferReadReplaceTest.java new file mode 100644 index 0000000000000..f6fe31df0045b --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OfferReadReplaceTest.java @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.List; + +//TODO: change to use external TestSuiteBase +public class OfferReadReplaceTest extends TestSuiteBase { + + public final String databaseId = DatabaseForTest.generateId(); + + private Database createdDatabase; + private DocumentCollection createdCollection; + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public OfferReadReplaceTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readAndReplaceOffer() { + + client.readOffers(null).subscribe((offersFeed) -> { + try { + int i; + List offers = offersFeed.results(); + for (i = 0; i < offers.size(); i++) { + if (offers.get(i).getOfferResourceId().equals(createdCollection.resourceId())) { + break; + } + } + + Offer rOffer = client.readOffer(offers.get(i).selfLink()).single().block().getResource(); + int oldThroughput = rOffer.getThroughput(); + + Flux> readObservable = client.readOffer(offers.get(i).selfLink()); + + // validate offer read + ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() + .withOfferThroughput(oldThroughput) + .notNullEtag() + .build(); + + validateSuccess(readObservable, validatorForRead); + + // update offer + int newThroughput = oldThroughput + 100; + offers.get(i).setThroughput(newThroughput); + Flux> replaceObservable = client.replaceOffer(offers.get(i)); + + // validate offer replace + ResourceResponseValidator validatorForReplace = new ResourceResponseValidator.Builder() + .withOfferThroughput(newThroughput) + .notNullEtag() + .build(); + + validateSuccess(replaceObservable, validatorForReplace); + + } catch (Exception e) { + e.printStackTrace(); + } + + }); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + createdCollection = createCollection(client, createdDatabase.id(), + getCollectionDefinition()); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, createdDatabase); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OrderbyDocumentQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OrderbyDocumentQueryTest.java new file mode 100644 index 0000000000000..4dae14a588277 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/OrderbyDocumentQueryTest.java @@ -0,0 +1,571 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.query.CompositeContinuationToken; +import com.azure.data.cosmos.internal.query.OrderByContinuationToken; +import com.azure.data.cosmos.internal.query.QueryItem; +import com.azure.data.cosmos.internal.routing.Range; +import com.fasterxml.jackson.core.JsonProcessingException; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OrderbyDocumentQueryTest extends TestSuiteBase { + private final double minQueryRequestChargePerPartition = 2.0; + + private CosmosClient client; + private CosmosContainer createdCollection; + private CosmosDatabase createdDatabase; + private List createdDocuments = new ArrayList<>(); + + private int numberOfPartitions; + + @Factory(dataProvider = "clientBuildersWithDirect") + public OrderbyDocumentQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider") + public void queryDocumentsValidateContent(boolean qmEnabled) throws Exception { + CosmosItemProperties expectedDocument = createdDocuments.get(0); + + String query = String.format("SELECT * from root r where r.propStr = '%s'" + + " ORDER BY r.propInt" + , expectedDocument.getString("propStr")); + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(qmEnabled); + + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedResourceIds = new ArrayList<>(); + expectedResourceIds.add(expectedDocument.resourceId()); + + Map> resourceIDToValidator = new HashMap<>(); + + resourceIDToValidator.put(expectedDocument.resourceId(), + new ResourceValidator.Builder().areEqual(expectedDocument).build()); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .numberOfPages(1) + .containsExactly(expectedResourceIds) + .validateAllResources(resourceIDToValidator) + .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) + .allPagesSatisfy(new FeedResponseValidator.Builder().hasRequestChargeHeader().build()) + .hasValidQueryMetrics(qmEnabled) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocuments_NoResults() throws Exception { + String query = "SELECT * from root r where r.id = '2' ORDER BY r.propInt"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .hasRequestChargeHeader().build()) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @DataProvider(name = "sortOrder") + public Object[][] sortOrder() { + return new Object[][] { { "ASC" }, {"DESC"} }; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "sortOrder") + public void queryOrderBy(String sortOrder) throws Exception { + String query = String.format("SELECT * FROM r ORDER BY r.propInt %s", sortOrder); + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + int pageSize = 3; + options.maxItemCount(pageSize); + Flux> queryObservable = createdCollection.queryItems(query, options); + Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); + + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); + if ("DESC".equals(sortOrder)) { + Collections.reverse(expectedResourceIds); + } + + int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedResourceIds) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .hasRequestChargeHeader().build()) + .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryOrderByInt() throws Exception { + String query = "SELECT * FROM r ORDER BY r.propInt"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + int pageSize = 3; + options.maxItemCount(pageSize); + Flux> queryObservable = createdCollection.queryItems(query, options); + + Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); + int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedResourceIds) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .hasRequestChargeHeader().build()) + .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryOrderByString() throws Exception { + String query = "SELECT * FROM r ORDER BY r.propStr"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + int pageSize = 3; + options.maxItemCount(pageSize); + Flux> queryObservable = createdCollection.queryItems(query, options); + + Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propStr", d -> d.getString("propStr"), validatorComparator); + int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedResourceIds) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .hasRequestChargeHeader().build()) + .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @DataProvider(name = "topValue") + public Object[][] topValueParameter() { + return new Object[][] { { 0 }, { 1 }, { 5 }, { createdDocuments.size() - 1 }, { createdDocuments.size() }, + { createdDocuments.size() + 1 }, { 2 * createdDocuments.size() } }; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "topValue") + public void queryOrderWithTop(int topValue) throws Exception { + String query = String.format("SELECT TOP %d * FROM r ORDER BY r.propInt", topValue); + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + int pageSize = 3; + options.maxItemCount(pageSize); + Flux> queryObservable = createdCollection.queryItems(query, options); + + Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); + + List expectedResourceIds = + sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator) + .stream().limit(topValue).collect(Collectors.toList()); + + int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedResourceIds) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .hasRequestChargeHeader().build()) + .totalRequestChargeIsAtLeast(numberOfPartitions * (topValue > 0 ? minQueryRequestChargePerPartition : 1)) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + private List sortDocumentsAndCollectResourceIds(String propName, Function extractProp, Comparator comparer) { + return createdDocuments.stream() + .filter(d -> d.getMap().containsKey(propName)) // removes undefined + .sorted((d1, d2) -> comparer.compare(extractProp.apply(d1), extractProp.apply(d2))) + .map(Resource::resourceId).collect(Collectors.toList()); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void crossPartitionQueryNotEnabled() throws Exception { + String query = "SELECT * FROM r ORDER BY r.propInt"; + FeedOptions options = new FeedOptions(); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .build(); + validateQueryFailure(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryScopedToSinglePartition_StartWithContinuationToken() throws Exception { + String query = "SELECT * FROM r ORDER BY r.propScopedPartitionInt ASC"; + FeedOptions options = new FeedOptions(); + options.partitionKey(new PartitionKey("duplicateParitionKeyValue")); + options.maxItemCount(3); + Flux> queryObservable = createdCollection.queryItems(query, options); + + TestSubscriber> subscriber = new TestSubscriber<>(); + queryObservable.take(1).subscribe(subscriber); + + subscriber.awaitTerminalEvent(); + subscriber.assertComplete(); + subscriber.assertNoErrors(); + assertThat(subscriber.valueCount()).isEqualTo(1); + FeedResponse page = (FeedResponse) subscriber.getEvents().get(0).get(0); + assertThat(page.results()).hasSize(3); + + assertThat(page.continuationToken()).isNotEmpty(); + + + options.requestContinuation(page.continuationToken()); + queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments.stream() + .filter(d -> (StringUtils.equals("duplicateParitionKeyValue", d.getString("mypk")))) + .filter(d -> (d.getInt("propScopedPartitionInt") > 2)).collect(Collectors.toList()); + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + assertThat(expectedDocs).hasSize(10 - 3); + + FeedResponseListValidator validator = null; + + validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedDocs.stream() + .sorted((e1, e2) -> Integer.compare(e1.getInt("propScopedPartitionInt"), e2.getInt("propScopedPartitionInt"))) + .map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void orderByContinuationTokenRoundTrip() throws Exception { + { + // Positive + OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( + new CompositeContinuationToken( + "asdf", + new Range("A", "D", false, true)), + new QueryItem[] {new QueryItem("{\"item\" : 42}")}, + "rid", + false); + String serialized = orderByContinuationToken.toString(); + ValueHolder outOrderByContinuationToken = new ValueHolder(); + + assertThat(OrderByContinuationToken.tryParse(serialized, outOrderByContinuationToken)).isTrue(); + OrderByContinuationToken deserialized = outOrderByContinuationToken.v; + CompositeContinuationToken compositeContinuationToken = deserialized.getCompositeContinuationToken(); + String token = compositeContinuationToken.getToken(); + Range range = compositeContinuationToken.getRange(); + assertThat(token).isEqualTo("asdf"); + assertThat(range.getMin()).isEqualTo("A"); + assertThat(range.getMax()).isEqualTo("D"); + assertThat(range.isMinInclusive()).isEqualTo(false); + assertThat(range.isMaxInclusive()).isEqualTo(true); + + QueryItem[] orderByItems = deserialized.getOrderByItems(); + assertThat(orderByItems).isNotNull(); + assertThat(orderByItems.length).isEqualTo(1); + assertThat(orderByItems[0].getItem()).isEqualTo(42); + + String rid = deserialized.getRid(); + assertThat(rid).isEqualTo("rid"); + + boolean inclusive = deserialized.getInclusive(); + assertThat(inclusive).isEqualTo(false); + } + + { + // Negative + ValueHolder outOrderByContinuationToken = new ValueHolder(); + assertThat(OrderByContinuationToken.tryParse("{\"property\" : \"Not a valid Order By Token\"}", outOrderByContinuationToken)).isFalse(); + } + } + @Test(groups = { "simple" }, timeOut = TIMEOUT * 10, dataProvider = "sortOrder", + retryAnalyzer = RetryAnalyzer.class) + public void queryDocumentsWithOrderByContinuationTokensInteger(String sortOrder) throws Exception { + // Get Actual + String query = String.format("SELECT * FROM c ORDER BY c.propInt %s", sortOrder); + + // Get Expected + Comparator order = sortOrder.equals("ASC")?Comparator.naturalOrder():Comparator.reverseOrder(); + Comparator validatorComparator = Comparator.nullsFirst(order); + + List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); + this.queryWithContinuationTokensAndPageSizes(query, new int[] { 1, 5, 10, 100}, expectedResourceIds); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 10, dataProvider = "sortOrder") + public void queryDocumentsWithOrderByContinuationTokensString(String sortOrder) throws Exception { + // Get Actual + String query = String.format("SELECT * FROM c ORDER BY c.id %s", sortOrder); + + // Get Expected + Comparator order = sortOrder.equals("ASC")?Comparator.naturalOrder():Comparator.reverseOrder(); + Comparator validatorComparator = Comparator.nullsFirst(order); + + List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> d.getString("id"), validatorComparator); + this.queryWithContinuationTokensAndPageSizes(query, new int[] { 1, 5, 10, 100 }, expectedResourceIds); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 10, dataProvider = "sortOrder") + public void queryDocumentsWithInvalidOrderByContinuationTokensString(String sortOrder) throws Exception { + // Get Actual + String query = String.format("SELECT * FROM c ORDER BY c.id %s", sortOrder); + + // Get Expected + Comparator validatorComparator; + if(sortOrder.equals("ASC")) { + validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); + }else{ + validatorComparator = Comparator.nullsFirst(Comparator.reverseOrder()); + } + List expectedResourceIds = sortDocumentsAndCollectResourceIds("id", d -> d.getString("id"), validatorComparator); + this.assertInvalidContinuationToken(query, new int[] { 1, 5, 10, 100 }, expectedResourceIds); + } + + public CosmosItemProperties createDocument(CosmosContainer cosmosContainer, Map keyValueProps) + throws CosmosClientException { + CosmosItemProperties docDefinition = getDocumentDefinition(keyValueProps); + return cosmosContainer.createItem(docDefinition).block().properties(); + } + + public List bulkInsert(CosmosContainer cosmosContainer, List> keyValuePropsList) { + + ArrayList result = new ArrayList(); + + for(Map keyValueProps: keyValuePropsList) { + CosmosItemProperties docDefinition = getDocumentDefinition(keyValueProps); + result.add(docDefinition); + } + + return bulkInsertBlocking(cosmosContainer, result); + } + + @BeforeMethod(groups = { "simple" }) + public void beforeMethod() throws Exception { + // add a cool off time + TimeUnit.SECONDS.sleep(10); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + List> keyValuePropsList = new ArrayList<>(); + Map props; + + for(int i = 0; i < 30; i++) { + props = new HashMap<>(); + props.put("propInt", i); + props.put("propStr", String.valueOf(i)); + keyValuePropsList.add(props); + } + + //undefined values + props = new HashMap<>(); + keyValuePropsList.add(props); + + createdDocuments = bulkInsert(createdCollection, keyValuePropsList); + + for(int i = 0; i < 10; i++) { + Map p = new HashMap<>(); + p.put("propScopedPartitionInt", i); + CosmosItemProperties doc = getDocumentDefinition("duplicateParitionKeyValue", UUID.randomUUID().toString(), p); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(new PartitionKey(doc.get("mypk"))); + createdDocuments.add(createDocument(createdCollection, doc).read(options).block().properties()); + + } + + numberOfPartitions = CosmosBridgeInternal.getAsyncDocumentClient(client) + .readPartitionKeyRanges("dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(), null) + .flatMap(p -> Flux.fromIterable(p.results())).collectList().single().block().size(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private void assertInvalidContinuationToken(String query, int[] pageSize, List expectedIds) { + String requestContinuation = null; + do { + FeedOptions options = new FeedOptions(); + options.maxItemCount(1); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(2); + OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( + new CompositeContinuationToken( + "asdf", + new Range("A", "D", false, true)), + new QueryItem[] {new QueryItem("{\"item\" : 42}")}, + "rid", + false); + options.requestContinuation(orderByContinuationToken.toString()); + Flux> queryObservable = createdCollection.queryItems(query, + options); + + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertError(CosmosClientException.class); + } while (requestContinuation != null); + } + + private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, List expectedIds) { + for (int pageSize : pageSizes) { + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + List actualIds = new ArrayList(); + for (CosmosItemProperties document : receivedDocuments) { + actualIds.add(document.resourceId()); + } + + assertThat(actualIds).containsExactlyElementsOf(expectedIds); + } + } + + private List queryWithContinuationTokens(String query, int pageSize) { + String requestContinuation = null; + List continuationTokens = new ArrayList(); + List receivedDocuments = new ArrayList(); + do { + FeedOptions options = new FeedOptions(); + options.maxItemCount(pageSize); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(2); + options.requestContinuation(requestContinuation); + Flux> queryObservable = createdCollection.queryItems(query, + options); + + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); + requestContinuation = firstPage.continuationToken(); + receivedDocuments.addAll(firstPage.results()); + continuationTokens.add(requestContinuation); + } while (requestContinuation != null); + + return receivedDocuments; + } + + private static CosmosItemProperties getDocumentDefinition(String partitionKey, String id, Map keyValuePair) { + StringBuilder sb = new StringBuilder(); + sb.append("{\n"); + + for(String key: keyValuePair.keySet()) { + Object val = keyValuePair.get(key); + sb.append(" "); + sb.append("\"").append(key).append("\"").append(" :" ); + if (val == null) { + sb.append("null"); + } else { + sb.append(toJson(val)); + } + sb.append(",\n"); + } + + sb.append(String.format(" \"id\": \"%s\",\n", id)); + sb.append(String.format(" \"mypk\": \"%s\"\n", partitionKey)); + sb.append("}"); + + return new CosmosItemProperties(sb.toString()); + } + + private static CosmosItemProperties getDocumentDefinition(Map keyValuePair) { + String uuid = UUID.randomUUID().toString(); + return getDocumentDefinition(uuid, uuid, keyValuePair); + } + + private static String toJson(Object object){ + try { + return Utils.getSimpleObjectMapper().writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParallelDocumentQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParallelDocumentQueryTest.java new file mode 100644 index 0000000000000..3bfcaa3679bc8 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParallelDocumentQueryTest.java @@ -0,0 +1,383 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.query.CompositeContinuationToken; +import com.azure.data.cosmos.internal.routing.Range; +import io.reactivex.subscribers.TestSubscriber; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static com.azure.data.cosmos.CommonsBridgeInternal.partitionKeyRangeIdInternal; +import static org.assertj.core.api.Assertions.assertThat; + +public class ParallelDocumentQueryTest extends TestSuiteBase { + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + @Factory(dataProvider = "clientBuildersWithDirect") + public ParallelDocumentQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @DataProvider(name = "queryMetricsArgProvider") + public Object[][] queryMetricsArgProvider() { + return new Object[][]{ + {true}, + {false}, + }; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider") + public void queryDocuments(boolean qmEnabled) { + String query = "SELECT * from c where c.prop = 99"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(qmEnabled); + options.maxDegreeOfParallelism(2); + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .hasValidQueryMetrics(qmEnabled) + .build(); + + validateQuerySuccess(queryObservable, validator, TIMEOUT); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryMetricEquality() throws Exception { + String query = "SELECT * from c where c.prop = 99"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(true); + options.maxDegreeOfParallelism(0); + + Flux> queryObservable = createdCollection.queryItems(query, options); + List> resultList1 = queryObservable.collectList().block(); + + options.maxDegreeOfParallelism(4); + Flux> threadedQueryObs = createdCollection.queryItems(query, options); + List> resultList2 = threadedQueryObs.collectList().block(); + + assertThat(resultList1.size()).isEqualTo(resultList2.size()); + for(int i = 0; i < resultList1.size(); i++){ + compareQueryMetrics(BridgeInternal.queryMetricsFromFeedResponse(resultList1.get(i)), + BridgeInternal.queryMetricsFromFeedResponse(resultList2.get(i))); + } + } + + private void compareQueryMetrics(Map qm1, Map qm2) { + assertThat(qm1.keySet().size()).isEqualTo(qm2.keySet().size()); + QueryMetrics queryMetrics1 = BridgeInternal.createQueryMetricsFromCollection(qm1.values()); + QueryMetrics queryMetrics2 = BridgeInternal.createQueryMetricsFromCollection(qm2.values()); + assertThat(queryMetrics1.getRetrievedDocumentSize()).isEqualTo(queryMetrics2.getRetrievedDocumentSize()); + assertThat(queryMetrics1.getRetrievedDocumentCount()).isEqualTo(queryMetrics2.getRetrievedDocumentCount()); + assertThat(queryMetrics1.getIndexHitDocumentCount()).isEqualTo(queryMetrics2.getIndexHitDocumentCount()); + assertThat(queryMetrics1.getOutputDocumentCount()).isEqualTo(queryMetrics2.getOutputDocumentCount()); + assertThat(queryMetrics1.getOutputDocumentSize()).isEqualTo(queryMetrics2.getOutputDocumentSize()); + assertThat(BridgeInternal.getClientSideMetrics(queryMetrics1).getRequestCharge()) + .isEqualTo(BridgeInternal.getClientSideMetrics(queryMetrics1).getRequestCharge()); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocuments_NoResults() { + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPagesIsGreaterThanOrEqualTo(1) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .pageSizeIsLessThanOrEqualTo(0) + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = 2 * TIMEOUT) + public void queryDocumentsWithPageSize() { + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + int pageSize = 3; + options.maxItemCount(pageSize); + options.maxDegreeOfParallelism(-1); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments; + assertThat(expectedDocs).isNotEmpty(); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .exactlyContainsInAnyOrder(expectedDocs + .stream() + .map(d -> d.resourceId()) + .collect(Collectors.toList())) + .numberOfPagesIsGreaterThanOrEqualTo((expectedDocs.size() + 1) / 3) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0) + .pageSizeIsLessThanOrEqualTo(pageSize) + .build()) + .build(); + validateQuerySuccess(queryObservable, validator, 2 * subscriberValidationTimeout); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySyntax() { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .notNullActivityId() + .build(); + validateQueryFailure(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void crossPartitionQueryNotEnabled() { + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .build(); + validateQueryFailure(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = 2 * TIMEOUT) + public void partitionKeyRangeId() { + int sum = 0; + + for (String partitionKeyRangeId : + CosmosBridgeInternal.getAsyncDocumentClient(client).readPartitionKeyRanges(getCollectionLink(), null) + .flatMap(p -> Flux.fromIterable(p.results())) + .map(Resource::id).collectList().single().block()) { + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + partitionKeyRangeIdInternal(options, partitionKeyRangeId); + int queryResultCount = createdCollection.queryItems(query, options) + .flatMap(p -> Flux.fromIterable(p.results())) + .collectList().block().size(); + + sum += queryResultCount; + } + + assertThat(sum).isEqualTo(createdDocuments.size()); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void compositeContinuationTokenRoundTrip() throws Exception { + { + // Positive + CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken("asdf", + new Range("A", "D", false, true)); + String serialized = compositeContinuationToken.toString(); + ValueHolder outCompositeContinuationToken = new ValueHolder(); + boolean succeeed = CompositeContinuationToken.tryParse(serialized, outCompositeContinuationToken); + assertThat(succeeed).isTrue(); + CompositeContinuationToken deserialized = outCompositeContinuationToken.v; + String token = deserialized.getToken(); + Range range = deserialized.getRange(); + assertThat(token).isEqualTo("asdf"); + assertThat(range.getMin()).isEqualTo("A"); + assertThat(range.getMax()).isEqualTo("D"); + assertThat(range.isMinInclusive()).isEqualTo(false); + assertThat(range.isMaxInclusive()).isEqualTo(true); + } + + { + // Negative + ValueHolder outCompositeContinuationToken = new ValueHolder(); + boolean succeeed = CompositeContinuationToken.tryParse("{\"property\" : \"not a valid composite continuation token\"}", outCompositeContinuationToken); + assertThat(succeeed).isFalse(); + } + + { + // Negative - GATEWAY composite continuation token + ValueHolder outCompositeContinuationToken = new ValueHolder(); + boolean succeeed = CompositeContinuationToken.tryParse("{\"token\":\"-RID:tZFQAImzNLQLAAAAAAAAAA==#RT:1#TRC:10\",\"range\":{\"min\":\"\",\"max\":\"FF\"}}", outCompositeContinuationToken); + assertThat(succeeed).isFalse(); + } + } + + // TODO: This test has been timing out on build, related work item - https://msdata.visualstudio.com/CosmosDB/_workitems/edit/402438/ + @Test(groups = { "non-emulator" }, timeOut = TIMEOUT * 10) + public void queryDocumentsWithCompositeContinuationTokens() throws Exception { + String query = "SELECT * FROM c"; + + // Get Expected + List expectedDocs = new ArrayList<>(createdDocuments); + assertThat(expectedDocs).isNotEmpty(); + + this.queryWithContinuationTokensAndPageSizes(query, new int[] {1, 10, 100}, expectedDocs); + } + + @BeforeClass(groups = { "simple", "non-emulator" }, timeOut = 2 * SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + List docDefList = new ArrayList<>(); + for(int i = 0; i < 13; i++) { + docDefList.add(getDocumentDefinition(i)); + } + + for(int i = 0; i < 21; i++) { + docDefList.add(getDocumentDefinition(99)); + } + + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple", "non-emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosItemProperties getDocumentDefinition(int cnt) { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"prop\" : %d, " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, cnt, uuid)); + return doc; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, enabled = false) + public void invalidQuerySytax() throws Exception { + + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FailureValidator validator = new FailureValidator.Builder().instanceOf(CosmosClientException.class) + .statusCode(400).notNullActivityId().build(); + validateQueryFailure(queryObservable, validator); + } + + public CosmosItemProperties createDocument(CosmosContainer cosmosContainer, int cnt) throws CosmosClientException { + + CosmosItemProperties docDefinition = getDocumentDefinition(cnt); + + return cosmosContainer.createItem(docDefinition).block().properties(); + } + + private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, List expectedDocs) { + for (int pageSize : pageSizes) { + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + List actualIds = new ArrayList(); + for (CosmosItemProperties document : receivedDocuments) { + actualIds.add(document.resourceId()); + } + + List expectedIds = new ArrayList(); + for (CosmosItemProperties document : expectedDocs) { + expectedIds.add(document.resourceId()); + } + + assertThat(actualIds).containsOnlyElementsOf(expectedIds); + } + } + + private List queryWithContinuationTokens(String query, int pageSize) { + String requestContinuation = null; + List continuationTokens = new ArrayList(); + List receivedDocuments = new ArrayList(); + do { + FeedOptions options = new FeedOptions(); + options.maxItemCount(pageSize); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(2); + options.requestContinuation(requestContinuation); + Flux> queryObservable = createdCollection.queryItems(query, options); + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); + requestContinuation = firstPage.continuationToken(); + receivedDocuments.addAll(firstPage.results()); + continuationTokens.add(requestContinuation); + } while (requestContinuation != null); + + return receivedDocuments; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParsingEnvTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParsingEnvTest.java new file mode 100644 index 0000000000000..91828d54395d4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ParsingEnvTest.java @@ -0,0 +1,76 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ParsingEnvTest { + + @Test(groups = "unit") + public void parseDesiredConsistencies() { + assertThat(TestSuiteBase.parseDesiredConsistencies("[ \"BoundedStaleness\" ]")).containsExactly(ConsistencyLevel.BOUNDED_STALENESS); + assertThat(TestSuiteBase.parseDesiredConsistencies("[ \"Session\" , \"Strong\" ]")).containsExactly( + ConsistencyLevel.SESSION, ConsistencyLevel.STRONG); + } + + @Test(groups = "unit") + public void parseDesiredConsistencies_null() { + assertThat(TestSuiteBase.parseDesiredConsistencies(null)).isNull(); + } + + @Test(groups = "unit") + public void lowerConsistencies() { + assertThat(TestSuiteBase.allEqualOrLowerConsistencies(ConsistencyLevel.SESSION)) + .containsExactly(ConsistencyLevel.SESSION, ConsistencyLevel.CONSISTENT_PREFIX, ConsistencyLevel.EVENTUAL); + } + + @Test(groups = "unit") + public void parseAccountConsistency() { + assertThat(TestSuiteBase.parseConsistency("Strong")).isEqualTo(ConsistencyLevel.STRONG); + assertThat(TestSuiteBase.parseConsistency("Session")).isEqualTo(ConsistencyLevel.SESSION); + assertThat(TestSuiteBase.parseConsistency("BoundedStaleness")).isEqualTo(ConsistencyLevel.BOUNDED_STALENESS); + assertThat(TestSuiteBase.parseConsistency("ConsistentPrefix")).isEqualTo(ConsistencyLevel.CONSISTENT_PREFIX); + assertThat(TestSuiteBase.parseConsistency("Eventual")).isEqualTo(ConsistencyLevel.EVENTUAL); + } + + @Test(groups = "unit") + public void parsePreferredLocation() { + assertThat(TestSuiteBase.parsePreferredLocation("[ \"central us\" , \"central us2\" ]")) + .containsExactly("central us", "central us2"); + } + + @Test(groups = "unit") + public void parsePreferredLocation_null() { + assertThat(TestSuiteBase.parsePreferredLocation(null)).isNull(); + } + + @Test(groups = "unit") + public void protocols() { + assertThat(TestSuiteBase.parseProtocols("[ \"Tcp\" , \"Https\" ]")).containsExactly(Protocol.TCP, Protocol.HTTPS); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionCrudTest.java new file mode 100644 index 0000000000000..141de2536d86d --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionCrudTest.java @@ -0,0 +1,238 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosPermission; +import com.azure.data.cosmos.CosmosPermissionResponse; +import com.azure.data.cosmos.CosmosPermissionProperties; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosUser; +import com.azure.data.cosmos.CosmosUserProperties; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.internal.FailureValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +//TODO: change to use external TestSuiteBase +public class PermissionCrudTest extends TestSuiteBase { + + private CosmosDatabase createdDatabase; + private CosmosUser createdUser; + private final String databaseId = CosmosDatabaseForTest.generateId(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public PermissionCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createPermission() throws Exception { + + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + //create permission + CosmosPermissionProperties permissionSettings = new CosmosPermissionProperties() + .id(UUID.randomUUID().toString()) + .permissionMode(PermissionMode.READ) + .resourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc="); + + Mono createObservable = createdUser.createPermission(permissionSettings, null); + + // validate permission creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(permissionSettings.id()) + .withPermissionMode(PermissionMode.READ) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readPermission() throws Exception { + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + // create permission + CosmosPermissionProperties permissionSettings = new CosmosPermissionProperties() + .id(UUID.randomUUID().toString()) + .permissionMode(PermissionMode.READ) + .resourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc="); + CosmosPermissionResponse readBackPermission = createdUser.createPermission(permissionSettings, null) + .block(); + + // read Permission + Mono readObservable = readBackPermission.permission().read(null); + + // validate permission read + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(permissionSettings.id()) + .withPermissionMode(PermissionMode.READ) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void deletePermission() throws Exception { + + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + // create permission + CosmosPermissionProperties permissionSettings = new CosmosPermissionProperties() + .id(UUID.randomUUID().toString()) + .permissionMode(PermissionMode.READ) + .resourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc="); + CosmosPermissionResponse readBackPermission = createdUser.createPermission(permissionSettings, null) + .block(); + // delete + Mono deleteObservable = readBackPermission.permission() + .delete(null); + + // validate delete permission + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource() + .build(); + validateSuccess(deleteObservable, validator); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + + // attempt to read the permission which was deleted + Mono readObservable = readBackPermission.permission() + .read( null); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void upsertPermission() throws Exception { + + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + // create permission + CosmosPermissionProperties permissionSettings = new CosmosPermissionProperties() + .id(UUID.randomUUID().toString()) + .permissionMode(PermissionMode.READ) + .resourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc="); + CosmosPermissionResponse readBackPermissionResponse = createdUser.createPermission(permissionSettings, null) + .block(); + CosmosPermissionProperties readBackPermission = readBackPermissionResponse.properties(); + // read Permission + Mono readObservable = readBackPermissionResponse.permission() + .read( null); + + // validate permission creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(readBackPermission.id()) + .withPermissionMode(PermissionMode.READ) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(readObservable, validator); + + //update permission + readBackPermission = readBackPermission.permissionMode(PermissionMode.ALL); + + Mono updateObservable = createdUser.upsertPermission(readBackPermission, null); + + // validate permission update + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() + .withId(readBackPermission.id()) + .withPermissionMode(PermissionMode.ALL) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(updateObservable, validatorForUpdate); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void replacePermission() throws Exception { + + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + String id = UUID.randomUUID().toString(); + // create permission + CosmosPermissionProperties permissionSettings = new CosmosPermissionProperties() + .id(id) + .permissionMode(PermissionMode.READ) + .resourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc="); + CosmosPermissionResponse readBackPermissionResponse = createdUser.createPermission(permissionSettings, null) + .block(); + // read Permission + Mono readObservable = readBackPermissionResponse.permission() + .read(null); + + // validate permission creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(readBackPermissionResponse.permission().id()) + .withPermissionMode(PermissionMode.READ) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(readObservable, validator); + + //update permission + CosmosPermissionProperties readBackPermission = readBackPermissionResponse.properties(); + readBackPermission = readBackPermission.permissionMode(PermissionMode.ALL); + + CosmosPermission cosmosPermission = createdUser.getPermission(id); + Mono updateObservable = readBackPermissionResponse.permission() + .replace(readBackPermission, null); + + // validate permission replace + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() + .withId(readBackPermission.id()) + .withPermissionMode(PermissionMode.ALL) + .withPermissionResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgTc=") + .notNullEtag() + .build(); + validateSuccess(updateObservable, validatorForUpdate); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosUserProperties getUserDefinition() { + return new CosmosUserProperties() + .id(UUID.randomUUID().toString()); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionQueryTest.java new file mode 100644 index 0000000000000..bf24efffd94ab --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/PermissionQueryTest.java @@ -0,0 +1,198 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +//TODO: change to use external TestSuiteBase +public class PermissionQueryTest extends TestSuiteBase { + + public final String databaseId = DatabaseForTest.generateId(); + + private Database createdDatabase; + private User createdUser; + private List createdPermissions = new ArrayList<>(); + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public PermissionQueryTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryWithFilter() throws Exception { + + String filterId = createdPermissions.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + Flux> queryObservable = client + .queryPermissions(getUserLink(), query, options); + + List expectedDocs = createdPermissions.stream().filter(sp -> filterId.equals(sp.id()) ).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator, TIMEOUT); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void query_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = client + .queryPermissions(getUserLink(), query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAll() throws Exception { + + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(3); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = client + .queryPermissions(getUserLink(), query, options); + + int expectedPageSize = (createdPermissions.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .exactlyContainsInAnyOrder(createdPermissions + .stream() + .map(d -> d.resourceId()) + .collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySytax() throws Exception { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = client + .queryPermissions(getUserLink(), query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .notNullActivityId() + .build(); + validateQueryFailure(queryObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + Database d = new Database(); + d.id(databaseId); + createdDatabase = createDatabase(client, d); + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + for(int i = 0; i < 5; i++) { + createdPermissions.add(createPermissions(client, i)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, createdDatabase); + safeClose(client); + } + + private static User getUserDefinition() { + User user = new User(); + user.id(UUID.randomUUID().toString()); + return user; + } + + public Permission createPermissions(AsyncDocumentClient client, int index) { + DocumentCollection collection = new DocumentCollection(); + collection.id(UUID.randomUUID().toString()); + + Permission permission = new Permission(); + permission.id(UUID.randomUUID().toString()); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgT" + Integer.toString(index) + "="); + + return client.createPermission(getUserLink(), permission, null).single().block().getResource(); + } + + private String getUserLink() { + return "dbs/" + getDatabaseId() + "/users/" + getUserId(); + } + + private String getDatabaseId() { + return createdDatabase.id(); + } + + private String getUserId() { + return createdUser.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ProxyHostTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ProxyHostTest.java new file mode 100644 index 0000000000000..e7a7315141be9 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ProxyHostTest.java @@ -0,0 +1,184 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.internal.TestConfigurations; +import com.azure.data.cosmos.rx.proxy.HttpProxyServer; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.WriterAppender; +import org.testng.annotations.AfterClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * This class help to test proxy host feature scenarios where user can provide proxy + * host server during AsyncDocumentClient initialization and all its request will + * go through that particular host. + * + */ +public class ProxyHostTest extends TestSuiteBase { + + private static CosmosDatabase createdDatabase; + private static CosmosContainer createdCollection; + + private CosmosClient client; + private final String PROXY_HOST = "localhost"; + private final int PROXY_PORT = 8080; + private HttpProxyServer httpProxyServer; + + public ProxyHostTest() { + super(createGatewayRxDocumentClient()); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + httpProxyServer = new HttpProxyServer(); + httpProxyServer.start(); + // wait for proxy server to be ready + TimeUnit.SECONDS.sleep(1); + } + + /** + * This test will try to create document via http proxy server and validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithValidHttpProxy() throws Exception { + CosmosClient clientWithRightProxy = null; + try { + ConnectionPolicy connectionPolicy =new ConnectionPolicy(); + connectionPolicy.proxy(PROXY_HOST, PROXY_PORT); + clientWithRightProxy = CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.SESSION).build(); + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = clientWithRightProxy.getDatabase(createdDatabase.id()).getContainer(createdCollection.id()) + .createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()) + .build(); + validateSuccess(createObservable, validator); + } finally { + safeClose(clientWithRightProxy); + } + } + + /** + * This test will try to create document via http proxy server with netty wire logging and validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createDocumentWithValidHttpProxyWithNettyWireLogging() throws Exception { + LogManager.getRootLogger().setLevel(Level.INFO); + LogManager.getLogger(LogLevelTest.NETWORK_LOGGING_CATEGORY).setLevel(Level.TRACE); + CosmosClient clientWithRightProxy = null; + try { + StringWriter consoleWriter = new StringWriter(); + WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); + Logger.getLogger(LogLevelTest.NETWORK_LOGGING_CATEGORY).addAppender(appender); + + ConnectionPolicy connectionPolicy =new ConnectionPolicy(); + connectionPolicy.proxy(PROXY_HOST, PROXY_PORT); + clientWithRightProxy = CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.SESSION).build(); + CosmosItemProperties docDefinition = getDocumentDefinition(); + Mono createObservable = clientWithRightProxy.getDatabase(createdDatabase.id()).getContainer(createdCollection.id()) + .createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.id()) + .build(); + validateSuccess(createObservable, validator); + + assertThat(consoleWriter.toString()).contains(LogLevelTest.LOG_PATTERN_1); + assertThat(consoleWriter.toString()).contains(LogLevelTest.LOG_PATTERN_2); + assertThat(consoleWriter.toString()).contains(LogLevelTest.LOG_PATTERN_3); + } finally { + safeClose(clientWithRightProxy); + } + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() throws Exception { + safeClose(client); + httpProxyServer.shutDown(); + // wait for proxy server to be shutdown + TimeUnit.SECONDS.sleep(1); + + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } + + @BeforeMethod(groups = { "simple"}) + public void beforeMethod() { + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } + + @AfterMethod(groups = { "simple" }) + public void afterMethod(Method method) { + LogManager.resetConfiguration(); + PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedCollectionsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedCollectionsTest.java new file mode 100644 index 0000000000000..0cba3b0535bca --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedCollectionsTest.java @@ -0,0 +1,112 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedCollectionsTest extends TestSuiteBase { + + protected static final int FEED_TIMEOUT = 60000; + protected static final int SETUP_TIMEOUT = 60000; + protected static final int SHUTDOWN_TIMEOUT = 20000; + + public final String databaseId = CosmosDatabaseForTest.generateId(); + + private CosmosDatabase createdDatabase; + private List createdCollections = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public ReadFeedCollectionsTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readCollections() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdDatabase.readAllContainers(options); + + int expectedPageSize = (createdCollections.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdCollections.size()) + .exactlyContainsInAnyOrder(createdCollections.stream().map(d -> d.read().block().properties().resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + + for(int i = 0; i < 3; i++) { + createdCollections.add(createCollections(createdDatabase)); + } + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } + + public CosmosContainer createCollections(CosmosDatabase database) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + CosmosContainerProperties collection = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + return database.createContainer(collection, new CosmosContainerRequestOptions()).block().container(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDatabasesTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDatabasesTest.java new file mode 100644 index 0000000000000..3aebc3b916975 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDatabasesTest.java @@ -0,0 +1,103 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabaseProperties; +import com.azure.data.cosmos.CosmosDatabaseRequestOptions; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedDatabasesTest extends TestSuiteBase { + + private List createdDatabases = new ArrayList<>(); + private List allDatabases = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public ReadFeedDatabasesTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readDatabases() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = client.readAllDatabases(options); + + int expectedPageSize = (allDatabases.size() + options.maxItemCount() - 1) / options.maxItemCount(); + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(allDatabases.size()) + .exactlyContainsInAnyOrder(allDatabases.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws URISyntaxException { + client = clientBuilder().build(); + allDatabases = client.readAllDatabases(null) + .map(frp -> frp.results()) + .collectList() + .map(list -> list.stream().flatMap(x -> x.stream()).collect(Collectors.toList())) + .block(); + for(int i = 0; i < 5; i++) { + createdDatabases.add(createDatabase(client)); + } + allDatabases.addAll(createdDatabases); + } + + public CosmosDatabaseProperties createDatabase(CosmosClient client) { + CosmosDatabaseProperties db = new CosmosDatabaseProperties(UUID.randomUUID().toString()); + return client.createDatabase(db, new CosmosDatabaseRequestOptions()).block().properties(); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + for (int i = 0; i < 5; i ++) { + safeDeleteDatabase(client.getDatabase(createdDatabases.get(i).id())); + } + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDocumentsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDocumentsTest.java new file mode 100644 index 0000000000000..eee99f3003f1c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedDocumentsTest.java @@ -0,0 +1,138 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedDocumentsTest extends TestSuiteBase { + + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedDocumentsTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readDocuments() { + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(2); + + Flux> feedObservable = createdCollection.readAllItems(options); + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdDocuments.size()) + .numberOfPagesIsGreaterThanOrEqualTo(1) + .exactlyContainsInAnyOrder(createdDocuments.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0) + .pageSizeIsLessThanOrEqualTo(options.maxItemCount()) + .build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readDocuments_withoutEnableCrossPartitionQuery() { + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdCollection.readAllItems(options); + FailureValidator validator = FailureValidator.builder().instanceOf(CosmosClientException.class) + .statusCode(400) + .errorMessageContains("Cross partition query is required but disabled." + + " Please set x-ms-documentdb-query-enablecrosspartition to true," + + " specify x-ms-documentdb-partitionkey," + + " or revise your query to avoid this exception.") + .build(); + validateQueryFailure(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT, alwaysRun = true) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + List docDefList = new ArrayList<>(); + + for(int i = 0; i < 100; i++) { + docDefList.add(getDocumentDefinition()); + } + + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + public String getCollectionLink() { + return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId(); + } + + private String getCollectionId() { + return createdCollection.id(); + } + + private String getDatabaseId() { + return createdDatabase.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedExceptionHandlingTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedExceptionHandlingTest.java new file mode 100644 index 0000000000000..623bbd1090ffa --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedExceptionHandlingTest.java @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabaseProperties; +import com.azure.data.cosmos.FeedResponse; +import io.reactivex.subscribers.TestSubscriber; +import org.mockito.Mockito; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ReadFeedExceptionHandlingTest extends TestSuiteBase { + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedExceptionHandlingTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readFeedException() throws Exception { + + ArrayList dbs = new ArrayList(); + dbs.add(new CosmosDatabaseProperties("db1")); + dbs.add(new CosmosDatabaseProperties("db2")); + + ArrayList> frps = new ArrayList>(); + frps.add(BridgeInternal.createFeedResponse(dbs, null)); + frps.add(BridgeInternal.createFeedResponse(dbs, null)); + + Flux> response = Flux.merge(Flux.fromIterable(frps)) + .mergeWith(Flux.error(BridgeInternal.createCosmosClientException(0))) + .mergeWith(Flux.fromIterable(frps)); + + final CosmosClient mockClient = Mockito.spy(client); + Mockito.when(mockClient.readAllDatabases(null)).thenReturn(response); + TestSubscriber> subscriber = new TestSubscriber>(); + mockClient.readAllDatabases(null).subscribe(subscriber); + assertThat(subscriber.valueCount()).isEqualTo(2); + assertThat(subscriber.assertNotComplete()); + assertThat(subscriber.assertTerminated()); + assertThat(subscriber.errorCount()).isEqualTo(1); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(this.client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedOffersTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedOffersTest.java new file mode 100644 index 0000000000000..69fd0cd1a5028 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedOffersTest.java @@ -0,0 +1,123 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +//TODO: change to use external TestSuiteBase +public class ReadFeedOffersTest extends TestSuiteBase { + + protected static final int FEED_TIMEOUT = 60000; + protected static final int SETUP_TIMEOUT = 60000; + protected static final int SHUTDOWN_TIMEOUT = 20000; + + public final String databaseId = DatabaseForTest.generateId(); + + private Database createdDatabase; + private List allOffers = new ArrayList<>(); + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public ReadFeedOffersTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = FEED_TIMEOUT) + public void readOffers() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = client.readOffers(options); + + int expectedPageSize = (allOffers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(allOffers.size()) + .exactlyContainsInAnyOrder(allOffers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + + for(int i = 0; i < 3; i++) { + createCollections(client); + } + + allOffers = client.readOffers(null) + .map(FeedResponse::results) + .collectList() + .map(list -> list.stream().flatMap(Collection::stream).collect(Collectors.toList())) + .single() + .block(); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, createdDatabase); + safeClose(client); + } + + public DocumentCollection createCollections(AsyncDocumentClient client) { + DocumentCollection collection = new DocumentCollection(); + collection.id(UUID.randomUUID().toString()); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + collection.setPartitionKey(partitionKeyDef); + + return client.createCollection(getDatabaseLink(), collection, null).single().block().getResource(); + } + + private String getDatabaseLink() { + return "dbs/" + createdDatabase.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPermissionsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPermissionsTest.java new file mode 100644 index 0000000000000..7581457b333eb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPermissionsTest.java @@ -0,0 +1,126 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +//TODO: change to use external TestSuiteBase +public class ReadFeedPermissionsTest extends TestSuiteBase { + + public final String databaseId = DatabaseForTest.generateId(); + + private Database createdDatabase; + private User createdUser; + private List createdPermissions = new ArrayList<>(); + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public ReadFeedPermissionsTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readPermissions() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = client.readPermissions(getUserLink(), options); + + int expectedPageSize = (createdPermissions.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdPermissions.size()) + .numberOfPages(expectedPageSize) + .exactlyContainsInAnyOrder(createdPermissions.stream().map(Resource::resourceId).collect(Collectors.toList())) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + Database d = new Database(); + d.id(databaseId); + createdDatabase = createDatabase(client, d); + createdUser = safeCreateUser(client, createdDatabase.id(), getUserDefinition()); + + for(int i = 0; i < 5; i++) { + createdPermissions.add(createPermissions(client, i)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, databaseId); + safeClose(client); + } + + private static User getUserDefinition() { + User user = new User(); + user.id(UUID.randomUUID().toString()); + return user; + } + + public Permission createPermissions(AsyncDocumentClient client, int index) { + Permission permission = new Permission(); + permission.id(UUID.randomUUID().toString()); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink("dbs/AQAAAA==/colls/AQAAAJ0fgT" + Integer.toString(index) + "="); + return client.createPermission(getUserLink(), permission, null).single().block().getResource(); + } + + private String getUserLink() { + return "dbs/" + getDatabaseId() + "/users/" + getUserId(); + } + + private String getDatabaseId() { + return createdDatabase.id(); + } + + private String getUserId() { + return createdUser.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPkrTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPkrTests.java new file mode 100644 index 0000000000000..0b5150755c89d --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedPkrTests.java @@ -0,0 +1,87 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.PartitionKeyRange; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + + +public class ReadFeedPkrTests extends TestSuiteBase { + + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedPkrTests(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = FEED_TIMEOUT) + public void readPartitionKeyRanges() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = client.readPartitionKeyRanges(getCollectionLink(), options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(1) + .numberOfPages(1) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = CosmosBridgeInternal.getAsyncDocumentClient(clientBuilder().build()); + createdDatabase = getSharedCosmosDatabase(clientBuilder().build()); + createdCollection = createCollection(createdDatabase, + getCollectionDefinition(), + new CosmosContainerRequestOptions()); + } + + @AfterClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteCollection(createdCollection); + client.close(); + } + + private String getCollectionLink() { + return "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedStoredProceduresTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedStoredProceduresTest.java new file mode 100644 index 0000000000000..144e5c6e7c1c0 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedStoredProceduresTest.java @@ -0,0 +1,104 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosStoredProcedureRequestOptions; +import com.azure.data.cosmos.CosmosStoredProcedureProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedStoredProceduresTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private List createdStoredProcedures = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedStoredProceduresTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readStoredProcedures() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdCollection.getScripts() + .readAllStoredProcedures(options); + + int expectedPageSize = (createdStoredProcedures.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdStoredProcedures.size()) + .exactlyContainsInAnyOrder( + createdStoredProcedures.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for (int i = 0; i < 5; i++) { + createdStoredProcedures.add(createStoredProcedures(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + public CosmosStoredProcedureProperties createStoredProcedures(CosmosContainer cosmosContainer) { + CosmosStoredProcedureProperties sproc = new CosmosStoredProcedureProperties(); + sproc.id(UUID.randomUUID().toString()); + sproc.body("function() {var x = 10;}"); + return cosmosContainer.getScripts().createStoredProcedure(sproc, new CosmosStoredProcedureRequestOptions()) + .block().properties(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedTriggersTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedTriggersTest.java new file mode 100644 index 0000000000000..18d106d58135c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedTriggersTest.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosTriggerProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedTriggersTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private List createdTriggers = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedTriggersTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readTriggers() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdCollection.getScripts().readAllTriggers(options); + + int expectedPageSize = (createdTriggers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdTriggers.size()) + .exactlyContainsInAnyOrder( + createdTriggers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for (int i = 0; i < 5; i++) { + this.createdTriggers.add(this.createTriggers(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + public CosmosTriggerProperties createTriggers(CosmosContainer cosmosContainer) { + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + return cosmosContainer.getScripts().createTrigger(trigger).block().properties(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUdfsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUdfsTest.java new file mode 100644 index 0000000000000..687ab8268640e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUdfsTest.java @@ -0,0 +1,118 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosUserDefinedFunctionProperties; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedUdfsTest extends TestSuiteBase { + + private Database createdDatabase; + private CosmosContainer createdCollection; + private List createdUserDefinedFunctions = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public ReadFeedUdfsTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readUserDefinedFunctions() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdCollection.getScripts() + .readAllUserDefinedFunctions(options); + + int expectedPageSize = (createdUserDefinedFunctions.size() + options.maxItemCount() - 1) + / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdUserDefinedFunctions.size()) + .exactlyContainsInAnyOrder( + createdUserDefinedFunctions.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for (int i = 0; i < 5; i++) { + createdUserDefinedFunctions.add(createUserDefinedFunctions(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + public CosmosUserDefinedFunctionProperties createUserDefinedFunctions(CosmosContainer cosmosContainer) { + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + return cosmosContainer.getScripts().createUserDefinedFunction(udf).block() + .properties(); + } + + private String getCollectionLink() { + return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId(); + } + + private String getCollectionId() { + return createdCollection.id(); + } + + private String getDatabaseId() { + return createdDatabase.id(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUsersTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUsersTest.java new file mode 100644 index 0000000000000..47331a6725f96 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ReadFeedUsersTest.java @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosUserProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class ReadFeedUsersTest extends TestSuiteBase { + + public final String databaseId = CosmosDatabaseForTest.generateId(); + private CosmosDatabase createdDatabase; + + private CosmosClient client; + private List createdUsers = new ArrayList<>(); + + @Factory(dataProvider = "clientBuilders") + public ReadFeedUsersTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readUsers() throws Exception { + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + + Flux> feedObservable = createdDatabase.readAllUsers(options); + + int expectedPageSize = (createdUsers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdUsers.size()) + .exactlyContainsInAnyOrder(createdUsers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + + for(int i = 0; i < 5; i++) { + createdUsers.add(createUsers(createdDatabase)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } + + public CosmosUserProperties createUsers(CosmosDatabase cosmosDatabase) { + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + return cosmosDatabase.createUser(user).block().properties(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ResourceTokenTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ResourceTokenTest.java new file mode 100644 index 0000000000000..388b03cd7ca3b --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/ResourceTokenTest.java @@ -0,0 +1,542 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * This class try to test different scenario related to fetching various + * resources from resource token directly or via permission feed . + * + */ + +// TODO: change to use external TestSuiteBase +public class ResourceTokenTest extends TestSuiteBase { + public final String databaseId = DatabaseForTest.generateId(); + + private Database createdDatabase; + private DocumentCollection createdCollection; + private DocumentCollection createdCollectionWithPartitionKey; + private Document createdDocument; + private Document createdDocumentWithPartitionKey; + private Document createdDocumentWithPartitionKey2; + private User createdUser; + private Permission createdCollPermission; + private Permission createdCollPermissionWithName; + private Permission createdDocPermission; + private Permission createdDocPermissionWithName; + private Permission createdDocPermissionWithPartitionKey; + private Permission createdDocPermissionWithPartitionKeyWithName; + private Permission createdDocPermissionWithPartitionKey2; + private Permission createdDocPermissionWithPartitionKey2WithName; + private Permission createdColPermissionWithPartitionKey; + private Permission createdColPermissionWithPartitionKeyWithName; + private Permission createdColPermissionWithPartitionKey2; + private Permission createdColPermissionWithPartitionKey2WithName; + + private AsyncDocumentClient client; + + // ALL static string used in below test cases + private final static String DOCUMENT_DEFINITION = "{ 'id': 'doc%d', 'counter': '%d'}"; + private final static String DOCUMENT_DEFINITION_WITH_PERMISSION_KEY = "{ " + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + "}"; + private final static String PARTITION_KEY_PATH_1 = "/mypk"; + private final static String PARTITION_KEY_PATH_2 = "/mypk2"; + + private static final String PARTITION_KEY_VALUE = "1"; + private static final String PARTITION_KEY_VALUE_2 = "2"; + private static final String PERMISSION_DEFINITION = "{" + " 'id': 'PermissionForDocWithPartitionKey'," + + " 'permissionMode': 'read'," + " 'resource': '%s'," + " 'resourcePartitionKey': ['%s']" + "}"; + private static final String COLLECTION_PERMISSION_DEFINITION = "{" + " 'id': 'PermissionForColWithPartitionKey'," + + " 'permissionMode': 'read'," + " 'resource': '%s'," + " 'resourcePartitionKey': ['%s']" + "}"; + private static final String USER_NAME = "TestUser"; + private static final String PERMISSION_FOR_COLL = "PermissionForColl"; + private static final String PERMISSION_FOR_COLL_WITH_NAME = "PermissionForCollWithName"; + private static final String PERMISSION_FOR_DOC = "PermissionForDoc"; + private static final String PERMISSION_FOR_DOC_WITH_NAME = "PermissionForDocWithName"; + + @Factory(dataProvider = "clientBuilders") + public ResourceTokenTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + Database d = new Database(); + d.id(databaseId); + createdDatabase = createDatabase(client, d); + // CREATE collection + createdCollection = createCollection(client, createdDatabase.id(), getCollectionDefinitionWithPartitionKey(PARTITION_KEY_PATH_2)); + // CREATE document + createdDocument = createDocument(client, createdDatabase.id(),createdCollection.id(), getDocument()); + // CREATE collection with partition key + createdCollectionWithPartitionKey = createCollection(client, createdDatabase.id(), getCollectionDefinitionWithPartitionKey(PARTITION_KEY_PATH_1)); + // CREATE document with partition key + createdDocumentWithPartitionKey = createDocument(client, createdDatabase.id(), createdCollectionWithPartitionKey.id(), + getDocumentDefinitionWithPartitionKey()); + // CREATE second document with partition key + createdDocumentWithPartitionKey2 = createDocument(client, createdDatabase.id(),createdCollectionWithPartitionKey.id(), + getDocumentDefinitionWithPartitionKey2()); + // CREATE user + createdUser = createUser(client, createdDatabase.id(), getUserDefinition()); + // CREATE permission for collection + createdCollPermission = client.createPermission(getUserLink(), getCollPermission(), null).single().block() + .getResource(); + createdCollPermissionWithName = client.createPermission(getUserLink(), getCollPermissionWithName(), null).single().block() + .getResource(); + // CREATE permission for document + createdDocPermission = client.createPermission(getUserLink(), getDocPermission(), null).single().block() + .getResource(); + createdDocPermissionWithName = client.createPermission(getUserLink(), getDocPermissionWithName(), null).single().block() + .getResource(); + // CREATE permission for document with partition key + createdDocPermissionWithPartitionKey = client + .createPermission(getUserLink(), getDocPermissionWithPartitionKey(), null).single().block() + .getResource(); + createdDocPermissionWithPartitionKeyWithName = client + .createPermission(getUserLink(), getDocPermissionWithPartitionKeyWithName(), null).single().block() + .getResource(); + // CREATE permission for document with partition key 2 + createdDocPermissionWithPartitionKey2 = client + .createPermission(getUserLink(), getDocPermissionWithPartitionKey2(), null).single().block() + .getResource(); + createdDocPermissionWithPartitionKey2WithName = client + .createPermission(getUserLink(), getDocPermissionWithPartitionKey2WithName(), null).single().block() + .getResource(); + // CREATE permission for collection with partition key + createdColPermissionWithPartitionKey = client + .createPermission(getUserLink(), getColPermissionWithPartitionKey(), null).single().block() + .getResource(); + createdColPermissionWithPartitionKeyWithName = client + .createPermission(getUserLink(), getColPermissionWithPartitionKeyWithName(), null).single().block() + .getResource(); + // CREATE permission for collection with partition key + createdColPermissionWithPartitionKey2 = client + .createPermission(getUserLink(), getColPermissionWithPartitionKey2(), null).single().block() + .getResource(); + createdColPermissionWithPartitionKey2WithName = client + .createPermission(getUserLink(), getColPermissionWithPartitionKey2WithName(), null).single().block() + .getResource(); + } + + @DataProvider(name = "collectionAndPermissionData") + public Object[][] collectionAndPermissionData() { + return new Object[][]{ + //This test will try to read collection from its own permission and validate it, both with request Id and name. + {createdCollection.selfLink(), createdCollPermission}, + {TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()), createdDocPermissionWithName}, + }; + } + + @DataProvider(name = "documentAndPermissionData") + public Object[][] documentAndPermissionData() { + return new Object[][]{ + //These tests will try to read document from its own permission and validate it, both with request Id and name. + {createdDocument.selfLink(), createdDocPermission, createdDocument.id(), null}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollection.id(), createdDocument.id()), createdDocPermissionWithName, createdDocument.id(), null}, + + //These tests will try to read document from its permission having partition key 1 and validate it, both with request Id and name. + {createdDocumentWithPartitionKey.selfLink(), createdDocPermissionWithPartitionKey, createdDocumentWithPartitionKey.id(), PARTITION_KEY_VALUE}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey.id()), createdDocPermissionWithPartitionKeyWithName + , createdDocumentWithPartitionKey.id(), PARTITION_KEY_VALUE}, + + //These tests will try to read document from its permission having partition key 2 and validate it, both with request Id and name. + {createdDocumentWithPartitionKey2.selfLink(), createdDocPermissionWithPartitionKey2, createdDocumentWithPartitionKey2.id(), PARTITION_KEY_VALUE_2}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey2.id()), + createdDocPermissionWithPartitionKey2WithName, createdDocumentWithPartitionKey2.id(), PARTITION_KEY_VALUE_2}, + + // These tests will try to read document from its parent collection permission and validate it, both with request Id and name. + {createdDocument.selfLink(), createdCollPermission, createdDocument.id(), null}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollection.id(), createdDocument.id()), createdCollPermissionWithName, createdDocument.id(), null}, + + //This test will try to read document from collection permission having partition key 1 and validate it, both with request Id and name. + {createdDocumentWithPartitionKey.selfLink(), createdColPermissionWithPartitionKey, createdDocumentWithPartitionKey.id(), PARTITION_KEY_VALUE}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey.id()), createdColPermissionWithPartitionKeyWithName, createdDocumentWithPartitionKey.id(), PARTITION_KEY_VALUE}, + + //This test will try to read document from collection permission having partition key 2 and validate it, both with request Id and name. + {createdDocumentWithPartitionKey2.selfLink(), createdColPermissionWithPartitionKey2, createdDocumentWithPartitionKey2.id(), PARTITION_KEY_VALUE_2}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey2.id()), createdColPermissionWithPartitionKey2WithName, createdDocumentWithPartitionKey2.id(), PARTITION_KEY_VALUE_2} + + }; + } + + @DataProvider(name = "documentAndPermissionDataForResourceNotFound") + public Object[][] documentAndPermissionDataForResourceNotFound() { + return new Object[][]{ + //This test will try to read document from its resource token directly and validate it. + {createdDocumentWithPartitionKey2.selfLink(), createdColPermissionWithPartitionKey, PARTITION_KEY_VALUE}, + //This test will try to read document from its parent collection resource token directly and validate it. + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey2.id()), + createdColPermissionWithPartitionKeyWithName, PARTITION_KEY_VALUE} + }; + } + + @DataProvider(name = "documentAndMultipleCollPermissionData") + public Object[][] documentAndMultipleCollPermissionData() { + return new Object[][]{ + //These tests will try to read document from partition 1 with two collection permissions having different partition keys and validate it, both with request Id and name. + {createdDocumentWithPartitionKey.selfLink(), createdColPermissionWithPartitionKey, createdColPermissionWithPartitionKey2, createdDocumentWithPartitionKey.id(), + PARTITION_KEY_VALUE}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey.id()), createdColPermissionWithPartitionKeyWithName + , createdColPermissionWithPartitionKey2WithName, createdDocumentWithPartitionKey.id(), PARTITION_KEY_VALUE}, + + //These tests will try to read document from partition 1 with two collection permissions having different partition keys and validate it, both with request Id and name. + {createdDocumentWithPartitionKey2.selfLink(), createdColPermissionWithPartitionKey, createdColPermissionWithPartitionKey2, createdDocumentWithPartitionKey2.id(), + PARTITION_KEY_VALUE_2}, + {TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey2.id()), createdColPermissionWithPartitionKeyWithName + , createdColPermissionWithPartitionKey2WithName, createdDocumentWithPartitionKey2.id(), PARTITION_KEY_VALUE_2} + }; + } + + @DataProvider(name = "resourceToken") + public Object[][] resourceToken() { + return new Object[][]{ + //This test will try to read document from its resource token directly and validate it. + {createdDocPermission.getToken()}, + //This test will try to read document from its parent collection resource token directly and validate it. + {createdCollPermission.getToken()} + }; + } + + /** + * This test will try to read collection from permission and validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, dataProvider = "collectionAndPermissionData", timeOut = TIMEOUT) + public void readCollectionFromPermissionFeed(String collectionUrl, Permission permission) throws Exception { + AsyncDocumentClient asyncClientResourceToken = null ; + try { + List permissionFeed = new ArrayList<>(); + permissionFeed.add(permission); + asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withPermissionFeed(permissionFeed).withConnectionPolicy(ConnectionPolicy.defaultPolicy()) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + Flux> readObservable = asyncClientResourceToken + .readCollection(collectionUrl, null); + + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(createdCollection.id()).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + /** + * This test will try to read document from permission and validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, dataProvider = "documentAndPermissionData", timeOut = TIMEOUT) + public void readDocumentFromPermissionFeed(String documentUrl, Permission permission, String documentId, String partitionKey) throws Exception { + AsyncDocumentClient asyncClientResourceToken = null; + try { + List permissionFeed = new ArrayList<>(); + permissionFeed.add(permission); + asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withPermissionFeed(permissionFeed).withConnectionPolicy(ConnectionPolicy.defaultPolicy()) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + RequestOptions options = new RequestOptions(); + if (StringUtils.isNotEmpty(partitionKey)) { + options.setPartitionKey(new PartitionKey((String)partitionKey)); + } else { + options.setPartitionKey(PartitionKey.None); + } + Flux> readObservable = asyncClientResourceToken + .readDocument(documentUrl, options); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(documentId).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + /** + * This test will try to read document from resource token directly and validate it. + * + * @throws Exception + */ + @Test(groups = { "simple" }, dataProvider = "resourceToken", timeOut = TIMEOUT) + public void readDocumentFromResouceToken(String resourceToken) throws Exception { + AsyncDocumentClient asyncClientResourceToken = null; + try { + asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(resourceToken) + .withConnectionPolicy(ConnectionPolicy.defaultPolicy()).withConsistencyLevel(ConsistencyLevel.SESSION) + .build(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + Flux> readObservable = asyncClientResourceToken + .readDocument(createdDocument.selfLink(), options); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(createdDocument.id()).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + /** + * This test will try to read document from multiple collection permissions having different keys and validate it. + * + * @throws Exception + */ + @Test(groups = {"simple"}, dataProvider = "documentAndMultipleCollPermissionData", timeOut = TIMEOUT) + public void readDocumentOfParKeyFromTwoCollPermissionWithDiffPartitionKeys(String documentUrl, Permission collPermission1, Permission collPermission2, String documentId, String partitionKey) throws Exception { + AsyncDocumentClient asyncClientResourceToken = null; + try { + List permissionFeed = new ArrayList<>(); + permissionFeed.add(collPermission1); + permissionFeed.add(collPermission2); + asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withPermissionFeed(permissionFeed).withConnectionPolicy(ConnectionPolicy.defaultPolicy()) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(partitionKey)); + Flux> readObservable = asyncClientResourceToken + .readDocument(documentUrl, options); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(documentId).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + /** + * This test will try to read document with wrong collection permission hence + * expecting resource not found failure. + * + * @throws Exception + */ + @Test(groups = { "simple" },dataProvider = "documentAndPermissionDataForResourceNotFound", timeOut = TIMEOUT) + public void readDocumentFromCollPermissionWithDiffPartitionKey_ResourceNotFound(String documentUrl, Permission permission, String partitionKey) throws Exception { + AsyncDocumentClient asyncClientResourceToken = null; + try { + List permissionFeed = new ArrayList<>(); + permissionFeed.add(permission); + asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) + .withPermissionFeed(permissionFeed).withConnectionPolicy(ConnectionPolicy.defaultPolicy()) + .withConsistencyLevel(ConsistencyLevel.SESSION).build(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(partitionKey)); + Flux> readObservable = asyncClientResourceToken + .readDocument(documentUrl, options); + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + /** + * This test will try to read document with collection permissions and passing wrong partitionkey + * in request options hence expecting exception. + * + * @throws Exception + */ + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readDocumentFromCollPermissionWithDiffPartitionKey_WithException() throws Exception { + AsyncDocumentClient asyncClientResourceToken = null; + try { + List permissionFeed = new ArrayList<>(); + permissionFeed.add(createdColPermissionWithPartitionKey); + asyncClientResourceToken = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(ConnectionPolicy.defaultPolicy()) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withPermissionFeed(permissionFeed) + .build(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey(PARTITION_KEY_VALUE_2)); + Flux> readObservable = asyncClientResourceToken + .readDocument(createdDocumentWithPartitionKey.selfLink(), options); + FailureValidator validator = new FailureValidator.Builder().resourceTokenNotFound().build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientResourceToken); + } + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(client, databaseId); + safeClose(client); + } + + private static User getUserDefinition() { + User user = new User(); + user.id(USER_NAME); + return user; + } + + private static Document getDocument() { + Document doc = new Document(String.format(DOCUMENT_DEFINITION, 1, 1)); + return doc; + } + + private Permission getCollPermission() { + Permission permission = new Permission(); + permission.id(PERMISSION_FOR_COLL); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink(createdCollection.selfLink()); + return permission; + } + + private Permission getCollPermissionWithName() { + Permission permission = new Permission(); + permission.id(PERMISSION_FOR_COLL_WITH_NAME); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink(TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id())); + return permission; + } + + private Permission getDocPermission() { + Permission permission = new Permission(); + permission.id(PERMISSION_FOR_DOC); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink(createdDocument.selfLink()); + return permission; + } + private Permission getDocPermissionWithName() { + Permission permission = new Permission(); + permission.id(PERMISSION_FOR_DOC_WITH_NAME); + permission.setPermissionMode(PermissionMode.READ); + permission.setResourceLink(TestUtils.getDocumentNameLink(createdDatabase.id(),createdCollection.id(),createdDocument.id())); + return permission; + } + + private Permission getDocPermissionWithPartitionKey() { + String permissionStr = String.format(PERMISSION_DEFINITION, createdDocumentWithPartitionKey.selfLink(), + PARTITION_KEY_VALUE); + Permission permission = new Permission(permissionStr); + return permission; + } + + private Permission getDocPermissionWithPartitionKeyWithName() { + String permissionStr = String.format(PERMISSION_DEFINITION, TestUtils.getDocumentNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id(), createdDocumentWithPartitionKey.id()), + PARTITION_KEY_VALUE); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForDocWithPartitionKeyWithName"); + return permission; + } + + private Permission getDocPermissionWithPartitionKey2() { + String permissionStr = String.format(PERMISSION_DEFINITION, createdDocumentWithPartitionKey2.selfLink(), + PARTITION_KEY_VALUE_2); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForDocWithPartitionKey2"); + return permission; + } + + private Permission getDocPermissionWithPartitionKey2WithName() { + String permissionStr = String.format(PERMISSION_DEFINITION, TestUtils.getDocumentNameLink(createdDatabase.id(),createdCollectionWithPartitionKey.id(),createdDocumentWithPartitionKey2.id()), + PARTITION_KEY_VALUE_2); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForDocWithPartitionKey2WithName"); + return permission; + } + + private Permission getColPermissionWithPartitionKey() { + String permissionStr = String.format(COLLECTION_PERMISSION_DEFINITION, createdCollectionWithPartitionKey.selfLink(), + PARTITION_KEY_VALUE); + Permission permission = new Permission(permissionStr); + return permission; + } + + private Permission getColPermissionWithPartitionKeyWithName() { + String permissionStr = String.format(COLLECTION_PERMISSION_DEFINITION, TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id()), + PARTITION_KEY_VALUE); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForColWithPartitionKeyWithName"); + return permission; + } + + private Permission getColPermissionWithPartitionKey2() { + String permissionStr = String.format(COLLECTION_PERMISSION_DEFINITION, createdCollectionWithPartitionKey.selfLink(), + PARTITION_KEY_VALUE_2); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForColWithPartitionKey2"); + return permission; + } + + private Permission getColPermissionWithPartitionKey2WithName() { + String permissionStr = String.format(COLLECTION_PERMISSION_DEFINITION, TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollectionWithPartitionKey.id()), + PARTITION_KEY_VALUE_2); + Permission permission = new Permission(permissionStr); + permission.id("PermissionForColWithPartitionKey2WithName"); + return permission; + } + + private String getUserLink() { + return createdUser.selfLink(); + } + + private Document getDocumentDefinitionWithPartitionKey() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format(DOCUMENT_DEFINITION_WITH_PERMISSION_KEY, uuid, PARTITION_KEY_VALUE)); + return doc; + } + private Document getDocumentDefinitionWithPartitionKey2() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format(DOCUMENT_DEFINITION_WITH_PERMISSION_KEY, uuid, PARTITION_KEY_VALUE_2)); + return doc; + } + + private DocumentCollection getCollectionDefinitionWithPartitionKey(String pkDefPath) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add(pkDefPath); + partitionKeyDef.paths(paths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.id(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SimpleSerializationTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SimpleSerializationTest.java new file mode 100644 index 0000000000000..613568e747a86 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SimpleSerializationTest.java @@ -0,0 +1,101 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.apache.commons.lang3.NotImplementedException; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SimpleSerializationTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private CosmosClient client; + + private static class TestObject { + public static class BadSerializer extends JsonSerializer { + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) { + throw new NotImplementedException("bad"); + } + } + + @JsonProperty("mypk") + private String mypk; + + @JsonProperty("id") + private String id; + + @JsonProperty("prop") + @JsonSerialize(using = BadSerializer.class) + private String prop; + } + + @Factory(dataProvider = "clientBuildersWithDirect") + public SimpleSerializationTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = {"simple"}, timeOut = TIMEOUT) + public void createDocument() throws InterruptedException { + TestObject testObject = new TestObject(); + testObject.id = UUID.randomUUID().toString(); + testObject.mypk = UUID.randomUUID().toString(); + testObject.prop = UUID.randomUUID().toString(); + + try { + createdCollection.createItem(testObject); + Assert.fail(); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Can't serialize the object into the json string"); + assertThat(e.getCause()).isInstanceOf(JsonMappingException.class); + assertThat(e.getCause().getMessage()).contains("bad"); + } + } + + @BeforeClass(groups = {"simple"}, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = {"simple"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionDocumentQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionDocumentQueryTest.java new file mode 100644 index 0000000000000..56e4cbe282812 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionDocumentQueryTest.java @@ -0,0 +1,314 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.SqlParameter; +import com.azure.data.cosmos.SqlParameterList; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import com.azure.data.cosmos.internal.TestUtils; +import io.reactivex.subscribers.TestSubscriber; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SinglePartitionDocumentQueryTest extends TestSuiteBase { + + private Database createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments = new ArrayList<>(); + + private CosmosClient client; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + @Factory(dataProvider = "clientBuildersWithDirect") + public SinglePartitionDocumentQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider") + public void queryDocuments(boolean queryMetricsEnabled) throws Exception { + + String query = "SELECT * from c where c.prop = 99"; + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + options.enableCrossPartitionQuery(true); + options.populateQueryMetrics(queryMetricsEnabled); + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .hasValidQueryMetrics(queryMetricsEnabled) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocuments_ParameterizedQueryWithInClause() throws Exception { + String query = "SELECT * from c where c.prop IN (@param1, @param2)"; + SqlParameterList params = new SqlParameterList(new SqlParameter("@param1", 3), new SqlParameter("@param2", 4)); + SqlQuerySpec sqs = new SqlQuerySpec(query, params); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(sqs, options); + + List expectedDocs = createdDocuments.stream().filter(d -> (3 == d.getInt("prop") || 4 == d.getInt("prop"))).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocuments_ParameterizedQuery() throws Exception { + String query = "SELECT * from c where c.prop = @param"; + SqlParameterList params = new SqlParameterList(new SqlParameter("@param", 3)); + SqlQuerySpec sqs = new SqlQuerySpec(query, params); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(sqs, options); + + List expectedDocs = createdDocuments.stream().filter(d -> 3 == d.getInt("prop")).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocuments_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryDocumentsWithPageSize() throws Exception { + + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(3); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments; + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .exactlyContainsInAnyOrder(createdDocuments + .stream() + .map(d -> d.resourceId()) + .collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryOrderBy() throws Exception { + + String query = "SELECT * FROM r ORDER BY r.prop ASC"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(3); + Flux> queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments; + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(createdDocuments.stream() + .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), e2.getInt("prop"))) + .map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 1000) + public void continuationToken() throws Exception { + String query = "SELECT * FROM r ORDER BY r.prop ASC"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(3); + Flux> queryObservable = createdCollection.queryItems(query, options); + + TestSubscriber> subscriber = new TestSubscriber<>(); + queryObservable.take(1).subscribe(subscriber); + + subscriber.awaitTerminalEvent(); + subscriber.assertComplete(); + subscriber.assertNoErrors(); + assertThat(subscriber.valueCount()).isEqualTo(1); + FeedResponse page = ((FeedResponse) subscriber.getEvents().get(0).get(0)); + assertThat(page.results()).hasSize(3); + + assertThat(page.continuationToken()).isNotEmpty(); + + + options.requestContinuation(page.continuationToken()); + queryObservable = createdCollection.queryItems(query, options); + + List expectedDocs = createdDocuments.stream().filter(d -> (d.getInt("prop") > 2)).collect(Collectors.toList()); + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + assertThat(expectedDocs).hasSize(createdDocuments.size() -3); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(expectedDocs.stream() + .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), e2.getInt("prop"))) + .map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySytax() throws Exception { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .notNullActivityId() + .build(); + validateQueryFailure(queryObservable, validator); + } + + public CosmosItemProperties createDocument(CosmosContainer cosmosContainer, int cnt) { + CosmosItemProperties docDefinition = getDocumentDefinition(cnt); + return cosmosContainer.createItem(docDefinition, new CosmosItemRequestOptions()).block().properties(); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for(int i = 0; i < 5; i++) { + createdDocuments.add(createDocument(createdCollection, i)); + } + + for(int i = 0; i < 8; i++) { + createdDocuments.add(createDocument(createdCollection, 99)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosItemProperties getDocumentDefinition(int cnt) { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"prop\" : %d, " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, cnt, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionReadFeedDocumentsTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionReadFeedDocumentsTest.java new file mode 100644 index 0000000000000..af1a5ab29b591 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/SinglePartitionReadFeedDocumentsTest.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +public class SinglePartitionReadFeedDocumentsTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public SinglePartitionReadFeedDocumentsTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) + public void readDocuments() { + final FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(2); + final Flux> feedObservable = createdCollection.readAllItems(options); + final int expectedPageSize = (createdDocuments.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(createdDocuments.size()) + .numberOfPages(expectedPageSize) + .exactlyContainsInAnyOrder(createdDocuments.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); + + List docDefList = new ArrayList<>(); + + for(int i = 0; i < 5; i++) { + docDefList.add(getDocumentDefinition()); + } + + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureCrudTest.java new file mode 100644 index 0000000000000..6f2662e89ff7e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureCrudTest.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosStoredProcedure; +import com.azure.data.cosmos.CosmosStoredProcedureRequestOptions; +import com.azure.data.cosmos.CosmosStoredProcedureResponse; +import com.azure.data.cosmos.CosmosStoredProcedureProperties; +import com.azure.data.cosmos.internal.FailureValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StoredProcedureCrudTest extends TestSuiteBase { + + private CosmosClient client; + private CosmosContainer container; + + @Factory(dataProvider = "clientBuildersWithDirect") + public StoredProcedureCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createStoredProcedure() throws Exception { + + CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(); + storedProcedureDef.id(UUID.randomUUID().toString()); + storedProcedureDef.body("function() {var x = 10;}"); + + Mono createObservable = container.getScripts().createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(storedProcedureDef.id()) + .withStoredProcedureBody("function() {var x = 10;}") + .notNullEtag() + .build(); + + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readStoredProcedure() throws Exception { + + CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(); + storedProcedureDef.id(UUID.randomUUID().toString()); + storedProcedureDef.body("function() {var x = 10;}"); + CosmosStoredProcedure storedProcedure = container.getScripts().createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block().storedProcedure(); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = storedProcedure.read(null); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(storedProcedureDef.id()) + .withStoredProcedureBody("function() {var x = 10;}") + .notNullEtag() + .build(); + + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void deleteStoredProcedure() throws Exception { + + CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(); + storedProcedureDef.id(UUID.randomUUID().toString()); + storedProcedureDef.body("function() {var x = 10;}"); + + CosmosStoredProcedure storedProcedure = this.container.getScripts().createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block().storedProcedure(); + Mono deleteObservable = storedProcedure.delete(new CosmosStoredProcedureRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder<>() + .nullResource() + .build(); + + validateSuccess(deleteObservable, validator); + + waitIfNeededForReplicasToCatchUp(this.clientBuilder()); + + Mono readObservable = storedProcedure.read(null); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @BeforeClass(groups = { "simple" }, timeOut = 10_000 * SETUP_TIMEOUT) + public void beforeClass() { + assertThat(this.client).isNull(); + this.client = clientBuilder().build(); + this.container = getSharedMultiPartitionCosmosContainer(this.client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + assertThat(this.client).isNotNull(); + this.client.close(); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureQueryTest.java new file mode 100644 index 0000000000000..7ac227a1b8a61 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureQueryTest.java @@ -0,0 +1,171 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosStoredProcedureProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StoredProcedureQueryTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private List createdStoredProcs = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public StoredProcedureQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryWithFilter() throws Exception { + + String filterId = createdStoredProcs.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + Flux> queryObservable = createdCollection.getScripts() + .queryStoredProcedures(query, options); + + List expectedDocs = createdStoredProcs.stream() + .filter(sp -> filterId.equals(sp.id())).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void query_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts() + .queryStoredProcedures(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()).numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAll() throws Exception { + + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(3); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts() + .queryStoredProcedures(query, options); + + List expectedDocs = createdStoredProcs; + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySytax() throws Exception { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts() + .queryStoredProcedures(query, options); + + FailureValidator validator = new FailureValidator.Builder().instanceOf(CosmosClientException.class) + .statusCode(400).notNullActivityId().build(); + validateQueryFailure(queryObservable, validator); + } + + public CosmosStoredProcedureProperties createStoredProc(CosmosContainer cosmosContainer) { + CosmosStoredProcedureProperties storedProcedure = getStoredProcedureDef(); + return cosmosContainer.getScripts().createStoredProcedure(storedProcedure).block().properties(); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for (int i = 0; i < 5; i++) { + createdStoredProcs.add(createStoredProc(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosStoredProcedureProperties getStoredProcedureDef() { + CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(); + storedProcedureDef.id(UUID.randomUUID().toString()); + storedProcedureDef.body("function() {var x = 10;}"); + return storedProcedureDef; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureUpsertReplaceTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureUpsertReplaceTest.java new file mode 100644 index 0000000000000..b4370517e7074 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/StoredProcedureUpsertReplaceTest.java @@ -0,0 +1,122 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosStoredProcedure; +import com.azure.data.cosmos.CosmosStoredProcedureProperties; +import com.azure.data.cosmos.CosmosStoredProcedureRequestOptions; +import com.azure.data.cosmos.CosmosStoredProcedureResponse; +import com.azure.data.cosmos.PartitionKey; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StoredProcedureUpsertReplaceTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public StoredProcedureUpsertReplaceTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void replaceStoredProcedure() throws Exception { + + // create a stored procedure + CosmosStoredProcedureProperties storedProcedureDef = new CosmosStoredProcedureProperties(); + storedProcedureDef.id(UUID.randomUUID().toString()); + storedProcedureDef.body("function() {var x = 10;}"); + CosmosStoredProcedureProperties readBackSp = createdCollection.getScripts() + .createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block() + .properties(); + + // read stored procedure to validate creation + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = createdCollection.getScripts() + .getStoredProcedure(readBackSp.id()).read(null); + + // validate stored procedure creation + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() + .withId(readBackSp.id()).withStoredProcedureBody("function() {var x = 10;}").notNullEtag().build(); + validateSuccess(readObservable, validatorForRead); + + // update stored procedure + readBackSp.body("function() {var x = 11;}"); + + Mono replaceObservable = createdCollection.getScripts() + .getStoredProcedure(readBackSp.id()).replace(readBackSp); + + // validate stored procedure replace + CosmosResponseValidator validatorForReplace = new CosmosResponseValidator.Builder() + .withId(readBackSp.id()).withStoredProcedureBody("function() {var x = 11;}").notNullEtag().build(); + validateSuccess(replaceObservable, validatorForReplace); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void executeStoredProcedure() throws Exception { + // create a stored procedure + CosmosStoredProcedureProperties storedProcedureDef = BridgeInternal + .createCosmosStoredProcedureProperties("{" + " 'id': '" + UUID.randomUUID().toString() + "'," + + " 'body':" + " 'function () {" + " for (var i = 0; i < 10; i++) {" + + " getContext().getResponse().appendValue(\"Body\", i);" + " }" + " }'" + "}"); + + CosmosStoredProcedure storedProcedure = null; + + storedProcedure = createdCollection.getScripts() + .createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block() + .storedProcedure(); + + String result = null; + + CosmosStoredProcedureRequestOptions options = new CosmosStoredProcedureRequestOptions(); + options.partitionKey(PartitionKey.None); + result = storedProcedure.execute(null, options).block().responseAsString(); + + assertThat(result).isEqualTo("\"0123456789\""); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TestSuiteBase.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TestSuiteBase.java new file mode 100644 index 0000000000000..2495347ac1169 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TestSuiteBase.java @@ -0,0 +1,1004 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CompositePath; +import com.azure.data.cosmos.CompositePathSortOrder; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosBridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosClientTest; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerRequestOptions; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosDatabaseProperties; +import com.azure.data.cosmos.CosmosDatabaseResponse; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.CosmosResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosStoredProcedureRequestOptions; +import com.azure.data.cosmos.CosmosUser; +import com.azure.data.cosmos.CosmosUserProperties; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.Index; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.RetryOptions; +import com.azure.data.cosmos.SqlQuerySpec; +import com.azure.data.cosmos.internal.Configs; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.PathParser; +import com.azure.data.cosmos.internal.TestConfigurations; +import com.azure.data.cosmos.internal.Utils; +import com.azure.data.cosmos.internal.directconnectivity.Protocol; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableList; +import io.reactivex.subscribers.TestSubscriber; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.mockito.stubbing.Answer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.DataProvider; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static com.azure.data.cosmos.BridgeInternal.extractConfigs; +import static com.azure.data.cosmos.BridgeInternal.injectConfigs; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +public class TestSuiteBase extends CosmosClientTest { + + private static final int DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL = 500; + private static final ObjectMapper objectMapper = new ObjectMapper(); + + protected static Logger logger = LoggerFactory.getLogger(TestSuiteBase.class.getSimpleName()); + protected static final int TIMEOUT = 40000; + protected static final int FEED_TIMEOUT = 40000; + protected static final int SETUP_TIMEOUT = 60000; + protected static final int SHUTDOWN_TIMEOUT = 12000; + + protected static final int SUITE_SETUP_TIMEOUT = 120000; + protected static final int SUITE_SHUTDOWN_TIMEOUT = 60000; + + protected static final int WAIT_REPLICA_CATCH_UP_IN_MILLIS = 4000; + + protected final static ConsistencyLevel accountConsistency; + protected static final ImmutableList preferredLocations; + private static final ImmutableList desiredConsistencies; + private static final ImmutableList protocols; + + protected int subscriberValidationTimeout = TIMEOUT; + + private static CosmosDatabase SHARED_DATABASE; + private static CosmosContainer SHARED_MULTI_PARTITION_COLLECTION; + private static CosmosContainer SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; + private static CosmosContainer SHARED_SINGLE_PARTITION_COLLECTION; + + public TestSuiteBase(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + protected static CosmosDatabase getSharedCosmosDatabase(CosmosClient client) { + return CosmosBridgeInternal.getCosmosDatabaseWithNewClient(SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedMultiPartitionCosmosContainer(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_MULTI_PARTITION_COLLECTION, SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedMultiPartitionCosmosContainerWithCompositeAndSpatialIndexes(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES, SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedSinglePartitionCosmosContainer(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_SINGLE_PARTITION_COLLECTION, SHARED_DATABASE, client); + } + + static { + accountConsistency = parseConsistency(TestConfigurations.CONSISTENCY); + desiredConsistencies = immutableListOrNull( + ObjectUtils.defaultIfNull(parseDesiredConsistencies(TestConfigurations.DESIRED_CONSISTENCIES), + allEqualOrLowerConsistencies(accountConsistency))); + preferredLocations = immutableListOrNull(parsePreferredLocation(TestConfigurations.PREFERRED_LOCATIONS)); + protocols = ObjectUtils.defaultIfNull(immutableListOrNull(parseProtocols(TestConfigurations.PROTOCOLS)), + ImmutableList.of(Protocol.HTTPS, Protocol.TCP)); + + // Object mapper configurations + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + objectMapper.configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true); + objectMapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + } + + protected TestSuiteBase() { + logger.debug("Initializing {} ...", this.getClass().getSimpleName()); + } + + private static ImmutableList immutableListOrNull(List list) { + return list != null ? ImmutableList.copyOf(list) : null; + } + + private static class DatabaseManagerImpl implements CosmosDatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(CosmosClient client) { + return new DatabaseManagerImpl(client); + } + + private final CosmosClient client; + + private DatabaseManagerImpl(CosmosClient client) { + this.client = client; + } + + @Override + public Flux> queryDatabases(SqlQuerySpec query) { + return client.queryDatabases(query, null); + } + + @Override + public Mono createDatabase(CosmosDatabaseProperties databaseDefinition) { + return client.createDatabase(databaseDefinition); + } + + @Override + public CosmosDatabase getDatabase(String id) { + return client.getDatabase(id); + } + } + + @BeforeSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SETUP_TIMEOUT) + public static void beforeSuite() { + + logger.info("beforeSuite Started"); + + try (CosmosClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build()) { + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.create(DatabaseManagerImpl.getInstance(houseKeepingClient)); + SHARED_DATABASE = dbForTest.createdDatabase; + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + SHARED_MULTI_PARTITION_COLLECTION = createCollection(SHARED_DATABASE, getCollectionDefinitionWithRangeRangeIndex(), options, 10100); + SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES = createCollection(SHARED_DATABASE, getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes(), options); + SHARED_SINGLE_PARTITION_COLLECTION = createCollection(SHARED_DATABASE, getCollectionDefinitionWithRangeRangeIndex(), options, 6000); + } + } + + @AfterSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SHUTDOWN_TIMEOUT) + public static void afterSuite() { + + logger.info("afterSuite Started"); + + try (CosmosClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build()) { + safeDeleteDatabase(SHARED_DATABASE); + CosmosDatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(houseKeepingClient)); + } + } + + protected static void truncateCollection(CosmosContainer cosmosContainer) { + CosmosContainerProperties cosmosContainerProperties = cosmosContainer.read().block().properties(); + String cosmosContainerId = cosmosContainerProperties.id(); + logger.info("Truncating collection {} ...", cosmosContainerId); + List paths = cosmosContainerProperties.partitionKeyDefinition().paths(); + FeedOptions options = new FeedOptions(); + options.maxDegreeOfParallelism(-1); + options.enableCrossPartitionQuery(true); + options.maxItemCount(100); + + logger.info("Truncating collection {} documents ...", cosmosContainer.id()); + + cosmosContainer.queryItems("SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(doc -> { + + Object propertyValue = null; + if (paths != null && !paths.isEmpty()) { + List pkPath = PathParser.getPathParts(paths.get(0)); + propertyValue = doc.getObjectByPath(pkPath); + if (propertyValue == null) { + propertyValue = PartitionKey.None; + } + + } + return cosmosContainer.getItem(doc.id(), propertyValue).delete(); + }).then().block(); + logger.info("Truncating collection {} triggers ...", cosmosContainerId); + + cosmosContainer.getScripts().queryTriggers("SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(trigger -> { +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = trigger.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return cosmosContainer.getScripts().getTrigger(trigger.id()).delete(); + }).then().block(); + + logger.info("Truncating collection {} storedProcedures ...", cosmosContainerId); + + cosmosContainer.getScripts().queryStoredProcedures("SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(storedProcedure -> { + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = storedProcedure.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return cosmosContainer.getScripts().getStoredProcedure(storedProcedure.id()).delete(new CosmosStoredProcedureRequestOptions()); + }).then().block(); + + logger.info("Truncating collection {} udfs ...", cosmosContainerId); + + cosmosContainer.getScripts().queryUserDefinedFunctions("SELECT * FROM root", options) + .publishOn(Schedulers.parallel()) + .flatMap(page -> Flux.fromIterable(page.results())) + .flatMap(udf -> { + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = udf.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.partitionKey(new PartitionKey(propertyValue)); +// } + + return cosmosContainer.getScripts().getUserDefinedFunction(udf.id()).delete(); + }).then().block(); + + logger.info("Finished truncating collection {}.", cosmosContainerId); + } + + protected static void waitIfNeededForReplicasToCatchUp(CosmosClientBuilder clientBuilder) { + switch (clientBuilder.consistencyLevel()) { + case EVENTUAL: + case CONSISTENT_PREFIX: + logger.info(" additional wait in EVENTUAL mode so the replica catch up"); + // give times to replicas to catch up after a write + try { + TimeUnit.MILLISECONDS.sleep(WAIT_REPLICA_CATCH_UP_IN_MILLIS); + } catch (Exception e) { + logger.error("unexpected failure", e); + } + + case SESSION: + case BOUNDED_STALENESS: + case STRONG: + default: + break; + } + } + + public static CosmosContainer createCollection(CosmosDatabase database, CosmosContainerProperties cosmosContainerProperties, + CosmosContainerRequestOptions options, int throughput) { + return database.createContainer(cosmosContainerProperties, throughput, options).block().container(); + } + + public static CosmosContainer createCollection(CosmosDatabase database, CosmosContainerProperties cosmosContainerProperties, + CosmosContainerRequestOptions options) { + return database.createContainer(cosmosContainerProperties, options).block().container(); + } + + private static CosmosContainerProperties getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes() { + final String NUMBER_FIELD = "numberField"; + final String STRING_FIELD = "stringField"; + final String NUMBER_FIELD_2 = "numberField2"; + final String STRING_FIELD_2 = "stringField2"; + final String BOOL_FIELD = "boolField"; + final String NULL_FIELD = "nullField"; + final String OBJECT_FIELD = "objectField"; + final String ARRAY_FIELD = "arrayField"; + final String SHORT_STRING_FIELD = "shortStringField"; + final String MEDIUM_STRING_FIELD = "mediumStringField"; + final String LONG_STRING_FIELD = "longStringField"; + final String PARTITION_KEY = "pk"; + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + ArrayList partitionKeyPaths = new ArrayList(); + partitionKeyPaths.add("/" + PARTITION_KEY); + partitionKeyDefinition.paths(partitionKeyPaths); + + CosmosContainerProperties cosmosContainerProperties = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDefinition); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List> compositeIndexes = new ArrayList<>(); + + //Simple + ArrayList compositeIndexSimple = new ArrayList(); + CompositePath compositePath1 = new CompositePath(); + compositePath1.path("/" + NUMBER_FIELD); + compositePath1.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath2 = new CompositePath(); + compositePath2.path("/" + STRING_FIELD); + compositePath2.order(CompositePathSortOrder.DESCENDING); + + compositeIndexSimple.add(compositePath1); + compositeIndexSimple.add(compositePath2); + + //Max Columns + ArrayList compositeIndexMaxColumns = new ArrayList(); + CompositePath compositePath3 = new CompositePath(); + compositePath3.path("/" + NUMBER_FIELD); + compositePath3.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath4 = new CompositePath(); + compositePath4.path("/" + STRING_FIELD); + compositePath4.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath5 = new CompositePath(); + compositePath5.path("/" + NUMBER_FIELD_2); + compositePath5.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath6 = new CompositePath(); + compositePath6.path("/" + STRING_FIELD_2); + compositePath6.order(CompositePathSortOrder.ASCENDING); + + compositeIndexMaxColumns.add(compositePath3); + compositeIndexMaxColumns.add(compositePath4); + compositeIndexMaxColumns.add(compositePath5); + compositeIndexMaxColumns.add(compositePath6); + + //Primitive Values + ArrayList compositeIndexPrimitiveValues = new ArrayList(); + CompositePath compositePath7 = new CompositePath(); + compositePath7.path("/" + NUMBER_FIELD); + compositePath7.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath8 = new CompositePath(); + compositePath8.path("/" + STRING_FIELD); + compositePath8.order(CompositePathSortOrder.ASCENDING); + + CompositePath compositePath9 = new CompositePath(); + compositePath9.path("/" + BOOL_FIELD); + compositePath9.order(CompositePathSortOrder.DESCENDING); + + CompositePath compositePath10 = new CompositePath(); + compositePath10.path("/" + NULL_FIELD); + compositePath10.order(CompositePathSortOrder.ASCENDING); + + compositeIndexPrimitiveValues.add(compositePath7); + compositeIndexPrimitiveValues.add(compositePath8); + compositeIndexPrimitiveValues.add(compositePath9); + compositeIndexPrimitiveValues.add(compositePath10); + + //Long Strings + ArrayList compositeIndexLongStrings = new ArrayList(); + CompositePath compositePath11 = new CompositePath(); + compositePath11.path("/" + STRING_FIELD); + + CompositePath compositePath12 = new CompositePath(); + compositePath12.path("/" + SHORT_STRING_FIELD); + + CompositePath compositePath13 = new CompositePath(); + compositePath13.path("/" + MEDIUM_STRING_FIELD); + + CompositePath compositePath14 = new CompositePath(); + compositePath14.path("/" + LONG_STRING_FIELD); + + compositeIndexLongStrings.add(compositePath11); + compositeIndexLongStrings.add(compositePath12); + compositeIndexLongStrings.add(compositePath13); + compositeIndexLongStrings.add(compositePath14); + + compositeIndexes.add(compositeIndexSimple); + compositeIndexes.add(compositeIndexMaxColumns); + compositeIndexes.add(compositeIndexPrimitiveValues); + compositeIndexes.add(compositeIndexLongStrings); + + indexingPolicy.compositeIndexes(compositeIndexes); + cosmosContainerProperties.indexingPolicy(indexingPolicy); + + return cosmosContainerProperties; + } + + public static CosmosContainer createCollection(CosmosClient client, String dbId, CosmosContainerProperties collectionDefinition) { + return client.getDatabase(dbId).createContainer(collectionDefinition).block().container(); + } + + public static void deleteCollection(CosmosClient client, String dbId, String collectionId) { + client.getDatabase(dbId).getContainer(collectionId).delete().block(); + } + + public static CosmosItem createDocument(CosmosContainer cosmosContainer, CosmosItemProperties item) { + return cosmosContainer.createItem(item).block().item(); + } + + private Flux bulkInsert(CosmosContainer cosmosContainer, + List documentDefinitionList, + int concurrencyLevel) { + List> result = new ArrayList<>(documentDefinitionList.size()); + for (CosmosItemProperties docDef : documentDefinitionList) { + result.add(cosmosContainer.createItem(docDef)); + } + + return Flux.merge(Flux.fromIterable(result), concurrencyLevel); + } + public List bulkInsertBlocking(CosmosContainer cosmosContainer, + List documentDefinitionList) { + return bulkInsert(cosmosContainer, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL) + .publishOn(Schedulers.parallel()) + .map(CosmosItemResponse::properties) + .collectList() + .block(); + } + + public void voidBulkInsertBlocking(CosmosContainer cosmosContainer, + List documentDefinitionList) { + bulkInsert(cosmosContainer, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL) + .publishOn(Schedulers.parallel()) + .map(CosmosItemResponse::properties) + .then() + .block(); + } + + public static CosmosUser createUser(CosmosClient client, String databaseId, CosmosUserProperties userSettings) { + return client.getDatabase(databaseId).read().block().database().createUser(userSettings).block().user(); + } + + public static CosmosUser safeCreateUser(CosmosClient client, String databaseId, CosmosUserProperties user) { + deleteUserIfExists(client, databaseId, user.id()); + return createUser(client, databaseId, user); + } + + private static CosmosContainer safeCreateCollection(CosmosClient client, String databaseId, CosmosContainerProperties collection, CosmosContainerRequestOptions options) { + deleteCollectionIfExists(client, databaseId, collection.id()); + return createCollection(client.getDatabase(databaseId), collection, options); + } + + static protected CosmosContainerProperties getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + + return collectionDefinition; + } + + static protected CosmosContainerProperties getCollectionDefinitionWithRangeRangeIndex() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + List includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.path("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.STRING); + BridgeInternal.setProperty(stringIndex, "precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.NUMBER); + BridgeInternal.setProperty(numberIndex, "precision", -1); + indexes.add(numberIndex); + includedPath.indexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + CosmosContainerProperties cosmosContainerProperties = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + cosmosContainerProperties.indexingPolicy(indexingPolicy); + + return cosmosContainerProperties; + } + + public static void deleteCollectionIfExists(CosmosClient client, String databaseId, String collectionId) { + CosmosDatabase database = client.getDatabase(databaseId).read().block().database(); + List res = database.queryContainers(String.format("SELECT * FROM root r where r.id = '%s'", collectionId), null) + .flatMap(page -> Flux.fromIterable(page.results())) + .collectList() + .block(); + + if (!res.isEmpty()) { + deleteCollection(database, collectionId); + } + } + + public static void deleteCollection(CosmosDatabase cosmosDatabase, String collectionId) { + cosmosDatabase.getContainer(collectionId).delete().block(); + } + + public static void deleteCollection(CosmosContainer cosmosContainer) { + cosmosContainer.delete().block(); + } + + public static void deleteDocumentIfExists(CosmosClient client, String databaseId, String collectionId, String docId) { + FeedOptions options = new FeedOptions(); + options.partitionKey(new PartitionKey(docId)); + CosmosContainer cosmosContainer = client.getDatabase(databaseId).read().block().database().getContainer(collectionId).read().block().container(); + List res = cosmosContainer + .queryItems(String.format("SELECT * FROM root r where r.id = '%s'", docId), options) + .flatMap(page -> Flux.fromIterable(page.results())) + .collectList().block(); + + if (!res.isEmpty()) { + deleteDocument(cosmosContainer, docId); + } + } + + public static void safeDeleteDocument(CosmosContainer cosmosContainer, String documentId, Object partitionKey) { + if (cosmosContainer != null && documentId != null) { + try { + cosmosContainer.getItem(documentId, partitionKey).read().block().item().delete().block(); + } catch (Exception e) { + CosmosClientException dce = Utils.as(e, CosmosClientException.class); + if (dce == null || dce.statusCode() != 404) { + throw e; + } + } + } + } + + public static void deleteDocument(CosmosContainer cosmosContainer, String documentId) { + cosmosContainer.getItem(documentId, PartitionKey.None).read().block().item().delete(); + } + + public static void deleteUserIfExists(CosmosClient client, String databaseId, String userId) { + CosmosDatabase database = client.getDatabase(databaseId).read().block().database(); + List res = database + .queryUsers(String.format("SELECT * FROM root r where r.id = '%s'", userId), null) + .flatMap(page -> Flux.fromIterable(page.results())) + .collectList().block(); + if (!res.isEmpty()) { + deleteUser(database, userId); + } + } + + public static void deleteUser(CosmosDatabase database, String userId) { + database.getUser(userId).read().block().user().delete().block(); + } + + static private CosmosDatabase safeCreateDatabase(CosmosClient client, CosmosDatabaseProperties databaseSettings) { + safeDeleteDatabase(client.getDatabase(databaseSettings.id())); + return client.createDatabase(databaseSettings).block().database(); + } + + static protected CosmosDatabase createDatabase(CosmosClient client, String databaseId) { + CosmosDatabaseProperties databaseSettings = new CosmosDatabaseProperties(databaseId); + return client.createDatabase(databaseSettings).block().database(); + } + + static protected CosmosDatabase createDatabaseIfNotExists(CosmosClient client, String databaseId) { + List res = client.queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseId), null) + .flatMap(p -> Flux.fromIterable(p.results())) + .collectList() + .block(); + if (res.size() != 0) { + return client.getDatabase(databaseId).read().block().database(); + } else { + CosmosDatabaseProperties databaseSettings = new CosmosDatabaseProperties(databaseId); + return client.createDatabase(databaseSettings).block().database(); + } + } + + static protected void safeDeleteDatabase(CosmosDatabase database) { + if (database != null) { + try { + database.delete().block(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteAllCollections(CosmosDatabase database) { + if (database != null) { + List collections = database.readAllContainers() + .flatMap(p -> Flux.fromIterable(p.results())) + .collectList() + .block(); + + for(CosmosContainerProperties collection: collections) { + database.getContainer(collection.id()).delete().block(); + } + } + } + + static protected void safeDeleteCollection(CosmosContainer collection) { + if (collection != null) { + try { + collection.delete().block(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteCollection(CosmosDatabase database, String collectionId) { + if (database != null && collectionId != null) { + try { + database.getContainer(collectionId).delete().block(); + } catch (Exception e) { + } + } + } + + static protected void safeCloseAsync(CosmosClient client) { + if (client != null) { + new Thread(() -> { + try { + client.close(); + } catch (Exception e) { + logger.error("failed to close client", e); + } + }).start(); + } + } + + static protected void safeClose(CosmosClient client) { + if (client != null) { + try { + client.close(); + } catch (Exception e) { + logger.error("failed to close client", e); + } + } + } + + public void validateSuccess(Mono single, CosmosResponseValidator validator) + throws InterruptedException { + validateSuccess(single.flux(), validator, subscriberValidationTimeout); + } + + public static void validateSuccess(Flux flowable, + CosmosResponseValidator validator, long timeout) { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public void validateFailure(Mono mono, FailureValidator validator) + throws InterruptedException { + validateFailure(mono.flux(), validator, subscriberValidationTimeout); + } + + public static void validateFailure(Flux flowable, + FailureValidator validator, long timeout) throws InterruptedException { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errors()).hasSize(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + public void validateQuerySuccess(Flux> flowable, + FeedResponseListValidator validator) { + validateQuerySuccess(flowable, validator, subscriberValidationTimeout); + } + + public static void validateQuerySuccess(Flux> flowable, + FeedResponseListValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + validator.validate(testSubscriber.values()); + } + + public void validateQueryFailure(Flux> flowable, FailureValidator validator) { + validateQueryFailure(flowable, validator, subscriberValidationTimeout); + } + + public static void validateQueryFailure(Flux> flowable, + FailureValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.getEvents().get(1)).hasSize(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + @DataProvider + public static Object[][] clientBuilders() { + return new Object[][]{{createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)}}; + } + + @DataProvider + public static Object[][] clientBuildersWithSessionConsistency() { + return new Object[][]{ + {createDirectRxDocumentClient(ConsistencyLevel.SESSION, Protocol.HTTPS, false, null)}, + {createDirectRxDocumentClient(ConsistencyLevel.SESSION, Protocol.TCP, false, null)}, + {createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)} + }; + } + + static ConsistencyLevel parseConsistency(String consistency) { + if (consistency != null) { + consistency = CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, consistency).trim(); + return ConsistencyLevel.valueOf(consistency); + } + + logger.error("INVALID configured test consistency [{}].", consistency); + throw new IllegalStateException("INVALID configured test consistency " + consistency); + } + + static List parsePreferredLocation(String preferredLocations) { + if (StringUtils.isEmpty(preferredLocations)) { + return null; + } + + try { + return objectMapper.readValue(preferredLocations, new TypeReference>() { + }); + } catch (Exception e) { + logger.error("INVALID configured test preferredLocations [{}].", preferredLocations); + throw new IllegalStateException("INVALID configured test preferredLocations " + preferredLocations); + } + } + + static List parseProtocols(String protocols) { + if (StringUtils.isEmpty(protocols)) { + return null; + } + List protocolList = new ArrayList<>(); + try { + List protocolStrings = objectMapper.readValue(protocols, new TypeReference>() { + }); + for(String protocol : protocolStrings) { + protocolList.add(Protocol.valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, protocol))); + } + return protocolList; + } catch (Exception e) { + logger.error("INVALID configured test protocols [{}].", protocols); + throw new IllegalStateException("INVALID configured test protocols " + protocols); + } + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirect() { + return simpleClientBuildersWithDirect(toArray(protocols)); + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirectHttps() { + return simpleClientBuildersWithDirect(Protocol.HTTPS); + } + + private static Object[][] simpleClientBuildersWithDirect(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + List testConsistencies = ImmutableList.of(ConsistencyLevel.EVENTUAL); + + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.SESSION; + + List cosmosConfigurations = new ArrayList<>(); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> cosmosConfigurations.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + cosmosConfigurations.forEach(c -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + c.connectionPolicy().connectionMode(), + c.consistencyLevel(), + extractConfigs(c).getProtocol() + )); + + cosmosConfigurations.add(createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null)); + + return cosmosConfigurations.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + @DataProvider + public static Object[][] clientBuildersWithDirect() { + return clientBuildersWithDirectAllConsistencies(toArray(protocols)); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectHttps() { + return clientBuildersWithDirectAllConsistencies(Protocol.HTTPS); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectSession() { + return clientBuildersWithDirectSession(toArray(protocols)); + } + + static Protocol[] toArray(List protocols) { + return protocols.toArray(new Protocol[protocols.size()]); + } + + private static Object[][] clientBuildersWithDirectSession(Protocol... protocols) { + return clientBuildersWithDirect(new ArrayList() {{ + add(ConsistencyLevel.SESSION); + }}, protocols); + } + + private static Object[][] clientBuildersWithDirectAllConsistencies(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + return clientBuildersWithDirect(desiredConsistencies, protocols); + } + + static List parseDesiredConsistencies(String consistencies) { + if (StringUtils.isEmpty(consistencies)) { + return null; + } + List consistencyLevels = new ArrayList<>(); + try { + List consistencyStrings = objectMapper.readValue(consistencies, new TypeReference>() {}); + for(String consistency : consistencyStrings) { + consistencyLevels.add(ConsistencyLevel.valueOf(CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, consistency))); + } + return consistencyLevels; + } catch (Exception e) { + logger.error("INVALID consistency test desiredConsistencies [{}].", consistencies); + throw new IllegalStateException("INVALID configured test desiredConsistencies " + consistencies); + } + } + + static List allEqualOrLowerConsistencies(ConsistencyLevel accountConsistency) { + List testConsistencies = new ArrayList<>(); + switch (accountConsistency) { + + case STRONG: + testConsistencies.add(ConsistencyLevel.STRONG); + case BOUNDED_STALENESS: + testConsistencies.add(ConsistencyLevel.BOUNDED_STALENESS); + case SESSION: + testConsistencies.add(ConsistencyLevel.SESSION); + case CONSISTENT_PREFIX: + testConsistencies.add(ConsistencyLevel.CONSISTENT_PREFIX); + case EVENTUAL: + testConsistencies.add(ConsistencyLevel.EVENTUAL); + break; + default: + throw new IllegalStateException("INVALID configured test consistency " + accountConsistency); + } + return testConsistencies; + } + + private static Object[][] clientBuildersWithDirect(List testConsistencies, Protocol... protocols) { + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.SESSION; + + List cosmosConfigurations = new ArrayList<>(); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> cosmosConfigurations.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + cosmosConfigurations.forEach(c -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + c.connectionPolicy().connectionMode(), + c.consistencyLevel(), + extractConfigs(c).getProtocol() + )); + + cosmosConfigurations.add(createGatewayRxDocumentClient(ConsistencyLevel.SESSION, isMultiMasterEnabled, preferredLocations)); + + return cosmosConfigurations.stream().map(c -> new Object[]{c}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + static protected CosmosClientBuilder createGatewayHouseKeepingDocumentClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + RetryOptions options = new RetryOptions(); + options.maxRetryWaitTimeInSeconds(SUITE_SETUP_TIMEOUT); + connectionPolicy.retryOptions(options); + return CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.SESSION); + } + + static protected CosmosClientBuilder createGatewayRxDocumentClient(ConsistencyLevel consistencyLevel, boolean multiMasterEnabled, List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.GATEWAY); + connectionPolicy.usingMultipleWriteLocations(multiMasterEnabled); + connectionPolicy.preferredLocations(preferredLocations); + return CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(consistencyLevel); + } + + static protected CosmosClientBuilder createGatewayRxDocumentClient() { + return createGatewayRxDocumentClient(ConsistencyLevel.SESSION, false, null); + } + + static protected CosmosClientBuilder createDirectRxDocumentClient(ConsistencyLevel consistencyLevel, + Protocol protocol, + boolean multiMasterEnabled, + List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(ConnectionMode.DIRECT); + + if (preferredLocations != null) { + connectionPolicy.preferredLocations(preferredLocations); + } + + if (multiMasterEnabled && consistencyLevel == ConsistencyLevel.SESSION) { + connectionPolicy.usingMultipleWriteLocations(true); + } + + Configs configs = spy(new Configs()); + doAnswer((Answer)invocation -> protocol).when(configs).getProtocol(); + + CosmosClientBuilder builder = CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(consistencyLevel); + + return injectConfigs(builder, configs); + } + + protected int expectedNumberOfPages(int totalExpectedResult, int maxPageSize) { + return Math.max((totalExpectedResult + maxPageSize - 1 ) / maxPageSize, 1); + } + + @DataProvider(name = "queryMetricsArgProvider") + public Object[][] queryMetricsArgProvider() { + return new Object[][]{ + {true}, + {false}, + }; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TokenResolverTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TokenResolverTest.java new file mode 100644 index 0000000000000..597ad47ca7f67 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TokenResolverTest.java @@ -0,0 +1,561 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.internal.AsyncDocumentClient; +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.ChangeFeedOptions; +import com.azure.data.cosmos.ConnectionMode; +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosResourceType; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.internal.Document; +import com.azure.data.cosmos.internal.DocumentCollection; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.*; +import com.azure.data.cosmos.PermissionMode; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.TokenResolver; +import com.azure.data.cosmos.internal.TestSuiteBase; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TokenResolverTest extends TestSuiteBase { + + private class UserClass { + public String userName; + public int userId; + + public UserClass(String userName, int userId) { + this.userName = userName; + this.userId = userId; + } + } + + private Database createdDatabase; + private DocumentCollection createdCollection; + private User userWithReadPermission; + private User userWithAllPermission; + + private Permission readPermission; + private Permission allPermission; + + private AsyncDocumentClient.Builder clientBuilder; + private AsyncDocumentClient client; + + @Factory(dataProvider = "clientBuilders") + public TokenResolverTest(AsyncDocumentClient.Builder clientBuilder) { + super(clientBuilder); + } + + @DataProvider(name = "connectionMode") + public Object[][] connectionMode() { + return new Object[][]{ + {ConnectionMode.GATEWAY}, + {ConnectionMode.DIRECT}, + }; + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + createdDatabase = SHARED_DATABASE; + createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + + client = clientBuilder().build(); + + userWithReadPermission = createUser(client, createdDatabase.id(), getUserDefinition()); + readPermission = client.createPermission(userWithReadPermission.selfLink(), getPermission(createdCollection, "ReadPermissionOnColl", PermissionMode.READ), null).single().block() + .getResource(); + + userWithAllPermission = createUser(client, createdDatabase.id(), getUserDefinition()); + allPermission = client.createPermission(userWithAllPermission.selfLink(), getPermission(createdCollection, "AllPermissionOnColl", PermissionMode.ALL), null).single().block() + .getResource(); + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void readDocumentWithReadPermission(ConnectionMode connectionMode) { + Document docDefinition = getDocumentDefinition(); + ResourceResponse resourceResponse = client + .createDocument(BridgeInternal.getAltLink(createdCollection), docDefinition, null, false).blockFirst(); + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.READ); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceResponse.getResource().get("mypk"))); + HashMap properties = new HashMap(); + properties.put("UserId", "readUser"); + requestOptions.setProperties(properties); + Flux> readObservable = asyncClientWithTokenResolver.readDocument(resourceResponse.getResource().selfLink(), requestOptions); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(resourceResponse.getResource().id()).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void deleteDocumentWithReadPermission(ConnectionMode connectionMode) { + Document docDefinition = getDocumentDefinition(); + ResourceResponse resourceResponse = client + .createDocument(BridgeInternal.getAltLink(createdCollection), docDefinition, null, false).blockFirst(); + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.READ); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceResponse.getResource().get("mypk"))); + Flux> readObservable = asyncClientWithTokenResolver.deleteDocument(resourceResponse.getResource().selfLink(), requestOptions); + FailureValidator validator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.FORBIDDEN).build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void writeDocumentWithReadPermission(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.READ); + Flux> readObservable = asyncClientWithTokenResolver.createDocument(createdCollection.selfLink(), getDocumentDefinition(), null, true); + FailureValidator validator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.FORBIDDEN).build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void writeDocumentWithAllPermission(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.ALL); + Document documentDefinition = getDocumentDefinition(); + Flux> readObservable = asyncClientWithTokenResolver.createDocument(createdCollection.selfLink(), documentDefinition, null, true); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(documentDefinition.id()).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void deleteDocumentWithAllPermission(ConnectionMode connectionMode) { + Document docDefinition = getDocumentDefinition(); + ResourceResponse resourceResponse = client + .createDocument(BridgeInternal.getAltLink(createdCollection), docDefinition, null, false).blockFirst(); + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.ALL); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceResponse.getResource().get("mypk"))); + Flux> readObservable = asyncClientWithTokenResolver.deleteDocument(resourceResponse.getResource().selfLink(), requestOptions); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .nullResource().build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void readCollectionWithReadPermission(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.READ); + Flux> readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), null); + ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + .withId(createdCollection.id()).build(); + validateSuccess(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void deleteCollectionWithReadPermission(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.READ); + Flux> readObservable = asyncClientWithTokenResolver.deleteCollection(createdCollection.selfLink(), null); + FailureValidator validator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.FORBIDDEN).build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void verifyingAuthTokenAPISequence(ConnectionMode connectionMode) { + Document docDefinition = getDocumentDefinition(); + ResourceResponse resourceResponse = client + .createDocument(BridgeInternal.getAltLink(createdCollection), docDefinition, null, false).blockFirst(); + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(connectionMode); + + //Unauthorized error with invalid token resolver, valid master key and valid permission feed, making it sure tokenResolver has higher priority than all. + List permissionFeed = new ArrayList<>(); + permissionFeed.add(readPermission); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolver(null)) //TokenResolver always generating invalid token. + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withPermissionFeed(permissionFeed) + .build(); + RequestOptions requestOptions = new RequestOptions(); + requestOptions.setPartitionKey(new PartitionKey(resourceResponse.getResource().get("mypk"))); + Flux> readObservable = asyncClientWithTokenResolver.readDocument(resourceResponse.getResource().selfLink(), requestOptions); + FailureValidator failureValidator = new FailureValidator.Builder().statusCode(HttpConstants.StatusCodes.UNAUTHORIZED).build(); + validateFailure(readObservable, failureValidator); + + //Success read operation with valid token resolver, invalid master key and invalid permission feed, making it sure tokenResolver has higher priority than all. + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolver(PermissionMode.READ)) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withPermissionFeed(permissionFeed) + .build(); + readObservable = asyncClientWithTokenResolver.readDocument(resourceResponse.getResource().selfLink(), requestOptions); + ResourceResponseValidator sucessValidator = new ResourceResponseValidator.Builder() + .withId(resourceResponse.getResource().id()).build(); + validateSuccess(readObservable, sucessValidator); + + + //Success read operation with valid permission feed, supporting above hypothesis. + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withPermissionFeed(permissionFeed) + .build(); + readObservable = asyncClientWithTokenResolver.readDocument(resourceResponse.getResource().selfLink(), requestOptions); + validateSuccess(readObservable, sucessValidator); + + + //Success read operation with valid master key, supporting above hypothesis. + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .build(); + readObservable = asyncClientWithTokenResolver.readDocument(resourceResponse.getResource().selfLink(), requestOptions); + validateSuccess(readObservable, sucessValidator); + + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = 6000000) + public void createAndExecuteSprocWithWritePermission(ConnectionMode connectionMode) throws InterruptedException { + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.ALL); + String sprocId = "storedProcedure" + UUID.randomUUID().toString(); + StoredProcedure sproc = new StoredProcedure( + "{" + + " 'id':'" + sprocId + "'," + + " 'body':" + + " 'function() {" + + " var mytext = \"x\";" + + " var myval = 1;" + + " try {" + + " getContext().getResponse().setBody(\"Success!\");" + + " }" + + " catch(err) {" + + " getContext().getResponse().setBody(\"inline err: [\" + err.number + \"] \" + err);" + + " }" + + " }'" + + "}"); + + Flux> createObservable = asyncClientWithTokenResolver.createStoredProcedure(createdCollection.selfLink(), sproc, null); + ResourceResponseValidator createSucessValidator = new ResourceResponseValidator.Builder() + .withId(sprocId).build(); + validateSuccess(createObservable, createSucessValidator); + + RequestOptions options = new RequestOptions(); + options.setPartitionKey(new PartitionKey("")); + String sprocLink = "dbs/" + createdDatabase.id() + "/colls/" + createdCollection.id() + "/sprocs/" + sprocId; + StoredProcedureResponse result = asyncClientWithTokenResolver.executeStoredProcedure(sprocLink, options, null).single().block(); + assertThat(result.getResponseAsString()).isEqualTo("\"Success!\""); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void readDocumentsWithAllPermission(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + String id1 = UUID.randomUUID().toString(); + String id2 = UUID.randomUUID().toString(); + + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.ALL); + Document document1 = asyncClientWithTokenResolver.createDocument(createdCollection.selfLink(), new Document("{'id': '" + id1 + "'}"), null, false) + .single().block().getResource(); + Document document2 = asyncClientWithTokenResolver.createDocument(createdCollection.selfLink(), new Document("{'id': '" + id2 + "'}"), null, false) + .single().block().getResource(); + List expectedIds = new ArrayList(); + String rid1 = document1.resourceId(); + String rid2 = document2.resourceId(); + expectedIds.add(rid1); + expectedIds.add(rid2); + String query = "SELECT * FROM r WHERE r._rid=\"" + rid1 + "\" or r._rid=\"" + rid2 + "\""; + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = asyncClientWithTokenResolver.queryDocuments(createdCollection.selfLink(), query, options); + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(2) + .exactlyContainsInAnyOrder(expectedIds).build(); + validateQuerySuccess(queryObservable, validator, 10000); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void readChangeFeedWithAllPermission(ConnectionMode connectionMode) throws InterruptedException { + + //setStartDateTime is not currently supported in multimaster mode. So skipping the test + if(BridgeInternal.isEnableMultipleWriteLocations(client.getDatabaseAccount().single().block())){ + throw new SkipException("StartTime/IfModifiedSince is not currently supported when EnableMultipleWriteLocations is set"); + } + + AsyncDocumentClient asyncClientWithTokenResolver = null; + String id1 = UUID.randomUUID().toString(); + String id2 = UUID.randomUUID().toString(); + String partitionKey = createdCollection.getPartitionKey().paths().get(0).substring(1); + String partitionKeyValue = "pk"; + Document document1 = new Document(); + document1.id(id1); + BridgeInternal.setProperty(document1, partitionKey, partitionKeyValue); + Document document2 = new Document(); + document2.id(id2); + BridgeInternal.setProperty(document2, partitionKey, partitionKeyValue); + try { + asyncClientWithTokenResolver = buildClient(connectionMode, PermissionMode.ALL); + OffsetDateTime befTime = OffsetDateTime.now(); + Thread.sleep(1000); + + document1 = asyncClientWithTokenResolver + .createDocument(createdCollection.selfLink(), document1, null, false).single().block() + .getResource(); + document2 = asyncClientWithTokenResolver + .createDocument(createdCollection.selfLink(), document2, null, false).single().block() + .getResource(); + List expectedIds = new ArrayList(); + String rid1 = document1.resourceId(); + String rid2 = document2.resourceId(); + expectedIds.add(rid1); + expectedIds.add(rid2); + + ChangeFeedOptions options = new ChangeFeedOptions(); + options.partitionKey(new PartitionKey(partitionKeyValue)); + options.startDateTime(befTime); + + Thread.sleep(1000); + Flux> queryObservable = asyncClientWithTokenResolver + .queryDocumentChangeFeed(createdCollection.selfLink(), options); + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .exactlyContainsInAnyOrder(expectedIds).build(); + validateQuerySuccess(queryObservable, validator, 10000); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void verifyRuntimeExceptionWhenUserModifiesProperties(ConnectionMode connectionMode) { + AsyncDocumentClient asyncClientWithTokenResolver = null; + + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(connectionMode); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getBadTokenResolver()) + .build(); + + RequestOptions options = new RequestOptions(); + options.setProperties(new HashMap()); + Flux> readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), options); + FailureValidator validator = new FailureValidator.Builder().withRuntimeExceptionClass(UnsupportedOperationException.class).build(); + validateFailure(readObservable, validator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @Test(groups = {"simple"}, dataProvider = "connectionMode", timeOut = TIMEOUT) + public void verifyBlockListedUserThrows(ConnectionMode connectionMode) { + String field = "user"; + UserClass blockListedUser = new UserClass("block listed user", 0); + String errorMessage = "block listed user! access denied!"; + + AsyncDocumentClient asyncClientWithTokenResolver = null; + try { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(connectionMode); + asyncClientWithTokenResolver = new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolverWithBlockList(PermissionMode.READ, field, blockListedUser, errorMessage)) + .build(); + + RequestOptions options = new RequestOptions(); + HashMap properties = new HashMap(); + properties.put(field, blockListedUser); + options.setProperties(properties); + Flux> readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), options); + FailureValidator validator = new FailureValidator.Builder().withRuntimeExceptionMessage(errorMessage).build(); + validateFailure(readObservable, validator); + + properties.put(field, new UserClass("valid user", 1)); + options.setProperties(properties); + readObservable = asyncClientWithTokenResolver.readCollection(createdCollection.selfLink(), options); + ResourceResponseValidator sucessValidator = new ResourceResponseValidator.Builder() + .withId(createdCollection.id()).build(); + validateSuccess(readObservable, sucessValidator); + } finally { + safeClose(asyncClientWithTokenResolver); + } + } + + @AfterClass(groups = {"simple"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + client.close(); + } + + private Document getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + Document doc = new Document(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , uuid, uuid)); + return doc; + } + + private AsyncDocumentClient buildClient(ConnectionMode connectionMode, PermissionMode permissionMode) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.connectionMode(connectionMode); + return new AsyncDocumentClient.Builder() + .withServiceEndpoint(TestConfigurations.HOST) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.SESSION) + .withTokenResolver(getTokenResolver(permissionMode)) + .build(); + } + + private static User getUserDefinition() { + User user = new User(); + user.id(UUID.randomUUID().toString()); + return user; + } + + private Permission getPermission(Resource resource, String permissionId, PermissionMode permissionMode) { + Permission permission = new Permission(); + permission.id(permissionId); + permission.setPermissionMode(permissionMode); + permission.setResourceLink(resource.selfLink()); + return permission; + } + + private TokenResolver getTokenResolver(PermissionMode permissionMode) { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + if (permissionMode == null) { + return "invalid"; + } else if (permissionMode.equals(PermissionMode.READ)) { + return readPermission.getToken(); + } else { + return allPermission.getToken(); + } + }; + } + + private TokenResolver getBadTokenResolver() { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + if (resourceType == CosmosResourceType.System) { + return readPermission.getToken(); + } + if (properties != null) { + properties.put("key", "value"); + } + return null; + }; + } + + private TokenResolver getTokenResolverWithBlockList(PermissionMode permissionMode, String field, UserClass blockListedUser, String errorMessage) { + return (String requestVerb, String resourceIdOrFullName, CosmosResourceType resourceType, Map properties) -> { + UserClass currentUser = null; + if (properties != null && properties.get(field) != null) { + currentUser = (UserClass) properties.get(field); + } + + if (resourceType == CosmosResourceType.System) { + return readPermission.getToken(); + } else if (currentUser != null && + !currentUser.userName.equals(blockListedUser.userName) && + currentUser.userId != blockListedUser.userId) { + if (permissionMode.equals(PermissionMode.READ)) { + return readPermission.getToken(); + } else { + return allPermission.getToken(); + } + } else { + throw new RuntimeException(errorMessage); + } + }; + } +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TopQueryTests.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TopQueryTests.java new file mode 100644 index 0000000000000..88910aeb5e35c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TopQueryTests.java @@ -0,0 +1,229 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.RetryAnalyzer; +import com.azure.data.cosmos.internal.Utils.ValueHolder; +import com.azure.data.cosmos.internal.query.TakeContinuationToken; +import io.reactivex.subscribers.TestSubscriber; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TopQueryTests extends TestSuiteBase { + private CosmosContainer createdCollection; + private ArrayList docs = new ArrayList(); + + private String partitionKey = "mypk"; + private int firstPk = 0; + private int secondPk = 1; + private String field = "field"; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public TopQueryTests(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider", retryAnalyzer = RetryAnalyzer.class) + public void queryDocumentsWithTop(boolean qmEnabled) throws Exception { + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + options.maxItemCount(9); + options.maxDegreeOfParallelism(2); + options.populateQueryMetrics(qmEnabled); + + int expectedTotalSize = 20; + int expectedNumberOfPages = 3; + int[] expectedPageLengths = new int[] { 9, 9, 2 }; + + for (int i = 0; i < 2; i++) { + Flux> queryObservable1 = createdCollection.queryItems("SELECT TOP 0 value AVG(c.field) from c", options); + + FeedResponseListValidator validator1 = new FeedResponseListValidator.Builder() + .totalSize(0).build(); + + validateQuerySuccess(queryObservable1, validator1, TIMEOUT); + + Flux> queryObservable2 = createdCollection.queryItems("SELECT TOP 1 value AVG(c.field) from c", options); + + FeedResponseListValidator validator2 = new FeedResponseListValidator.Builder() + .totalSize(1).build(); + + validateQuerySuccess(queryObservable2, validator2, TIMEOUT); + + Flux> queryObservable3 = createdCollection.queryItems("SELECT TOP 20 * from c", options); + + FeedResponseListValidator validator3 = new FeedResponseListValidator.Builder() + .totalSize(expectedTotalSize).numberOfPages(expectedNumberOfPages).pageLengths(expectedPageLengths) + .hasValidQueryMetrics(qmEnabled).build(); + + validateQuerySuccess(queryObservable3, validator3, TIMEOUT); + + if (i == 0) { + options.partitionKey(new PartitionKey(firstPk)); + options.enableCrossPartitionQuery(false); + + expectedTotalSize = 10; + expectedNumberOfPages = 2; + expectedPageLengths = new int[] { 9, 1 }; + + } + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void topContinuationTokenRoundTrips() throws Exception { + { + // Positive + TakeContinuationToken takeContinuationToken = new TakeContinuationToken(42, "asdf"); + String serialized = takeContinuationToken.toString(); + ValueHolder outTakeContinuationToken = new ValueHolder(); + + assertThat(TakeContinuationToken.tryParse(serialized, outTakeContinuationToken)).isTrue(); + TakeContinuationToken deserialized = outTakeContinuationToken.v; + + assertThat(deserialized.getTakeCount()).isEqualTo(42); + assertThat(deserialized.getSourceToken()).isEqualTo("asdf"); + } + + { + // Negative + ValueHolder outTakeContinuationToken = new ValueHolder(); + assertThat( + TakeContinuationToken.tryParse("{\"property\": \"Not a valid token\"}", outTakeContinuationToken)) + .isFalse(); + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 10, retryAnalyzer = RetryAnalyzer.class) + public void queryDocumentsWithTopContinuationTokens() throws Exception { + String query = "SELECT TOP 8 * FROM c"; + this.queryWithContinuationTokensAndPageSizes(query, new int[] { 1, 5, 10 }, 8); + } + + private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, int topCount) { + for (int pageSize : pageSizes) { + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + Set actualIds = new HashSet(); + for (CosmosItemProperties document : receivedDocuments) { + actualIds.add(document.resourceId()); + } + + assertThat(actualIds.size()).describedAs("total number of results").isEqualTo(topCount); + } + } + + private List queryWithContinuationTokens(String query, int pageSize) { + String requestContinuation = null; + List continuationTokens = new ArrayList(); + List receivedDocuments = new ArrayList(); + + do { + FeedOptions options = new FeedOptions(); + options.maxItemCount(pageSize); + options.enableCrossPartitionQuery(true); + options.maxDegreeOfParallelism(2); + options.requestContinuation(requestContinuation); + Flux> queryObservable = createdCollection.queryItems(query, options); + + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); + requestContinuation = firstPage.continuationToken(); + receivedDocuments.addAll(firstPage.results()); + continuationTokens.add(requestContinuation); + } while (requestContinuation != null); + + return receivedDocuments; + } + + public void bulkInsert(CosmosClient client) { + generateTestData(); + + for (int i = 0; i < docs.size(); i++) { + createDocument(createdCollection, docs.get(i)); + } + } + + public void generateTestData() { + + for (int i = 0; i < 10; i++) { + CosmosItemProperties d = new CosmosItemProperties(); + d.id(Integer.toString(i)); + BridgeInternal.setProperty(d, field, i); + BridgeInternal.setProperty(d, partitionKey, firstPk); + docs.add(d); + } + + for (int i = 10; i < 20; i++) { + CosmosItemProperties d = new CosmosItemProperties(); + d.id(Integer.toString(i)); + BridgeInternal.setProperty(d, field, i); + BridgeInternal.setProperty(d, partitionKey, secondPk); + docs.add(d); + } + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); + + bulkInsert(client); + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerCrudTest.java new file mode 100644 index 0000000000000..f152077f4d19a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerCrudTest.java @@ -0,0 +1,129 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosTrigger; +import com.azure.data.cosmos.CosmosTriggerProperties; +import com.azure.data.cosmos.CosmosTriggerResponse; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +public class TriggerCrudTest extends TestSuiteBase { + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public TriggerCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 100) + public void createTrigger() throws Exception { + + // create a trigger + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + + Mono createObservable = createdCollection.getScripts().createTrigger(trigger); + + // validate trigger creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(trigger.id()) + .withTriggerBody("function() {var x = 10;}") + .withTriggerInternals(TriggerType.PRE, TriggerOperation.CREATE) + .notNullEtag() + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readTrigger() throws Exception { + // create a trigger + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + CosmosTrigger readBackTrigger = createdCollection.getScripts().createTrigger(trigger).block().trigger(); + + // read trigger + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = readBackTrigger.read(); + + // validate read trigger + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(trigger.id()) + .withTriggerBody("function() {var x = 10;}") + .withTriggerInternals(TriggerType.PRE, TriggerOperation.CREATE) + .notNullEtag() + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void deleteTrigger() throws Exception { + // create a trigger + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + CosmosTrigger readBackTrigger = createdCollection.getScripts().createTrigger(trigger).block().trigger(); + + // delete trigger + Mono deleteObservable = readBackTrigger.delete(); + + // validate delete trigger + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource() + .build(); + validateSuccess(deleteObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerQueryTest.java new file mode 100644 index 0000000000000..f0fd9b6785f0c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerQueryTest.java @@ -0,0 +1,184 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosTriggerProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.Resource; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TriggerQueryTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private static final List createdTriggers = new ArrayList<>(); + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public TriggerQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryWithFilter() throws Exception { + + String filterId = createdTriggers.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + Flux> queryObservable = createdCollection.getScripts().queryTriggers(query, options); + + List expectedDocs = createdTriggers + .stream() + .filter(sp -> filterId.equals(sp.id()) ) + .collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(Resource::resourceId).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void query_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryTriggers(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAll() throws Exception { + + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(3); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryTriggers(query, options); + + createdTriggers.forEach(cosmosTriggerSettings -> logger.info("Created trigger in method: {}", cosmosTriggerSettings.resourceId())); + + List expectedDocs = createdTriggers; + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .exactlyContainsInAnyOrder(expectedDocs + .stream() + .map(Resource::resourceId) + .collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySytax() throws Exception { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryTriggers(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .notNullActivityId() + .build(); + validateQueryFailure(queryObservable, validator); + } + + public CosmosTriggerProperties createTrigger(CosmosContainer cosmosContainer) { + CosmosTriggerProperties storedProcedure = getTriggerDef(); + return cosmosContainer.getScripts().createTrigger(storedProcedure).block().properties(); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + createdTriggers.clear(); + + for(int i = 0; i < 5; i++) { + createdTriggers.add(createTrigger(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosTriggerProperties getTriggerDef() { + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + return trigger; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerUpsertReplaceTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerUpsertReplaceTest.java new file mode 100644 index 0000000000000..39f0c0addc345 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/TriggerUpsertReplaceTest.java @@ -0,0 +1,102 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosTriggerProperties; +import com.azure.data.cosmos.CosmosTriggerResponse; +import com.azure.data.cosmos.TriggerOperation; +import com.azure.data.cosmos.TriggerType; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +public class TriggerUpsertReplaceTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public TriggerUpsertReplaceTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void replaceTrigger() throws Exception { + + // create a trigger + CosmosTriggerProperties trigger = new CosmosTriggerProperties(); + trigger.id(UUID.randomUUID().toString()); + trigger.body("function() {var x = 10;}"); + trigger.triggerOperation(TriggerOperation.CREATE); + trigger.triggerType(TriggerType.PRE); + CosmosTriggerProperties readBackTrigger = createdCollection.getScripts().createTrigger(trigger).block().properties(); + + // read trigger to validate creation + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = createdCollection.getScripts().getTrigger(readBackTrigger.id()).read(); + + // validate trigger creation + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() + .withId(readBackTrigger.id()) + .withTriggerBody("function() {var x = 10;}") + .withTriggerInternals(TriggerType.PRE, TriggerOperation.CREATE) + .notNullEtag() + .build(); + validateSuccess(readObservable, validatorForRead); + + //update trigger + readBackTrigger.body("function() {var x = 11;}"); + + Mono updateObservable = createdCollection.getScripts().getTrigger(readBackTrigger.id()).replace(readBackTrigger); + + // validate trigger replace + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() + .withId(readBackTrigger.id()) + .withTriggerBody("function() {var x = 11;}") + .withTriggerInternals(TriggerType.PRE, TriggerOperation.CREATE) + .notNullEtag() + .build(); + validateSuccess(updateObservable, validatorForUpdate); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UniqueIndexTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UniqueIndexTest.java new file mode 100644 index 0000000000000..1fcd0f8497509 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UniqueIndexTest.java @@ -0,0 +1,247 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.ConnectionPolicy; +import com.azure.data.cosmos.ConsistencyLevel; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosContainerProperties; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosItem; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.DataType; +import com.azure.data.cosmos.ExcludedPath; +import com.azure.data.cosmos.HashIndex; +import com.azure.data.cosmos.IncludedPath; +import com.azure.data.cosmos.IndexingMode; +import com.azure.data.cosmos.IndexingPolicy; +import com.azure.data.cosmos.PartitionKey; +import com.azure.data.cosmos.PartitionKeyDefinition; +import com.azure.data.cosmos.UniqueKey; +import com.azure.data.cosmos.UniqueKeyPolicy; +import com.azure.data.cosmos.internal.HttpConstants; +import com.azure.data.cosmos.internal.TestConfigurations; +import com.azure.data.cosmos.internal.TestUtils; +import com.azure.data.cosmos.internal.Utils; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +public class UniqueIndexTest extends TestSuiteBase { + protected static final int TIMEOUT = 30000; + protected static final int SETUP_TIMEOUT = 20000; + protected static final int SHUTDOWN_TIMEOUT = 20000; + + private final String databaseId = CosmosDatabaseForTest.generateId(); + private CosmosClient client; + private CosmosDatabase database; + + private CosmosContainer collection; + + @Test(groups = { "long" }, timeOut = TIMEOUT) + public void insertWithUniqueIndex() throws Exception { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); + UniqueKey uniqueKey = new UniqueKey(); + uniqueKey.paths(ImmutableList.of("/name", "/description")); + uniqueKeyPolicy.uniqueKeys(Lists.newArrayList(uniqueKey)); + collectionDefinition.uniqueKeyPolicy(uniqueKeyPolicy); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + indexingPolicy.indexingMode(IndexingMode.CONSISTENT); + ExcludedPath excludedPath = new ExcludedPath(); + excludedPath.path("/*"); + indexingPolicy.excludedPaths(Collections.singletonList(excludedPath)); + + IncludedPath includedPath1 = new IncludedPath(); + includedPath1.path("/name/?"); + includedPath1.indexes(Collections.singletonList(new HashIndex(DataType.STRING, 7))); + + IncludedPath includedPath2 = new IncludedPath(); + includedPath2.path("/description/?"); + includedPath2.indexes(Collections.singletonList(new HashIndex(DataType.STRING, 7))); + indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); + collectionDefinition.indexingPolicy(indexingPolicy); + + ObjectMapper om = new ObjectMapper(); + + JsonNode doc1 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", JsonNode.class); + JsonNode doc2 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"playwright\",\"id\": \"" + UUID.randomUUID().toString() + "\"}", JsonNode.class); + JsonNode doc3 = om.readValue("{\"name\":\"حافظ شیرازی\",\"description\":\"poet\",\"id\": \"" + UUID.randomUUID().toString() + "\"}", JsonNode.class); + + collection = database.createContainer(collectionDefinition).block().container(); + + CosmosItem item = collection.createItem(doc1).block().item(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.partitionKey(PartitionKey.None); + CosmosItemProperties itemSettings = item.read(options).block().properties(); + assertThat(itemSettings.id()).isEqualTo(doc1.get("id").textValue()); + + try { + collection.createItem(doc1).block(); + fail("Did not throw due to unique constraint (create)"); + } catch (RuntimeException e) { + assertThat(getDocumentClientException(e).statusCode()).isEqualTo(HttpConstants.StatusCodes.CONFLICT); + } + + collection.createItem(doc2).block(); + collection.createItem(doc3).block(); + } + + @Test(groups = { "long" }, timeOut = TIMEOUT * 1000) + public void replaceAndDeleteWithUniqueIndex() throws Exception { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); + UniqueKey uniqueKey = new UniqueKey(); + uniqueKey.paths(ImmutableList.of("/name", "/description")); + uniqueKeyPolicy.uniqueKeys(Lists.newArrayList(uniqueKey)); + collectionDefinition.uniqueKeyPolicy(uniqueKeyPolicy); + + collection = database.createContainer(collectionDefinition).block().container(); + + ObjectMapper om = new ObjectMapper(); + + ObjectNode doc1 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); + ObjectNode doc3 = om.readValue("{\"name\":\"Rabindranath Tagore\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); + ObjectNode doc2 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"mathematician\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); + + CosmosItemProperties doc1Inserted = collection.createItem(doc1, new CosmosItemRequestOptions()).block().properties(); + + collection.getItem(doc1.get("id").asText(), PartitionKey.None).replace(doc1Inserted, new CosmosItemRequestOptions()).block().properties(); // REPLACE with same values -- OK. + + CosmosItemProperties doc2Inserted = collection.createItem(doc2, new CosmosItemRequestOptions()).block().properties(); + CosmosItemProperties doc2Replacement = new CosmosItemProperties(doc1Inserted.toJson()); + doc2Replacement.id( doc2Inserted.id()); + + try { + collection.getItem(doc2Inserted.id(), PartitionKey.None).replace(doc2Replacement, new CosmosItemRequestOptions()).block(); // REPLACE doc2 with values from doc1 -- Conflict. + fail("Did not throw due to unique constraint"); + } + catch (RuntimeException ex) { + assertThat(getDocumentClientException(ex).statusCode()).isEqualTo(HttpConstants.StatusCodes.CONFLICT); + } + + doc3.put("id", doc1Inserted.id()); + collection.getItem(doc1Inserted.id(), PartitionKey.None).replace(doc3).block(); // REPLACE with values from doc3 -- OK. + + collection.getItem(doc1Inserted.id(), PartitionKey.None).delete().block(); + collection.createItem(doc1, new CosmosItemRequestOptions()).block(); + } + + @Test(groups = { "long" }, timeOut = TIMEOUT) + public void uniqueKeySerializationDeserialization() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.paths(paths); + + CosmosContainerProperties collectionDefinition = new CosmosContainerProperties(UUID.randomUUID().toString(), partitionKeyDef); + UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); + UniqueKey uniqueKey = new UniqueKey(); + uniqueKey.paths(ImmutableList.of("/name", "/description")); + uniqueKeyPolicy.uniqueKeys(Lists.newArrayList(uniqueKey)); + collectionDefinition.uniqueKeyPolicy(uniqueKeyPolicy); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + indexingPolicy.indexingMode(IndexingMode.CONSISTENT); + ExcludedPath excludedPath = new ExcludedPath(); + excludedPath.path("/*"); + indexingPolicy.excludedPaths(Collections.singletonList(excludedPath)); + + IncludedPath includedPath1 = new IncludedPath(); + includedPath1.path("/name/?"); + includedPath1.indexes(Collections.singletonList(new HashIndex(DataType.STRING, 7))); + + IncludedPath includedPath2 = new IncludedPath(); + includedPath2.path("/description/?"); + includedPath2.indexes(Collections.singletonList(new HashIndex(DataType.STRING, 7))); + indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); + + collectionDefinition.indexingPolicy(indexingPolicy); + + CosmosContainer createdCollection = database.createContainer(collectionDefinition).block().container(); + + CosmosContainerProperties collection = createdCollection.read().block().properties(); + + assertThat(collection.uniqueKeyPolicy()).isNotNull(); + assertThat(collection.uniqueKeyPolicy().uniqueKeys()).isNotNull(); + assertThat(collection.uniqueKeyPolicy().uniqueKeys()) + .hasSameSizeAs(collectionDefinition.uniqueKeyPolicy().uniqueKeys()); + assertThat(collection.uniqueKeyPolicy().uniqueKeys() + .stream().map(ui -> ui.paths()).collect(Collectors.toList())) + .containsExactlyElementsOf( + ImmutableList.of(ImmutableList.of("/name", "/description"))); + } + + private CosmosClientException getDocumentClientException(RuntimeException e) { + CosmosClientException dce = Utils.as(e.getCause(), CosmosClientException.class); + assertThat(dce).isNotNull(); + return dce; + } + + @BeforeClass(groups = { "long" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + // set up the client + client = CosmosClient.builder() + .endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(ConnectionPolicy.defaultPolicy()) + .consistencyLevel(ConsistencyLevel.SESSION).build(); + + database = createDatabase(client, databaseId); + } + + @AfterClass(groups = { "long" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(database); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserCrudTest.java new file mode 100644 index 0000000000000..61f47f895a7af --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserCrudTest.java @@ -0,0 +1,180 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosUser; +import com.azure.data.cosmos.CosmosUserResponse; +import com.azure.data.cosmos.CosmosUserProperties; +import com.azure.data.cosmos.internal.FailureValidator; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +public class UserCrudTest extends TestSuiteBase { + + public final String databaseId = CosmosDatabaseForTest.generateId(); + + private CosmosDatabase createdDatabase; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuilders") + public UserCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createUser() throws Exception { + //create user + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + + Mono createObservable = createdDatabase.createUser(user); + + // validate user creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(user.id()) + .notNullEtag() + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void readUser() throws Exception { + + //create user + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + + CosmosUser readBackUser = createdDatabase.createUser(user).block().user(); + + // read user + Mono readObservable = readBackUser.read(); + + //validate user read + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(readBackUser.id()) + .notNullEtag() + .build(); + + validateSuccess(readObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void deleteUser() throws Exception { + //create user + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + + CosmosUser readBackUser = createdDatabase.createUser(user).block().user(); + + // delete user + Mono deleteObservable = readBackUser.delete(); + + // validate user delete + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource() + .build(); + validateSuccess(deleteObservable, validator); + + // attempt to read the user which was deleted + Mono readObservable = readBackUser.read(); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void upsertUser() throws Exception { + + //create user + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + + Mono upsertObservable = createdDatabase.upsertUser(user); + + //validate user upsert + CosmosResponseValidator validatorForUpsert = new CosmosResponseValidator.Builder() + .withId(user.id()) + .notNullEtag() + .build(); + + validateSuccess(upsertObservable, validatorForUpsert); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void replaceUser() throws Exception { + + //create user + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + + CosmosUserProperties readBackUser = createdDatabase.createUser(user).block().properties(); + + // read user to validate creation + Mono readObservable = createdDatabase.getUser(user.id()).read(); + + //validate user read + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() + .withId(readBackUser.id()) + .notNullEtag() + .build(); + + validateSuccess(readObservable, validatorForRead); + + //update user + String oldId = readBackUser.id(); + readBackUser.id(UUID.randomUUID().toString()); + + Mono updateObservable = createdDatabase.getUser(oldId).replace(readBackUser); + + // validate user replace + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() + .withId(readBackUser.id()) + .notNullEtag() + .build(); + + validateSuccess(updateObservable, validatorForUpdate); + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdDatabase = createDatabase(client, databaseId); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionCrudTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionCrudTest.java new file mode 100644 index 0000000000000..d00e74ac9f499 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionCrudTest.java @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponse; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosUserDefinedFunction; +import com.azure.data.cosmos.CosmosUserDefinedFunctionProperties; +import com.azure.data.cosmos.CosmosUserDefinedFunctionResponse; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +public class UserDefinedFunctionCrudTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public UserDefinedFunctionCrudTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void createUserDefinedFunction() throws Exception { + // create udf + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + + Mono createObservable = createdCollection.getScripts().createUserDefinedFunction(udf); + + // validate udf creation + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(udf.id()) + .withUserDefinedFunctionBody("function() {var x = 10;}") + .notNullEtag() + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void readUserDefinedFunction() throws Exception { + // create a udf + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + CosmosUserDefinedFunction readBackUdf = createdCollection.getScripts().createUserDefinedFunction(udf).block().userDefinedFunction(); + + // read udf + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = readBackUdf.read(); + + //validate udf read + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(udf.id()) + .withUserDefinedFunctionBody("function() {var x = 10;}") + .notNullEtag() + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void deleteUserDefinedFunction() throws Exception { + // create a udf + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + CosmosUserDefinedFunction readBackUdf = createdCollection.getScripts().createUserDefinedFunction(udf).block().userDefinedFunction(); + + // delete udf + Mono deleteObservable = readBackUdf.delete(); + + // validate udf delete + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource() + .build(); + validateSuccess(deleteObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionQueryTest.java new file mode 100644 index 0000000000000..b77d030affd43 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionQueryTest.java @@ -0,0 +1,180 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosClientException; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosUserDefinedFunctionProperties; +import com.azure.data.cosmos.internal.Database; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FailureValidator; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import com.azure.data.cosmos.internal.TestUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UserDefinedFunctionQueryTest extends TestSuiteBase { + + private Database createdDatabase; + private CosmosContainer createdCollection; + private List createdUDF = new ArrayList<>(); + + private CosmosClient client; + + public String getCollectionLink() { + return TestUtils.getCollectionNameLink(createdDatabase.id(), createdCollection.id()); + } + + @Factory(dataProvider = "clientBuildersWithDirect") + public UserDefinedFunctionQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryWithFilter() throws Exception { + + String filterId = createdUDF.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + Flux> queryObservable = createdCollection.getScripts().queryUserDefinedFunctions(query, options); + + List expectedDocs = createdUDF.stream().filter(sp -> filterId.equals(sp.id()) ).collect(Collectors.toList()); + assertThat(expectedDocs).isNotEmpty(); + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedDocs.size()) + .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void query_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryUserDefinedFunctions(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAll() throws Exception { + + String query = "SELECT * from root"; + FeedOptions options = new FeedOptions(); + options.maxItemCount(3); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryUserDefinedFunctions(query, options); + + List expectedDocs = createdUDF; + + int expectedPageSize = (expectedDocs.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() + .exactlyContainsInAnyOrder(expectedDocs + .stream() + .map(d -> d.resourceId()) + .collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .allPagesSatisfy(new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void invalidQuerySytax() throws Exception { + String query = "I am an invalid query"; + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.getScripts().queryUserDefinedFunctions(query, options); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(CosmosClientException.class) + .statusCode(400) + .notNullActivityId() + .build(); + validateQueryFailure(queryObservable, validator); + } + + public CosmosUserDefinedFunctionProperties createUserDefinedFunction(CosmosContainer cosmosContainer) { + CosmosUserDefinedFunctionProperties storedProcedure = getUserDefinedFunctionDef(); + return cosmosContainer.getScripts().createUserDefinedFunction(storedProcedure).block().properties(); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + + for(int i = 0; i < 5; i++) { + createdUDF.add(createUserDefinedFunction(createdCollection)); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosUserDefinedFunctionProperties getUserDefinedFunctionDef() { + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + return udf; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionUpsertReplaceTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionUpsertReplaceTest.java new file mode 100644 index 0000000000000..3f18c39be096f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserDefinedFunctionUpsertReplaceTest.java @@ -0,0 +1,99 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosResponseValidator; +import com.azure.data.cosmos.CosmosUserDefinedFunctionProperties; +import com.azure.data.cosmos.CosmosUserDefinedFunctionResponse; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +public class UserDefinedFunctionUpsertReplaceTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public UserDefinedFunctionUpsertReplaceTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void replaceUserDefinedFunction() throws Exception { + + // create a udf + CosmosUserDefinedFunctionProperties udf = new CosmosUserDefinedFunctionProperties(); + udf.id(UUID.randomUUID().toString()); + udf.body("function() {var x = 10;}"); + + CosmosUserDefinedFunctionProperties readBackUdf = null; + + readBackUdf = createdCollection.getScripts().createUserDefinedFunction(udf).block().properties(); + + // read udf to validate creation + waitIfNeededForReplicasToCatchUp(clientBuilder()); + Mono readObservable = createdCollection.getScripts().getUserDefinedFunction(readBackUdf.id()).read(); + + // validate udf creation + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() + .withId(readBackUdf.id()) + .withUserDefinedFunctionBody("function() {var x = 10;}") + .notNullEtag() + .build(); + validateSuccess(readObservable, validatorForRead); + + //update udf + readBackUdf.body("function() {var x = 11;}"); + + Mono replaceObservable = createdCollection.getScripts().getUserDefinedFunction(readBackUdf.id()).replace(readBackUdf); + + //validate udf replace + CosmosResponseValidator validatorForReplace = new CosmosResponseValidator.Builder() + .withId(readBackUdf.id()) + .withUserDefinedFunctionBody("function() {var x = 11;}") + .notNullEtag() + .build(); + validateSuccess(replaceObservable, validatorForReplace); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserQueryTest.java new file mode 100644 index 0000000000000..3845c32f4db0f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/UserQueryTest.java @@ -0,0 +1,154 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosDatabase; +import com.azure.data.cosmos.CosmosDatabaseForTest; +import com.azure.data.cosmos.CosmosUserProperties; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import com.azure.data.cosmos.internal.FeedResponseListValidator; +import com.azure.data.cosmos.internal.FeedResponseValidator; +import com.azure.data.cosmos.internal.TestUtils; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; + +public class UserQueryTest extends TestSuiteBase { + + public final String databaseId = CosmosDatabaseForTest.generateId(); + + private List createdUsers = new ArrayList<>(); + + private CosmosClient client; + private CosmosDatabase createdDatabase; + + @Factory(dataProvider = "clientBuilders") + public UserQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryUsersWithFilter() throws Exception { + + String filterUserId = createdUsers.get(0).id(); + String query = String.format("SELECT * from c where c.id = '%s'", filterUserId); + + FeedOptions options = new FeedOptions(); + options.maxItemCount(5); + Flux> queryObservable = createdDatabase.queryUsers(query, options); + + List expectedUsers = createdUsers.stream() + .filter(c -> StringUtils.equals(filterUserId, c.id()) ).collect(Collectors.toList()); + + assertThat(expectedUsers).isNotEmpty(); + + int expectedPageSize = (expectedUsers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedUsers.size()) + .exactlyContainsInAnyOrder(expectedUsers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryAllUsers() throws Exception { + + String query = "SELECT * from c"; + + FeedOptions options = new FeedOptions(); + options.maxItemCount(2); + String databaseLink = TestUtils.getDatabaseNameLink(databaseId); + Flux> queryObservable = createdDatabase.queryUsers(query, options); + + List expectedUsers = createdUsers; + + assertThat(expectedUsers).isNotEmpty(); + + int expectedPageSize = (expectedUsers.size() + options.maxItemCount() - 1) / options.maxItemCount(); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .totalSize(expectedUsers.size()) + .exactlyContainsInAnyOrder(expectedUsers.stream().map(d -> d.resourceId()).collect(Collectors.toList())) + .numberOfPages(expectedPageSize) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + + validateQuerySuccess(queryObservable, validator, 10000); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT) + public void queryUsers_NoResults() throws Exception { + + String query = "SELECT * from root r where r.id = '2'"; + FeedOptions options = new FeedOptions(); + Flux> queryObservable = createdDatabase.queryUsers(query, options); + + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + .containsExactly(new ArrayList<>()) + .numberOfPages(1) + .pageSatisfy(0, new FeedResponseValidator.Builder() + .requestChargeGreaterThanOrEqualTo(1.0).build()) + .build(); + validateQuerySuccess(queryObservable, validator); + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws Exception { + client = clientBuilder().build(); + + createdDatabase = createDatabase(client, databaseId); + + for(int i = 0; i < 5; i++) { + CosmosUserProperties user = new CosmosUserProperties(); + user.id(UUID.randomUUID().toString()); + createdUsers.add(createUser(client, databaseId, user).read().block().properties()); + } + + waitIfNeededForReplicasToCatchUp(clientBuilder()); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/VeryLargeDocumentQueryTest.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/VeryLargeDocumentQueryTest.java new file mode 100644 index 0000000000000..5e69089374d64 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/VeryLargeDocumentQueryTest.java @@ -0,0 +1,125 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx; + +import com.azure.data.cosmos.BridgeInternal; +import com.azure.data.cosmos.CosmosClient; +import com.azure.data.cosmos.CosmosClientBuilder; +import com.azure.data.cosmos.CosmosContainer; +import com.azure.data.cosmos.CosmosItemProperties; +import com.azure.data.cosmos.CosmosItemRequestOptions; +import com.azure.data.cosmos.CosmosItemResponse; +import com.azure.data.cosmos.FeedOptions; +import com.azure.data.cosmos.FeedResponse; +import org.apache.commons.lang3.StringUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import reactor.test.StepVerifier; + +import java.time.Duration; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.apache.commons.io.FileUtils.ONE_MB; + +public class VeryLargeDocumentQueryTest extends TestSuiteBase { + + private final static int TIMEOUT = 60000; + private final static int SETUP_TIMEOUT = 60000; + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "simpleClientBuildersWithDirect") + public VeryLargeDocumentQueryTest(CosmosClientBuilder clientBuilder) { + super(clientBuilder); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void queryLargeDocuments() { + + int cnt = 5; + + for(int i = 0; i < cnt; i++) { + createLargeDocument(); + } + + FeedOptions options = new FeedOptions(); + options.enableCrossPartitionQuery(true); + + Flux> feedResponseFlux = createdCollection.queryItems("SELECT * FROM r", + options); + + AtomicInteger totalCount = new AtomicInteger(); + StepVerifier.create(feedResponseFlux.subscribeOn(Schedulers.single())) + .thenConsumeWhile(feedResponse -> { + int size = feedResponse.results().size(); + totalCount.addAndGet(size); + return true; + }) + .expectComplete() + .verify(Duration.ofMillis(subscriberValidationTimeout)); + } + + private void createLargeDocument() { + CosmosItemProperties docDefinition = getDocumentDefinition(); + + //Keep size as ~ 1.999MB to account for size of other props + int size = (int) (ONE_MB * 1.999); + BridgeInternal.setProperty(docDefinition, "largeString", StringUtils.repeat("x", size)); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + + StepVerifier.create(createObservable.subscribeOn(Schedulers.single())) + .expectNextMatches(cosmosItemResponse -> cosmosItemResponse.properties().id().equals(docDefinition.id())) + .expectComplete() + .verify(Duration.ofMillis(subscriberValidationTimeout)); + } + + @BeforeClass(groups = { "emulator" }, timeOut = 2 * SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder().build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + private static CosmosItemProperties getDocumentDefinition() { + String uuid = UUID.randomUUID().toString(); + CosmosItemProperties doc = new CosmosItemProperties(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "}" + , uuid, uuid)); + return doc; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyChannelInitializer.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyChannelInitializer.java new file mode 100644 index 0000000000000..bb3973d0ab3d3 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyChannelInitializer.java @@ -0,0 +1,48 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.proxy; + +import io.netty.channel.ChannelInitializer; +import io.netty.channel.socket.SocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.atomic.AtomicLong; + +/** + * The channel initializer. + * + */ +public class HttpProxyChannelInitializer extends ChannelInitializer { + private final Logger logger = LoggerFactory.getLogger(HttpProxyChannelInitializer.class); + private AtomicLong taskCounter = new AtomicLong(); + private HttpProxyClientHandler httpProxyClientHandler; + + @Override + protected void initChannel(SocketChannel ch) throws Exception { + httpProxyClientHandler = new HttpProxyClientHandler("task-" + taskCounter.getAndIncrement()); + logger.info("task-" + taskCounter.getAndIncrement()); + ch.pipeline().addLast(httpProxyClientHandler); + } + +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHandler.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHandler.java new file mode 100644 index 0000000000000..a1edfb573dadb --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHandler.java @@ -0,0 +1,116 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.proxy; + +import io.netty.bootstrap.Bootstrap; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handle data from client. + * + */ +public class HttpProxyClientHandler extends ChannelInboundHandlerAdapter { + private final Logger logger = LoggerFactory.getLogger(HttpProxyClientHandler.class); + private final String id; + private Channel clientChannel; + private Channel remoteChannel; + private HttpProxyClientHeader header ; + public HttpProxyClientHandler(String id) { + this.id = id; + header = new HttpProxyClientHeader(); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + clientChannel = ctx.channel(); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (header.isComplete()) { + remoteChannel.writeAndFlush(msg); // just forward + return; + } + + ByteBuf in = (ByteBuf) msg; + header.digest(in); + + if (!header.isComplete()) { + in.release(); + return; + } + + logger.info(id + " {}", header); + clientChannel.config().setAutoRead(false); // disable AutoRead until remote connection is ready + + if (header.isHttps()) { // if https, respond 200 to create tunnel + clientChannel.writeAndFlush(Unpooled.wrappedBuffer("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes())); + } + + Bootstrap b = new Bootstrap(); + b.group(clientChannel.eventLoop()) // use the same EventLoop + .channel(clientChannel.getClass()) + .handler(new HttpProxyRemoteHandler(id, clientChannel)); + ChannelFuture f = b.connect(header.getHost(), header.getPort()); + remoteChannel = f.channel(); + + f.addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + clientChannel.config().setAutoRead(true); // connection is ready, enable AutoRead + if (!header.isHttps()) { // forward header and remaining bytes + remoteChannel.write(header.getByteBuf()); + } + + remoteChannel.writeAndFlush(in); + } else { + in.release(); + clientChannel.close(); + } + }); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + flushAndClose(remoteChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { + logger.error(id + " error occured", e); + flushAndClose(clientChannel); + } + + private void flushAndClose(Channel ch) { + if (ch != null && ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHeader.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHeader.java new file mode 100644 index 0000000000000..f58c47cc23d55 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyClientHeader.java @@ -0,0 +1,149 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.proxy; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +/** + * The http header of client. + * + */ +public class HttpProxyClientHeader { + private String method; + private String host; + private int port; + private boolean https; + private boolean complete; + private ByteBuf byteBuf = Unpooled.buffer(); + + private final StringBuilder lineBuf = new StringBuilder(); + + public boolean isComplete() { + return complete; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isHttps() { + return https; + } + + public void setHttps(boolean https) { + this.https = https; + } + + public ByteBuf getByteBuf() { + return byteBuf; + } + + public void setByteBuf(ByteBuf byteBuf) { + this.byteBuf = byteBuf; + } + + public StringBuilder getLineBuf() { + return lineBuf; + } + + public void setComplete(boolean complete) { + this.complete = complete; + } + + public void digest(ByteBuf in) { + while (in.isReadable()) { + if (complete) { + throw new IllegalStateException("already complete"); + } + + String line = readLine(in); + if (line == null) { + return; + } + + if (method == null) { + method = line.split(" ")[0]; // the first word is http method name + https = method.equalsIgnoreCase("CONNECT"); // method CONNECT means https + } + + if (line.startsWith("Host: ") || line.startsWith("host: ")) { + String[] arr = line.split(":"); + host = arr[1].trim(); + if (arr.length == 3) { + port = Integer.parseInt(arr[2]); + } else if (https) { + port = 443; // https + } else { + port = 80; // http + } + } + + if (line.isEmpty()) { + if (host == null || port == 0) { + throw new IllegalStateException("cannot find header \'Host\'"); + } + + byteBuf = byteBuf.asReadOnly(); + complete = true; + break; + } + } + } + + private String readLine(ByteBuf in) { + while (in.isReadable()) { + byte b = in.readByte(); + byteBuf.writeByte(b); + lineBuf.append((char) b); + int len = lineBuf.length(); + if (len >= 2 && lineBuf.substring(len - 2).equals("\r\n")) { + String line = lineBuf.substring(0, len - 2); + lineBuf.delete(0, len); + return line; + } + + } + return null; + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyRemoteHandler.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyRemoteHandler.java new file mode 100644 index 0000000000000..7424ae3c25a2a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyRemoteHandler.java @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.proxy; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Handle data from remote. + * + */ +public class HttpProxyRemoteHandler extends ChannelInboundHandlerAdapter { + private final Logger logger = LoggerFactory.getLogger(HttpProxyRemoteHandler.class); + private final String id; + private Channel clientChannel; + private Channel remoteChannel; + + public HttpProxyRemoteHandler(String id, Channel clientChannel) { + this.id = id; + this.clientChannel = clientChannel; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + this.remoteChannel = ctx.channel(); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + clientChannel.writeAndFlush(msg); // just forward + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + flushAndClose(clientChannel); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) { + logger.error(id + " error occured", e); + flushAndClose(remoteChannel); + } + + private void flushAndClose(Channel ch) { + if (ch != null && ch.isActive()) { + ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyServer.java b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyServer.java new file mode 100644 index 0000000000000..be33ef88ffce4 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/java/com/azure/data/cosmos/rx/proxy/HttpProxyServer.java @@ -0,0 +1,71 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.azure.data.cosmos.rx.proxy; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A http proxy server. + * + */ +public class HttpProxyServer { + private final Logger logger = LoggerFactory.getLogger(HttpProxyServer.class); + private HttpProxyChannelInitializer httpProxyChannelInitializer; + private int port = 8080; + EventLoopGroup bossGroup; + EventLoopGroup workerGroup; + public HttpProxyServer() { + bossGroup = new NioEventLoopGroup(1); + workerGroup = new NioEventLoopGroup(); + } + + public void start() { + new Thread(() -> { + logger.info("HttpProxyServer started on port: {}", port); + httpProxyChannelInitializer = new HttpProxyChannelInitializer(); + try { + ServerBootstrap bootstrap = new ServerBootstrap(); + bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) + .childHandler(httpProxyChannelInitializer) + .bind(port).sync().channel().closeFuture().sync(); + } catch (InterruptedException e) { + logger.error("Error occurred", e); + } + }).start(); + } + + public void shutDown() { + if(!workerGroup.isShutdown()) { + workerGroup.shutdownGracefully(); + } + + if(!bossGroup.isShutdown()) { + bossGroup.shutdownGracefully(); + } + } +} diff --git a/sdk/cosmos/sdk/src/test/resources/Microsoft.jpg b/sdk/cosmos/sdk/src/test/resources/Microsoft.jpg new file mode 100644 index 0000000000000..cf6c76bba4981 Binary files /dev/null and b/sdk/cosmos/sdk/src/test/resources/Microsoft.jpg differ diff --git a/sdk/cosmos/sdk/src/test/resources/cosmosdb-1.png b/sdk/cosmos/sdk/src/test/resources/cosmosdb-1.png new file mode 100644 index 0000000000000..60d23806107c5 Binary files /dev/null and b/sdk/cosmos/sdk/src/test/resources/cosmosdb-1.png differ diff --git a/sdk/cosmos/sdk/src/test/resources/databaseAccount.json b/sdk/cosmos/sdk/src/test/resources/databaseAccount.json new file mode 100644 index 0000000000000..b514a0dda813a --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/databaseAccount.json @@ -0,0 +1,38 @@ +{ + "_self": "", + "id": "localhost", + "_rid": "localhost", + "media": "//media/", + "addresses": "//addresses/", + "_dbs": "//dbs/", + "writableLocations": [ + { + "name": "South Central US", + "databaseAccountEndpoint": "https://127.0.0.1:8081/" + } + ], + "readableLocations": [ + { + "name": "South Central US", + "databaseAccountEndpoint": "https://127.0.0.1:8081/" + } + ], + "enableMultipleWriteLocations": false, + "userReplicationPolicy": { + "asyncReplication": false, + "minReplicaSetSize": 1, + "maxReplicasetSize": 4 + }, + "userConsistencyPolicy": { + "defaultConsistencyLevel": "Session" + }, + "systemReplicationPolicy": { + "minReplicaSetSize": 1, + "maxReplicasetSize": 4 + }, + "readPolicy": { + "primaryReadCoefficient": 1, + "secondaryReadCoefficient": 1 + }, + "queryEngineConfiguration": "{\"maxSqlQueryInputLength\":262144,\"maxJoinsPerSqlQuery\":5,\"maxLogicalAndPerSqlQuery\":500,\"maxLogicalOrPerSqlQuery\":500,\"maxUdfRefPerSqlQuery\":10,\"maxInExpressionItemsCount\":16000,\"queryMaxInMemorySortDocumentCount\":500,\"maxQueryRequestTimeoutFraction\":0.9,\"sqlAllowNonFiniteNumbers\":false,\"sqlAllowAggregateFunctions\":true,\"sqlAllowSubQuery\":true,\"sqlAllowScalarSubQuery\":true,\"allowNewKeywords\":true,\"sqlAllowLike\":false,\"maxSpatialQueryCells\":12,\"spatialMaxGeometryPointCount\":256,\"sqlAllowTop\":true,\"enableSpatialIndexing\":true}" +} \ No newline at end of file diff --git a/sdk/cosmos/sdk/src/test/resources/emulator-testng.xml b/sdk/cosmos/sdk/src/test/resources/emulator-testng.xml new file mode 100644 index 0000000000000..16bec3b3b396c --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/emulator-testng.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + diff --git a/sdk/cosmos/sdk/src/test/resources/fast-testng.xml b/sdk/cosmos/sdk/src/test/resources/fast-testng.xml new file mode 100644 index 0000000000000..b78fb1cab3254 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/fast-testng.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + diff --git a/sdk/cosmos/sdk/src/test/resources/log4j.properties b/sdk/cosmos/sdk/src/test/resources/log4j.properties new file mode 100644 index 0000000000000..1f3287c67a55f --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/log4j.properties @@ -0,0 +1,15 @@ +# this is the log4j configuration for tests + +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=INFO, A1 + +# Set HTTP components' logger to INFO + +log4j.category.io.netty=INFO +log4j.category.io.reactivex=INFO +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n diff --git a/sdk/cosmos/sdk/src/test/resources/long-testng.xml b/sdk/cosmos/sdk/src/test/resources/long-testng.xml new file mode 100644 index 0000000000000..debd90ba2136e --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/long-testng.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + diff --git a/sdk/cosmos/sdk/src/test/resources/sampleConflict.json b/sdk/cosmos/sdk/src/test/resources/sampleConflict.json new file mode 100644 index 0000000000000..12f2a507b7a39 --- /dev/null +++ b/sdk/cosmos/sdk/src/test/resources/sampleConflict.json @@ -0,0 +1,11 @@ +{ + "id": "k6d9ALgBmD8BAAAAAAAAQA==", + "_rid": "k6d9ALgBmD8BAAAAAAAAQA==", + "_self": "dbs/k6d9AA==/colls/k6d9ALgBmD8=/conflicts/k6d9ALgBmD8BAAAAAAAAQA==/", + "_etag": "\"00004a0f-0000-0000-0000-5b6e214b0000\"", + "resourceType": "document", + "operationType": "create", + "resourceId": "k6d9ALgBmD+ChB4AAAAAAA==", + "content": "{\"id\":\"0007312a-a1c5-4b54-9e39-35de2367fa33\",\"regionId\":2,\"regionEndpoint\":\"https://test-southeastasia.documents.azure.com:443/\",\"_rid\":\"k6d9ALgBmD+ChB4AAAAAAA==\",\"_self\":\"dbs\\/k6d9AA==\\/colls\\/k6d9ALgBmD8=\\/docs\\/k6d9ALgBmD+ChB4AAAAAAA==\\/\",\"_etag\":\"\\\"00000200-0000-0000-0000-5b6e214b0000\\\"\",\"_attachments\":\"attachments\\/\",\"_ts\":1533944139}", + "_ts": 1533944139 +} diff --git a/sdk/cosmosdb/ci.yml b/sdk/cosmosdb/ci.yml new file mode 100644 index 0000000000000..c2a1e5d1f072e --- /dev/null +++ b/sdk/cosmosdb/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/cosmosdb/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/cosmosdb/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: cosmosdb \ No newline at end of file diff --git a/sdk/cosmosdb/pom.service.xml b/sdk/cosmosdb/pom.service.xml new file mode 100644 index 0000000000000..56f12fc9d934b --- /dev/null +++ b/sdk/cosmosdb/pom.service.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + com.azure + azure-keyvault-service + pom + 1.0.0 + + microsoft-azure-keyvault + microsoft-azure-keyvault-core + microsoft-azure-keyvault-webkey + microsoft-azure-keyvault-cryptography + microsoft-azure-keyvault-extensions + microsoft-azure-keyvault-complete + + diff --git a/sdk/eventhubs/CHANGELOG.md b/sdk/eventhubs/CHANGELOG.md new file mode 100644 index 0000000000000..331c6ad6b4477 --- /dev/null +++ b/sdk/eventhubs/CHANGELOG.md @@ -0,0 +1,28 @@ +# Release History + +## 5.0.0-preview.1 (2019-07-01) +Version 5.0.0-preview.1 is a preview of our efforts in creating a client library that is developer-friendly, idiomatic +to the Java ecosystem, and as consistent across different languages and platforms as possible. The principles that guide +our efforts can be found in the [Azure SDK Design Guidelines for +.Java](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html). + +For release notes and more information please visit https://aka.ms/azure-sdk-preview1-java + +### Features + +- Reactive streams support using [Project Reactor](https://projectreactor.io/). +- Fetch Event Hub and partition metadata using `EventHubClient`. +- Publish messages to an Azure Event Hub using `EventHubPublisher`. +- Receive messages from an Azure Event Hub using `EventHubConsumer`. + +### Known issues + +- AMQP protocol using web sockets is not implemented. +- Proxy support is not implemented. +- Event Host Processor is not implemented. +- Creating an `EventDataBatch` is not exposed. +- Getting `ReceiverRuntimeInformation` from `EventHubConsumer` is not implemented. +- `EventHubClient` does not clean up its `EventHubPublishers` and `EventHubConsumers`. These need to be closed manually + by calling `EventHubPublisher.close()` or `EventHubConsumer.close()`. +- Creating more than two concurrent `EventHubClients` or `EventHubConsumers` does not work. Limit usage of concurrent + clients and consumers to two to avoid failures. \ No newline at end of file diff --git a/eventhubs/client/CONTRIBUTING.md b/sdk/eventhubs/CONTRIBUTING.md similarity index 100% rename from eventhubs/client/CONTRIBUTING.md rename to sdk/eventhubs/CONTRIBUTING.md diff --git a/eventhubs/client/README.md b/sdk/eventhubs/README.md similarity index 98% rename from eventhubs/client/README.md rename to sdk/eventhubs/README.md index 436cc035e11f8..68cddc513e8f5 100644 --- a/eventhubs/client/README.md +++ b/sdk/eventhubs/README.md @@ -17,7 +17,7 @@ The Azure Event Hubs client library allows for publishing and consuming of Azure the transformed events to a new stream for consumers to observe. [Source code][source_code] | [API reference documentation][api_documentation] | [Product -documentation][event_hubs_product_docs] +documentation][event_hubs_product_docs] | [Samples][sample_examples] ## Getting started @@ -45,7 +45,7 @@ documentation][event_hubs_product_docs] For the Event Hubs client library to interact with an Event Hub, it will need to understand how to connect and authorize with it. -### Create an Event Hub client using a connection String +### Create an Event Hub client using a connection string The easiest means for doing so is to use a connection string, which is created automatically when creating an Event Hubs namespace. If you aren't familiar with shared access policies in Azure, you may wish to follow the @@ -93,7 +93,7 @@ String host = "<< EVENT HUBS HOST >>" String eventHubPath = "<< NAME OF THE EVENT HUB >>"; EventHubClient client = new EventHubClientBuilder() .credential(host, eventHubPath, credential) - .build(); + .buildAsyncClient(); ``` ## Key concepts @@ -294,7 +294,7 @@ Guidelines](./CONTRIBUTING.md) for more information. [amqp_exception]: ../../core/azure-core-amqp/src/main/java/com/azure/core/amqp/exception/AmqpException.java [amqp_transport_error]: https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-amqp-error -[api_documentation]: https://azuresdkartifacts.blob.core.windows.net/azure-sdk-for-java/index.html +[api_documentation]: https://aka.ms/java-docs [app_registration_page]: https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#get-values-for-signing-in [application_client_secret]: https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#create-a-new-application-secret [error_condition]: ../../core/azure-core-amqp/src/main/java/com/azure/core/amqp/exception/ErrorCondition.java @@ -314,6 +314,7 @@ Guidelines](./CONTRIBUTING.md) for more information. [oasis_amqp_v1_error]: http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-error [oasis_amqp_v1]: http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-overview-v1.0-os.html [qpid_proton_j_apache]: http://qpid.apache.org/proton/ +[sample_examples]: ./azure-eventhubs/src/samples/java [sample_consume_event]: ./azure-eventhubs/src/samples/java/ConsumeEvent.java [sample_get_event_hubs_metadata]: ./azure-eventhubs/src/samples/java/GetEventHubMetadata.java [sample_publish_custom_meta_data]: ./azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java diff --git a/eventhubs/client/pom.xml b/sdk/eventhubs/azure-eventhubs/pom.xml similarity index 79% rename from eventhubs/client/pom.xml rename to sdk/eventhubs/azure-eventhubs/pom.xml index 349a20ea12b0e..ddbdaeffd691f 100644 --- a/eventhubs/client/pom.xml +++ b/sdk/eventhubs/azure-eventhubs/pom.xml @@ -8,17 +8,16 @@ com.azure azure-client-sdk-parent - 1.0.0 - ../../pom.client.xml + 1.1.0 + ../../../pom.client.xml com.azure - azure-messaging-eventhubs-parent - 5.0.0-preview.1 - pom + azure-messaging-eventhubs + 5.0.0-preview.2 - Microsoft Azure client library for Event Hubs (Parent) - This package contains the Microsoft Azure Event Hubs client library. + Microsoft Azure client library for Event Hubs + Libraries built on Microsoft Azure Event Hubs https://github.com/Azure/azure-sdk-for-java @@ -38,12 +37,12 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 com.azure azure-core-amqp - 1.0.0-preview.1 + 1.0.0-preview.3 com.microsoft.azure @@ -54,10 +53,11 @@ proton-j + com.azure azure-core-test - 1.0.0-preview.1 + 1.0.0-preview.3 test @@ -81,9 +81,4 @@ test - - - azure-eventhubs - - diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java similarity index 99% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java index 19e27feea1331..1eb29b00ee982 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventData.java @@ -116,7 +116,7 @@ public EventData(ByteBuffer body) { addMapEntry(receiveProperties, MessageConstant.CORRELATION_ID, message.getCorrelationId()); addMapEntry(receiveProperties, MessageConstant.CONTENT_TYPE, message.getContentType()); addMapEntry(receiveProperties, MessageConstant.CONTENT_ENCODING, message.getContentEncoding()); - addMapEntry(receiveProperties, MessageConstant.ABSOLUTE_EXPRITY_TIME, message.getExpiryTime()); + addMapEntry(receiveProperties, MessageConstant.ABSOLUTE_EXPIRY_TIME, message.getExpiryTime()); addMapEntry(receiveProperties, MessageConstant.CREATION_TIME, message.getCreationTime()); addMapEntry(receiveProperties, MessageConstant.GROUP_ID, message.getGroupId()); addMapEntry(receiveProperties, MessageConstant.GROUP_SEQUENCE, message.getGroupSequence()); @@ -133,7 +133,7 @@ public EventData(ByteBuffer body) { Data bodyData = (Data) bodySection; this.body = bodyData.getValue().asByteBuffer(); } else { - logger.asWarning().log(String.format(Locale.US, + logger.warning(String.format(Locale.US, "Message body type is not of type Data, but type: %s. Not setting body contents.", bodySection != null ? bodySection.getType() : "null")); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java similarity index 99% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java index d3b4daf8af672..7caf7bfd8444d 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventDataBatch.java @@ -143,7 +143,7 @@ private static Message createAmqpMessage(EventData event, String partitionKey) { case CONTENT_ENCODING: message.setContentEncoding((String) value); break; - case ABSOLUTE_EXPRITY_TIME: + case ABSOLUTE_EXPIRY_TIME: message.setExpiryTime((long) value); break; case CREATION_TIME: diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java index c12c9a1dfcd9c..a9cd13f889fd0 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClient.java @@ -141,7 +141,7 @@ public EventHubProducer createProducer() { public EventHubProducer createProducer(EventHubProducerOptions options) { Objects.requireNonNull(options); - final EventHubProducerOptions clonedOptions = options.clone(); + final EventHubProducerOptions clonedOptions = (EventHubProducerOptions) options.clone(); if (clonedOptions.timeout() == null) { clonedOptions.timeout(connectionOptions.timeout()); } @@ -162,7 +162,7 @@ public EventHubProducer createProducer(EventHubProducerOptions options) { final Mono amqpLinkMono = connectionMono.flatMap(connection -> connection.createSession(entityPath)) .flatMap(session -> { - logger.asInfo().log("Creating producer."); + logger.info("Creating producer."); return session.createProducer(linkName, entityPath, clonedOptions.timeout(), clonedOptions.retry()) .cast(AmqpSendLink.class); }); @@ -248,7 +248,7 @@ public EventHubConsumer createConsumer(String consumerGroup, String partitionId, final Mono receiveLinkMono = connectionMono.flatMap(connection -> { return connection.createSession(entityPath).cast(EventHubSession.class); }).flatMap(session -> { - logger.asInfo().log("Creating consumer."); + logger.info("Creating consumer."); return session.createConsumer(linkName, entityPath, eventPosition.getExpression(), connectionOptions.timeout(), clonedOptions.retry(), options.ownerLevel(), options.identifier()).cast(AmqpReceiveLink.class); }); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClientBuilder.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClientBuilder.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClientBuilder.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubClientBuilder.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java similarity index 88% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java index ade3cc6c5d515..e66e509a26449 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumer.java @@ -66,14 +66,14 @@ public class EventHubConsumer implements Closeable { // Caching the created link so we don't invoke another link creation. this.messageFlux = receiveLinkMono.flatMapMany(link -> { if (RECEIVE_LINK_FIELD_UPDATER.compareAndSet(this, null, link)) { - logger.asInfo().log("Created AMQP receive link. Initialising prefetch credit: {}", options.prefetchCount()); + logger.info("Created AMQP receive link. Initialising prefetch credit: {}", options.prefetchCount()); link.addCredits(options.prefetchCount()); link.setEmptyCreditListener(() -> { if (emitterProcessor.hasDownstreams()) { return creditsToRequest.get(); } else { - logger.asVerbose().log("Emitter has no downstream subscribers. Not adding credits."); + logger.verbose("Emitter has no downstream subscribers. Not adding credits."); return 0; } }); @@ -85,19 +85,19 @@ public class EventHubConsumer implements Closeable { .doOnSubscribe(subscription -> { AmqpReceiveLink existingLink = RECEIVE_LINK_FIELD_UPDATER.get(this); if (existingLink == null) { - logger.asInfo().log("AmqpReceiveLink not set yet."); + logger.info("AmqpReceiveLink not set yet."); return; } - logger.asInfo().log("Subscription received for consumer."); + logger.info("Subscription received for consumer."); if (existingLink.getCredits() == 0) { - logger.asInfo().log("Subscription received and there are no remaining credits on the link. Adding more."); + logger.info("Subscription received and there are no remaining credits on the link. Adding more."); existingLink.addCredits(creditsToRequest.get()); } }) .doOnRequest(request -> { if (request < MINIMUM_REQUEST) { - logger.asWarning().log("Back pressure request value not valid. It must be between {} and {}.", + logger.warning("Back pressure request value not valid. It must be between {} and {}.", MINIMUM_REQUEST, MAXIMUM_REQUEST); return; } @@ -106,7 +106,7 @@ public class EventHubConsumer implements Closeable { ? MAXIMUM_REQUEST : (int) request; - logger.asInfo().log("Back pressure request. Old value: {}. New value: {}", creditsToRequest.get(), newRequest); + logger.info("Back pressure request. Old value: {}. New value: {}", creditsToRequest.get(), newRequest); creditsToRequest.set(newRequest); }); } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java similarity index 94% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java index 55c1f40450975..97bc0ebc8a135 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubConsumerOptions.java @@ -5,6 +5,7 @@ import com.azure.core.amqp.Retry; import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.logging.ClientLogger; import reactor.core.scheduler.Scheduler; import java.time.Duration; @@ -19,6 +20,8 @@ * @see EventHubClient#createConsumer(String, String, EventPosition, EventHubConsumerOptions) */ public class EventHubConsumerOptions implements Cloneable { + private final ClientLogger logger = new ClientLogger(EventHubConsumerOptions.class); + /** * The maximum length, in characters, for the identifier assigned to an {@link EventHubConsumer}. */ @@ -37,7 +40,7 @@ public class EventHubConsumerOptions implements Cloneable { private String identifier; private Long ownerLevel; - private Retry retryPolicy; + private Retry retry; private Scheduler scheduler; private int prefetchCount; @@ -102,7 +105,7 @@ public EventHubConsumerOptions ownerLevel(Long priority) { * @return The updated {@link EventHubConsumerOptions} object. */ public EventHubConsumerOptions retry(Retry retry) { - this.retryPolicy = retry; + this.retry = retry; return this; } @@ -159,7 +162,7 @@ public String identifier() { * @return The retry policy when receiving events. */ public Retry retry() { - return retryPolicy; + return retry; } /** @@ -211,10 +214,18 @@ public EventHubConsumerOptions clone() { clone = new EventHubConsumerOptions(); } + if (retry != null) { + try { + clone.retry((Retry) retry.clone()); + } catch (CloneNotSupportedException e) { + logger.error("Unable to create clone of retry.", e); + clone.retry(retry); + } + } + clone.scheduler(this.scheduler()); clone.identifier(this.identifier()); clone.prefetchCount(this.prefetchCount()); - clone.retry(this.retry()); clone.ownerLevel(this.ownerLevel()); return clone; diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java index c89b64bcb5f01..03989de29869b 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducer.java @@ -225,17 +225,17 @@ private Mono send(Flux eventBatches) { .flatMap(this::send) .then() .doOnError(error -> { - logger.asError().log("Error sending batch.", error); + logger.error("Error sending batch.", error); }); } private Mono send(EventDataBatch batch) { if (batch.getEvents().isEmpty()) { - logger.asInfo().log("Cannot send an EventBatch that is empty."); + logger.info("Cannot send an EventBatch that is empty."); return Mono.empty(); } - logger.asInfo().log("Sending batch with partitionKey[{}], size[{}].", batch.getPartitionKey(), batch.getSize()); + logger.info("Sending batch with partitionKey[{}], size[{}].", batch.getPartitionKey(), batch.getSize()); final List messages = EventDataUtil.toAmqpMessage(batch.getPartitionKey(), batch.getEvents()); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java similarity index 75% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java index 9d0ae36fe5c32..4b45fe7ffbac7 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProducerOptions.java @@ -4,6 +4,7 @@ package com.azure.messaging.eventhubs; import com.azure.core.amqp.Retry; +import com.azure.core.util.logging.ClientLogger; import java.time.Duration; @@ -14,6 +15,8 @@ * @see EventHubClient#createProducer(EventHubProducerOptions) */ public class EventHubProducerOptions implements Cloneable { + private final ClientLogger logger = new ClientLogger(EventHubProducerOptions.class); + private String partitionId; private Retry retry; private Duration timeout; @@ -25,9 +28,9 @@ public class EventHubProducerOptions implements Cloneable { * If the identifier is not specified, the Event Hubs service will be responsible for routing events that are sent * to an available partition. * - * @param partitionId The identifier of the Event Hub partition that the {@link EventHubProducer} will be bound to. - * If the producer wishes the events to be automatically to partitions, {@code null}; otherwise, the - * identifier of the desired partition. + * @param partitionId The identifier of the Event Hub partition that the {@link EventHubProducer} will be + * bound to. If the producer wishes the events to be automatically to partitions, {@code null}; otherwise, + * the identifier of the desired partition. * @return The updated {@link EventHubProducerOptions} object. */ public EventHubProducerOptions partitionId(String partitionId) { @@ -61,8 +64,8 @@ public EventHubProducerOptions timeout(Duration timeout) { /** * Gets the retry policy used to govern retry attempts when an issue is encountered while sending. * - * @return the retry policy used to govern retry attempts when an issue is encountered while sending. If - * {@code null}, then the retry policy configured on the associated {@link EventHubClient} is used. + * @return the retry policy used to govern retry attempts when an issue is encountered while sending. If {@code + * null}, then the retry policy configured on the associated {@link EventHubClient} is used. */ public Retry retry() { return retry; @@ -91,15 +94,15 @@ public Duration timeout() { } /** - * Creates a shallow clone of this instance. + * Creates a clone of this instance. * - * The object is cloned, but the objects {@link #retry()}, {@link #timeout()} and {@link #partitionId()} are not - * cloned. {@link Duration} and {@link String} are immutable objects and are not an issue. However, the - * implementation of {@link Retry} could be mutable. + * The object and {@link #retry()} is cloned, but the objects {@link #timeout()} and {@link #partitionId()} are not + * cloned. {@link Duration} and {@link String} are immutable objects and are not an issue. * * @return A shallow clone of this object. */ - public EventHubProducerOptions clone() { + @Override + public Object clone() { EventHubProducerOptions clone; try { clone = (EventHubProducerOptions) super.clone(); @@ -107,9 +110,17 @@ public EventHubProducerOptions clone() { clone = new EventHubProducerOptions(); } - clone.partitionId(this.partitionId); - clone.retry(this.retry); - clone.timeout(this.timeout); + if (retry != null) { + try { + clone.retry((Retry) retry.clone()); + } catch (CloneNotSupportedException e) { + logger.error("Unable to create clone of retry.", e); + clone.retry(retry); + } + } + + clone.partitionId(partitionId); + clone.timeout(timeout); return clone; } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProperties.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProperties.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProperties.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubProperties.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredential.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredential.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredential.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredential.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java similarity index 99% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java index 52736b77f31b6..d12563c57a059 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/EventPosition.java @@ -158,7 +158,7 @@ String getExpression() { ms = Long.toString(this.enqueuedDateTime.toEpochMilli()); } catch (ArithmeticException ex) { ms = Long.toString(Long.MAX_VALUE); - logger.asWarning().log( + logger.warning( "Receiver not yet created, action[createReceiveLink], warning[starting receiver from epoch+Long.Max]"); } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionProperties.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionProperties.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionProperties.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/PartitionProperties.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyAuthenticationType.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyAuthenticationType.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyAuthenticationType.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyAuthenticationType.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java similarity index 97% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java index d3ba4ea04a2b9..40a428a79e43b 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/ProxyConfiguration.java @@ -62,7 +62,7 @@ public ProxyConfiguration(ProxyAuthenticationType authentication, Proxy proxyAdd if (username != null && password != null) { this.credentials = new PasswordAuthentication(username, password.toCharArray()); } else { - logger.asInfo().log("Username or password is null. Using system-wide authentication."); + logger.info("Username or password is null. Using system-wide authentication."); this.credentials = null; } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java similarity index 84% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java index c8b1db7c5daf4..44d0fcac342bb 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/SendOptions.java @@ -9,7 +9,7 @@ * * @see EventHubProducer */ -public class SendOptions { +public class SendOptions implements Cloneable { private int maximumSizeInBytes; private String partitionKey; @@ -72,4 +72,23 @@ public SendOptions partitionKey(String partitionKey) { public String partitionKey() { return partitionKey; } + + /** + * Creates a shallow clone of this instance. The parameters are not cloned, but they are immutable. + * + * @return A shallow clone of this object. + */ + public SendOptions clone() { + SendOptions clone; + try { + clone = (SendOptions) super.clone(); + } catch (CloneNotSupportedException e) { + clone = new SendOptions(); + } + + clone.maximumSizeInBytes(maximumSizeInBytes); + clone.partitionKey(partitionKey); + + return clone; + } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java similarity index 87% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java index f48ad6210dbaf..a05f96148ba24 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManager.java @@ -85,7 +85,7 @@ Mono authorize() { // If this is the first time authorize is called, the task will not have been scheduled yet. if (!hasScheduled.getAndSet(true)) { - logger.asInfo().log("Scheduling refresh token task."); + logger.info("Scheduling refresh token task."); scheduleRefreshTokenTask(refreshIntervalMS); } @@ -108,7 +108,7 @@ private void scheduleRefreshTokenTask(Long refreshIntervalInMS) { try { timer.schedule(new RefreshAuthorizationToken(), refreshIntervalInMS); } catch (IllegalStateException e) { - logger.asWarning().log("Unable to schedule RefreshAuthorizationToken task.", e); + logger.warning("Unable to schedule RefreshAuthorizationToken task.", e); hasScheduled.set(false); } } @@ -116,25 +116,25 @@ private void scheduleRefreshTokenTask(Long refreshIntervalInMS) { private class RefreshAuthorizationToken extends TimerTask { @Override public void run() { - logger.asInfo().log("Refreshing authorization token."); + logger.info("Refreshing authorization token."); authorize().subscribe( (Long refreshIntervalInMS) -> { if (hasDisposed.get()) { - logger.asInfo().log("Token manager has been disposed of. Not rescheduling."); + logger.info("Token manager has been disposed of. Not rescheduling."); return; } - logger.asInfo().log("Authorization successful. Refreshing token in {} ms.", refreshIntervalInMS); + logger.info("Authorization successful. Refreshing token in {} ms.", refreshIntervalInMS); sink.next(AmqpResponseCode.ACCEPTED); scheduleRefreshTokenTask(refreshIntervalInMS); }, error -> { if ((error instanceof AmqpException) && ((AmqpException) error).isTransient()) { - logger.asError().log("Error is transient. Rescheduling authorization task.", error); + logger.error("Error is transient. Rescheduling authorization task.", error); scheduleRefreshTokenTask(lastRefreshInterval.get()); } else { - logger.asError().log("Error occurred while refreshing token that is not retriable. Not scheduling" + logger.error("Error occurred while refreshing token that is not retriable. Not scheduling" + " refresh task. Use ActiveClientTokenManager.authorize() to schedule task again.", error); hasScheduled.set(false); } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpConstants.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpConstants.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpConstants.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpConstants.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpErrorCode.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpErrorCode.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpErrorCode.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpErrorCode.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpReceiveLink.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpReceiveLink.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpReceiveLink.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpReceiveLink.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpResponseMapper.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpResponseMapper.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpResponseMapper.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpResponseMapper.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpSendLink.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpSendLink.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpSendLink.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/AmqpSendLink.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSAuthorizationType.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSAuthorizationType.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSAuthorizationType.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSAuthorizationType.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java similarity index 97% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java index cbfa813672252..4ff385121c402 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/CBSChannel.java @@ -87,7 +87,7 @@ public void close() { } if (!connection.removeSession(SESSION_NAME)) { - logger.asInfo().log("Unable to remove CBSChannel {} from connection", SESSION_NAME); + logger.info("Unable to remove CBSChannel {} from connection", SESSION_NAME); } } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ClientConstants.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ClientConstants.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ClientConstants.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ClientConstants.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionOptions.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionOptions.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionOptions.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionOptions.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionStringProperties.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionStringProperties.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionStringProperties.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ConnectionStringProperties.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java similarity index 93% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java index 9d221fa091750..293c29084b4a8 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBase.java @@ -55,21 +55,21 @@ public Flux getShutdownSignals() { void notifyError(Throwable error) { Objects.requireNonNull(error); - logger.asInfo().log("Notify error: {}", error); + logger.info("Notify error: {}", error); errorContextProcessor.onNext(error); } void notifyShutdown(AmqpShutdownSignal shutdownSignal) { Objects.requireNonNull(shutdownSignal); - logger.asInfo().log("Notify shutdown signal: {}", shutdownSignal); + logger.info("Notify shutdown signal: {}", shutdownSignal); shutdownSignalProcessor.onNext(shutdownSignal); } void notifyEndpointState(EndpointState endpointState) { Objects.requireNonNull(endpointState); - logger.asVerbose().log("Connection state: {}", endpointState); + logger.verbose("Connection state: {}", endpointState); final AmqpEndpointState state = getConnectionState(endpointState); connectionStateProcessor.onNext(state); } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ErrorContextProvider.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ErrorContextProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ErrorContextProvider.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ErrorContextProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java similarity index 99% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java index 58cf8c9c76d99..68d224b907e05 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventDataUtil.java @@ -141,7 +141,7 @@ private static void setSystemProperties(EventData eventData, Message message) { case CONTENT_ENCODING: message.setContentEncoding((String) value); break; - case ABSOLUTE_EXPRITY_TIME: + case ABSOLUTE_EXPIRY_TIME: message.setExpiryTime((long) value); break; case CREATION_TIME: diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubConnection.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubConnection.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubConnection.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubConnection.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubManagementNode.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubManagementNode.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubManagementNode.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubManagementNode.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSession.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSession.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSession.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/EventHubSession.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java index 61bdab1667c0d..efd2d8f678c0a 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ManagementChannel.java @@ -156,7 +156,7 @@ public void close() { } if (!connection.removeSession(SESSION_NAME)) { - logger.asInfo().log("Unable to remove CBSChannel {} from connection", SESSION_NAME); + logger.info("Unable to remove CBSChannel {} from connection", SESSION_NAME); } } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java similarity index 96% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java index 0f668b0bc5586..0c8434e2516a7 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorConnection.java @@ -176,7 +176,7 @@ public void close() { try { session.close(); } catch (IOException e) { - logger.asError().log("Could not close session: " + name, e); + logger.error("Could not close session: " + name, e); } }); super.close(); @@ -184,7 +184,7 @@ public void close() { private synchronized CBSNode getOrCreateCBSNode() { if (cbsChannel == null) { - logger.asInfo().log("Setting CBS channel."); + logger.info("Setting CBS channel."); cbsChannel = new CBSChannel(this, connectionOptions.tokenCredential(), connectionOptions.authorizationType(), reactorProvider, handlerProvider, @@ -196,7 +196,7 @@ private synchronized CBSNode getOrCreateCBSNode() { private synchronized Connection getOrCreateConnection() throws IOException { if (connection == null) { - logger.asInfo().log("Creating and starting connection to {}:{}", handler.getHostname(), handler.getProtocolPort()); + logger.info("Creating and starting connection to {}:{}", handler.getHostname(), handler.getProtocolPort()); final Reactor reactor = reactorProvider.createReactor(connectionId, handler.getMaxFrameSize()); connection = reactor.connectionToHost(handler.getHostname(), handler.getProtocolPort(), handler); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java similarity index 92% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java index d6d2a0e8e7f4e..41acbbfb3cd05 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorDispatcher.java @@ -100,7 +100,7 @@ private void signalWorkQueue() throws IOException { oneByteBuffer = ByteBuffer.allocate(1); } } catch (ClosedChannelException ignorePipeClosedDuringReactorShutdown) { - logger.asInfo().log("signalWorkQueue failed with an error: %s", ignorePipeClosedDuringReactorShutdown); + logger.info("signalWorkQueue failed with an error: %s", ignorePipeClosedDuringReactorShutdown); } } @@ -115,9 +115,9 @@ public void run(Selectable selectable) { oneKbByteBuffer = ByteBuffer.allocate(1024); } } catch (ClosedChannelException ignorePipeClosedDuringReactorShutdown) { - logger.asInfo().log("WorkScheduler.run() failed with an error: %s", ignorePipeClosedDuringReactorShutdown); + logger.info("WorkScheduler.run() failed with an error: %s", ignorePipeClosedDuringReactorShutdown); } catch (IOException ioException) { - logger.asError().log("WorkScheduler.run() failed with an error: %s", ioException); + logger.error("WorkScheduler.run() failed with an error: %s", ioException); throw new RuntimeException(ioException); } @@ -142,7 +142,7 @@ public void run(Selectable selectable) { ioSignal.sink().close(); } } catch (IOException ioException) { - logger.asError().log("CloseHandler.run() sink().close() failed with an error. %s", ioException); + logger.error("CloseHandler.run() sink().close() failed with an error. %s", ioException); } workScheduler.run(null); @@ -152,7 +152,7 @@ public void run(Selectable selectable) { ioSignal.source().close(); } } catch (IOException ioException) { - logger.asError().log("CloseHandler.run() source().close() failed with an error %s", ioException); + logger.error("CloseHandler.run() source().close() failed with an error %s", ioException); } } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java similarity index 89% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java index 75ba05eca7ea5..23da0dbfb2aaf 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorExecutor.java @@ -59,11 +59,11 @@ class ReactorExecutor implements Closeable { */ void start() { if (hasStarted.get()) { - logger.asWarning().log("ReactorExecutor has already started."); + logger.warning("ReactorExecutor has already started."); return; } - logger.asInfo().log(LOG_MESSAGE, connectionId, "Starting reactor."); + logger.info(LOG_MESSAGE, connectionId, "Starting reactor."); hasStarted.set(true); synchronized (lock) { @@ -80,7 +80,7 @@ void start() { private void run() { // If this hasn't been disposed of, and we're trying to run work items on it, log a warning and return. if (!isDisposed.get() && !hasStarted.get()) { - logger.asWarning().log("Cannot run work items on ReactorExecutor if ReactorExecutor.start() has not been invoked."); + logger.warning("Cannot run work items on ReactorExecutor if ReactorExecutor.start() has not been invoked."); return; } @@ -97,7 +97,7 @@ private void run() { scheduler.schedule(this::run); rescheduledReactor = true; } catch (RejectedExecutionException exception) { - logger.asWarning().log(LOG_MESSAGE, connectionId, + logger.warning(LOG_MESSAGE, connectionId, StringUtil.toStackTraceString(exception, "Scheduling reactor failed because the executor has been shut down")); this.reactor.attachments().set(RejectedExecutionException.class, RejectedExecutionException.class, exception); @@ -108,7 +108,7 @@ private void run() { ? handlerException : handlerException.getCause(); - logger.asWarning().log(LOG_MESSAGE, connectionId, StringUtil.toStackTraceString(handlerException, + logger.warning(LOG_MESSAGE, connectionId, StringUtil.toStackTraceString(handlerException, "Unhandled exception while processing events in reactor, report this error.")); final String message = !ImplUtils.isNullOrEmpty(cause.getMessage()) @@ -139,7 +139,7 @@ private void run() { } else { final String reason = "Stopping the reactor because thread was interrupted or the reactor has no more events to process."; - logger.asInfo().log(LOG_MESSAGE, connectionId, reason); + logger.info(LOG_MESSAGE, connectionId, reason); close(false, reason); } } @@ -150,12 +150,12 @@ private void scheduleCompletePendingTasks() { hasStarted.set(false); this.scheduler.schedule(() -> { - logger.asInfo().log(LOG_MESSAGE, connectionId, "Processing all pending tasks and closing old reactor."); + logger.info(LOG_MESSAGE, connectionId, "Processing all pending tasks and closing old reactor."); try { reactor.stop(); reactor.process(); } catch (HandlerException e) { - logger.asWarning().log(LOG_MESSAGE, connectionId, + logger.warning(LOG_MESSAGE, connectionId, StringUtil.toStackTraceString(e, "scheduleCompletePendingTasks - exception occurred while processing events.")); } finally { reactor.free(); @@ -172,7 +172,7 @@ public void close() { private void close(boolean isUserInitialized, String reason) { if (hasStarted.getAndSet(false)) { - logger.asInfo().log(LOG_MESSAGE, connectionId, "Stopping the reactor."); + logger.info(LOG_MESSAGE, connectionId, "Stopping the reactor."); synchronized (lock) { this.reactor.stop(); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorHandlerProvider.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorHandlerProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorHandlerProvider.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorHandlerProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorProvider.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorProvider.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java similarity index 92% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java index 63443d313fd8c..4c93ff648a040 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorReceiver.java @@ -49,9 +49,9 @@ public class ReactorReceiver extends EndpointStateNotifierBase implements AmqpRe handler.getEndpointStates().subscribe( this::notifyEndpointState, - error -> logger.asError().log("Error encountered getting endpointState", error), + error -> logger.error("Error encountered getting endpointState", error), () -> { - logger.asVerbose().log("getEndpointStates completed."); + logger.verbose("getEndpointStates completed."); notifyEndpointState(EndpointState.CLOSED); }), @@ -59,10 +59,10 @@ public class ReactorReceiver extends EndpointStateNotifierBase implements AmqpRe tokenManager.getAuthorizationResults().subscribe( response -> { - logger.asVerbose().log("Token refreshed: {}", response); + logger.verbose("Token refreshed: {}", response); hasAuthorized.set(true); }, error -> { - logger.asInfo().log("clientId[{}], path[{}], linkName[{}] - tokenRenewalFailure[{}]", + logger.info("clientId[{}], path[{}], linkName[{}] - tokenRenewalFailure[{}]", handler.getConnectionId(), this.entityPath, getLinkName(), error.getMessage()); hasAuthorized.set(false); }, () -> hasAuthorized.set(false)) diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java similarity index 94% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java index 3236043a1e913..b4c6aa2bd6d62 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSender.java @@ -95,7 +95,7 @@ class ReactorSender extends EndpointStateNotifierBase implements AmqpSendLink { handler.getDeliveredMessages().subscribe(this::processDeliveredMessage), handler.getLinkCredits().subscribe(credit -> { - logger.asVerbose().log("Credits on link: {}", credit); + logger.verbose("Credits on link: {}", credit); this.scheduleWorkOnDispatcher(); }), @@ -112,19 +112,19 @@ class ReactorSender extends EndpointStateNotifierBase implements AmqpSendLink { notifyEndpointState(endpoint); }, - error -> logger.asError().log("Error encountered getting endpointState", error), + error -> logger.error("Error encountered getting endpointState", error), () -> { - logger.asVerbose().log("getLinkCredits completed."); + logger.verbose("getLinkCredits completed."); hasConnected.set(false); }), tokenManager.getAuthorizationResults().subscribe( response -> { - logger.asVerbose().log("Token refreshed: {}", response); + logger.verbose("Token refreshed: {}", response); hasAuthorized.set(true); }, error -> { - logger.asInfo().log("clientId[{}], path[{}], linkName[{}] - tokenRenewalFailure[{}]", + logger.info("clientId[{}], path[{}], linkName[{}] - tokenRenewalFailure[{}]", handler.getConnectionId(), this.entityPath, getLinkName(), error.getMessage()); hasAuthorized.set(false); }, () -> hasAuthorized.set(false)) @@ -248,7 +248,7 @@ private void send(RetriableWorkItem workItem) { */ private void processSendWork() { if (!hasConnected.get()) { - logger.asWarning().log("Not connected. Not processing send work."); + logger.warning("Not connected. Not processing send work."); return; } @@ -269,7 +269,7 @@ private void processSendWork() { if (workItem == null) { if (deliveryTag != null) { - logger.asVerbose().log("clientId[{}]. path[{}], linkName[{}], deliveryTag[{}]: sendData not found for this delivery.", + logger.verbose("clientId[{}]. path[{}], linkName[{}], deliveryTag[{}]: sendData not found for this delivery.", handler.getConnectionId(), entityPath, getLinkName(), deliveryTag); } @@ -295,12 +295,12 @@ private void processSendWork() { } if (linkAdvance) { - logger.asVerbose().log("entityPath[{}], linkName[{}], deliveryTag[{}]: Sent message", entityPath, getLinkName(), deliveryTag); + logger.verbose("entityPath[{}], linkName[{}], deliveryTag[{}]: Sent message", entityPath, getLinkName(), deliveryTag); workItem.setIsWaitingForAck(); sendTimeoutTimer.schedule(new SendTimeout(deliveryTag), timeout.toMillis()); } else { - logger.asVerbose().log( + logger.verbose( "clientId[{}]. path[{}], linkName[{}], deliveryTag[{}], sentMessageSize[{}], payloadActualSize[{}]: sendlink advance failed", handler.getConnectionId(), entityPath, getLinkName(), deliveryTag, sentMsgSize, workItem.encodedMessageSize()); @@ -322,13 +322,13 @@ private void processDeliveredMessage(Delivery delivery) { final DeliveryState outcome = delivery.getRemoteState(); final String deliveryTag = new String(delivery.getTag(), UTF_8); - logger.asVerbose().log("entityPath[{}], clinkName[{}], deliveryTag[{}]: process delivered message", + logger.verbose("entityPath[{}], clinkName[{}], deliveryTag[{}]: process delivered message", entityPath, getLinkName(), deliveryTag); final RetriableWorkItem workItem = pendingSendsMap.remove(deliveryTag); if (workItem == null) { - logger.asVerbose().log("clientId[{}]. path[{}], linkName[{}], delivery[{}] - mismatch (or send timed out)", + logger.verbose("clientId[{}]. path[{}], linkName[{}], delivery[{}] - mismatch (or send timed out)", handler.getConnectionId(), entityPath, getLinkName(), deliveryTag); return; } @@ -384,7 +384,7 @@ private void scheduleWorkOnDispatcher() { try { reactorProvider.getReactorDispatcher().invoke(this::processSendWork); } catch (IOException e) { - logger.asError().log("Error scheduling work on reactor.", e); + logger.error("Error scheduling work on reactor.", e); notifyError(e); } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java index 4ce72fa7ad670..66ee731b2062b 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/ReactorSession.java @@ -88,7 +88,7 @@ public void close() { try { link.close(); } catch (IOException e) { - logger.asError().log("Error closing send link: " + key, e); + logger.error("Error closing send link: " + key, e); } }); openReceiveLinks.clear(); @@ -97,7 +97,7 @@ public void close() { try { link.close(); } catch (IOException e) { - logger.asError().log("Error closing receive link: " + key, e); + logger.error("Error closing receive link: " + key, e); } }); openSendLinks.clear(); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java similarity index 95% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java index 761609ec21a58..9295cc885f5e1 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RequestResponseChannel.java @@ -76,7 +76,7 @@ class RequestResponseChannel implements Closeable { BaseHandler.setHandler(this.receiveLink, receiveLinkHandler); this.subscription = receiveLinkHandler.getDeliveredMessages().map(this::decodeDelivery).subscribe(message -> { - logger.asVerbose().log("Settling message: {}", message.getCorrelationId()); + logger.verbose("Settling message: {}", message.getCorrelationId()); settleMessage(message); }, this::handleException); } @@ -114,7 +114,7 @@ Mono sendWithAck(final Message message, final ReactorDispatcher dispatc receiveLinkHandler.getEndpointStates().takeUntil(x -> x == EndpointState.ACTIVE)).then( Mono.create(sink -> { try { - logger.asVerbose().log("Scheduling on dispatcher. Message Id {}", messageId); + logger.verbose("Scheduling on dispatcher. Message Id {}", messageId); unconfirmedSends.putIfAbsent(messageId, sink); dispatcher.invoke(() -> { @@ -167,7 +167,7 @@ private void settleMessage(Message message) { if (sink == null) { int size = unconfirmedSends.size(); - logger.asWarning().log("Received delivery without pending messageId[{}]. Size[{}]", id, size); + logger.warning("Received delivery without pending messageId[{}]. Size[{}]", id, size); return; } @@ -188,7 +188,7 @@ private void handleException(Throwable error) { AmqpException exception = (AmqpException) error; if (!exception.isTransient()) { - logger.asError().log("Exception encountered. Closing channel and clearing unconfirmed sends.", exception); + logger.error("Exception encountered. Closing channel and clearing unconfirmed sends.", exception); close(); unconfirmedSends.forEach((key, value) -> { diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RetriableWorkItem.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RetriableWorkItem.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RetriableWorkItem.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/RetriableWorkItem.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/StringUtil.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/StringUtil.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/StringUtil.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/StringUtil.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TimeoutTracker.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TimeoutTracker.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TimeoutTracker.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TimeoutTracker.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TokenResourceProvider.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TokenResourceProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TokenResourceProvider.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/TokenResourceProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java similarity index 93% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java index f74092b11483d..9053bc6178a52 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandler.java @@ -84,7 +84,7 @@ protected void addTransportLayers(final Event event, final TransportInternal tra @Override public void onConnectionInit(Event event) { - logger.asInfo().log("onConnectionInit hostname[{}], connectionId[{}]", getHostname(), getConnectionId()); + logger.info("onConnectionInit hostname[{}], connectionId[{}]", getHostname(), getConnectionId()); final Connection connection = event.getConnection(); final String hostName = getHostname() + ":" + getProtocolPort(); @@ -119,7 +119,7 @@ public int getMaxFrameSize() { @Override public void onConnectionBound(Event event) { - logger.asInfo().log("onConnectionBound hostname[{}], connectionId[{}]", getHostname(), getConnectionId()); + logger.info("onConnectionBound hostname[{}], connectionId[{}]", getHostname(), getConnectionId()); final Transport transport = event.getTransport(); @@ -134,7 +134,7 @@ public void onConnectionBound(Event event) { @Override public void onConnectionUnbound(Event event) { final Connection connection = event.getConnection(); - logger.asInfo().log("onConnectionUnbound hostname[{}], connectionId[{}], state[{}], remoteState[{}]", + logger.info("onConnectionUnbound hostname[{}], connectionId[{}], state[{}], remoteState[{}]", connection.getHostname(), getConnectionId(), connection.getLocalState(), connection.getRemoteState()); // if failure happened while establishing transport - nothing to free up. @@ -151,7 +151,7 @@ public void onTransportError(Event event) { final Transport transport = event.getTransport(); final ErrorCondition condition = transport.getCondition(); - logger.asWarning().log("onTransportError hostname[{}], connectionId[{}], error[{}]", + logger.warning("onTransportError hostname[{}], connectionId[{}], error[{}]", connection != null ? connection.getHostname() : ClientConstants.NOT_APPLICABLE, getConnectionId(), condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -171,7 +171,7 @@ public void onTransportClosed(Event event) { final Transport transport = event.getTransport(); final ErrorCondition condition = transport.getCondition(); - logger.asInfo().log("onTransportClosed hostname[{}], connectionId[{}], error[{}]", + logger.info("onTransportClosed hostname[{}], connectionId[{}], error[{}]", connection != null ? connection.getHostname() : ClientConstants.NOT_APPLICABLE, getConnectionId(), condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -194,7 +194,7 @@ public void onConnectionLocalOpen(Event event) { public void onConnectionRemoteOpen(Event event) { final Connection connection = event.getConnection(); - logger.asInfo().log("onConnectionRemoteOpen hostname[{}], connectionId[{}], remoteContainer[{}]", + logger.info("onConnectionRemoteOpen hostname[{}], connectionId[{}], remoteContainer[{}]", connection.getHostname(), getConnectionId(), connection.getRemoteContainer()); onNext(connection.getRemoteState()); @@ -271,7 +271,7 @@ private void notifyErrorContext(Connection connection, ErrorCondition condition) } private void logErrorCondition(String eventName, Connection connection, ErrorCondition error) { - logger.asInfo().log("{} hostname[{}], connectionId[{}], errorCondition[{}], errorDescription[{}]", + logger.info("{} hostname[{}], connectionId[{}], errorCondition[{}], errorDescription[{}]", eventName, connection.getHostname(), getConnectionId(), diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java similarity index 87% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java index f788c60faa29f..9b78d3cef1149 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/CustomIOHandler.java @@ -22,7 +22,7 @@ public void onTransportClosed(Event event) { final Transport transport = event.getTransport(); final Connection connection = event.getConnection(); - logger.asInfo().log("onTransportClosed name[{}], hostname[{}]", + logger.info("onTransportClosed name[{}], hostname[{}]", connectionId, (connection != null ? connection.getHostname() : "n/a")); if (transport != null && connection != null && connection.getTransport() != null) { @@ -32,7 +32,7 @@ public void onTransportClosed(Event event) { @Override public void onUnhandled(Event event) { - // logger.asVerbose().log("Unhandled event: {}, {}", event.getEventType(), event.toString()); + // logger.verbose("Unhandled event: {}, {}", event.getEventType(), event.toString()); super.onUnhandled(event); } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java similarity index 93% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java index 7d365514c540e..20084aabf2f46 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandler.java @@ -32,7 +32,7 @@ public DispatchHandler(Runnable work) { */ @Override public void onTimerTask(Event e) { - logger.asVerbose().log("Running task for event: %s", e); + logger.verbose("Running task for event: %s", e); this.work.run(); } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/Handler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/Handler.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/Handler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/Handler.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java similarity index 86% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java index 1d75ebb42c429..ee582c8b23a17 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/LinkHandler.java @@ -32,7 +32,7 @@ public void onLinkLocalClose(Event event) { final Link link = event.getLink(); final ErrorCondition condition = link.getCondition(); - logger.asInfo().log("onLinkLocalClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", + logger.info("onLinkLocalClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", getConnectionId(), link.getName(), condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -45,7 +45,7 @@ public void onLinkRemoteClose(Event event) { final Link link = event.getLink(); final ErrorCondition condition = link.getRemoteCondition(); - logger.asInfo().log("onLinkRemoteClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", + logger.info("onLinkRemoteClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", getConnectionId(), link.getName(), condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -58,7 +58,7 @@ public void onLinkRemoteDetach(Event event) { final Link link = event.getLink(); final ErrorCondition condition = link.getCondition(); - logger.asInfo().log("onLinkRemoteClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", + logger.info("onLinkRemoteClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", getConnectionId(), link.getName(), condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -68,7 +68,7 @@ public void onLinkRemoteDetach(Event event) { @Override public void onLinkFinal(Event event) { - logger.asInfo().log("onLinkFinal clientName[{}], linkName[{}]", getConnectionId(), event.getLink().getName()); + logger.info("onLinkFinal clientName[{}], linkName[{}]", getConnectionId(), event.getLink().getName()); close(); } @@ -84,7 +84,7 @@ public ErrorContext getErrorContext(Link link) { } private void processOnClose(Link link, ErrorCondition condition) { - logger.asInfo().log("processOnClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", + logger.info("processOnClose connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", getConnectionId(), link.getName(), condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -103,7 +103,7 @@ private void closeSession(Link link, ErrorCondition condition) { final Session session = link.getSession(); if (session != null && session.getLocalState() != EndpointState.CLOSED) { - logger.asInfo().log("closeSession connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", + logger.info("closeSession connectionId[{}], linkName[{}], errorCondition[{}], errorDescription[{}]", getConnectionId(), link.getName(), condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java similarity index 89% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java index 143879e53ae5f..8d85642578e42 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReactorHandler.java @@ -30,7 +30,7 @@ public ReactorHandler(final String name) { @Override public void onReactorInit(Event e) { - logger.asInfo().log("name[{}] reactor.onReactorInit", name); + logger.info("name[{}] reactor.onReactorInit", name); final Reactor reactor = e.getReactor(); reactor.setTimeout(REACTOR_IO_POLL_TIMEOUT); @@ -38,6 +38,6 @@ public void onReactorInit(Event e) { @Override public void onReactorFinal(Event e) { - logger.asInfo().log("name[{}] reactor.onReactorFinal", name); + logger.info("name[{}] reactor.onReactorFinal", name); } } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java similarity index 84% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java index 0f9f5edee8161..0a14387f54476 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/ReceiveLinkHandler.java @@ -42,7 +42,7 @@ public void close() { public void onLinkLocalOpen(Event event) { final Link link = event.getLink(); if (link instanceof Receiver) { - logger.asVerbose().log("onLinkLocalOpen receiverName[{}], linkName[{}], localSource[{}]", + logger.verbose("onLinkLocalOpen receiverName[{}], linkName[{}], localSource[{}]", receiverName, link.getName(), link.getSource()); } } @@ -52,14 +52,14 @@ public void onLinkRemoteOpen(Event event) { final Link link = event.getLink(); if (link instanceof Receiver) { if (link.getRemoteSource() != null) { - logger.asInfo().log("onLinkRemoteOpen receiverName[{}], linkName[{}], remoteSource[{}]", + logger.info("onLinkRemoteOpen receiverName[{}], linkName[{}], remoteSource[{}]", receiverName, link.getName(), link.getRemoteSource()); if (isFirstResponse.getAndSet(false)) { onNext(EndpointState.ACTIVE); } } else { - logger.asInfo().log("onLinkRemoteOpen receiverName[{}], linkName[{}], action[waitingForError]", + logger.info("onLinkRemoteOpen receiverName[{}], linkName[{}], action[waitingForError]", receiverName, link.getName()); } } @@ -83,11 +83,11 @@ public void onDelivery(Event event) { // before we fix proton-j - this work around ensures that we ignore the duplicate Delivery event if (delivery.isSettled()) { if (link != null) { - logger.asInfo().log("onDelivery receiverName[{}], linkName[{}], updatedLinkCredit[{}], remoteCredit[{}], " + logger.info("onDelivery receiverName[{}], linkName[{}], updatedLinkCredit[{}], remoteCredit[{}], " + "remoteCondition[{}], delivery.isSettled[{}]", receiverName, link.getName(), link.getCredit(), link.getRemoteCredit(), link.getRemoteCondition(), delivery.isSettled()); } else { - logger.asWarning().log("delivery.isSettled[{}]", delivery.isSettled()); + logger.warning("delivery.isSettled[{}]", delivery.isSettled()); } } else { deliverySink.next(delivery); @@ -95,7 +95,7 @@ public void onDelivery(Event event) { } if (link != null) { - logger.asVerbose().log("onDelivery receiverName[{}], linkName[{}], updatedLinkCredit[{}], remoteCredit[{}], " + logger.verbose("onDelivery receiverName[{}], linkName[{}], updatedLinkCredit[{}], remoteCredit[{}], " + "remoteCondition[{}], delivery.isPartial[{}]", receiverName, link.getName(), link.getCredit(), link.getRemoteCredit(), link.getRemoteCondition(), delivery.isPartial()); } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java similarity index 84% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java index 26740bbd5198b..cf04b211f5c41 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SendLinkHandler.java @@ -49,7 +49,7 @@ public void close() { public void onLinkLocalOpen(Event event) { final Link link = event.getLink(); if (link instanceof Sender) { - logger.asVerbose().log("onLinkLocalOpen senderName[{}], linkName[{}], localTarget[{}]", + logger.verbose("onLinkLocalOpen senderName[{}], linkName[{}], localTarget[{}]", senderName, link.getName(), link.getTarget()); } } @@ -59,14 +59,14 @@ public void onLinkRemoteOpen(Event event) { final Link link = event.getLink(); if (link instanceof Sender) { if (link.getRemoteTarget() != null) { - logger.asInfo().log("onLinkRemoteOpen senderName[{}], linkName[{}], remoteTarget[{}]", + logger.info("onLinkRemoteOpen senderName[{}], linkName[{}], remoteTarget[{}]", senderName, link.getName(), link.getRemoteTarget()); if (isFirstFlow.getAndSet(false)) { onNext(EndpointState.ACTIVE); } } else { - logger.asInfo().log("onLinkRemoteOpen senderName[{}], linkName[{}], remoteTarget[null], remoteSource[null], action[waitingForError]", + logger.info("onLinkRemoteOpen senderName[{}], linkName[{}], remoteTarget[null], remoteSource[null], action[waitingForError]", senderName, link.getName()); } } @@ -81,7 +81,7 @@ public void onLinkFlow(Event event) { final Sender sender = event.getSender(); creditSink.next(sender.getRemoteCredit()); - logger.asVerbose().log("onLinkFlow senderName[{}], linkName[{}], unsettled[{}], credit[{}]", + logger.verbose("onLinkFlow senderName[{}], linkName[{}], unsettled[{}], credit[{}]", senderName, sender.getName(), sender.getUnsettled(), sender.getCredit()); } @@ -92,7 +92,7 @@ public void onDelivery(Event event) { while (delivery != null) { Sender sender = (Sender) delivery.getLink(); - logger.asInfo().log("onDelivery senderName[{}], linkName[{}], unsettled[{}], credit[{}], deliveryState[{}], delivery.isBuffered[{}], delivery.id[{}]", + logger.info("onDelivery senderName[{}], linkName[{}], unsettled[{}], credit[{}], deliveryState[{}], delivery.isBuffered[{}], delivery.id[{}]", senderName, sender.getName(), sender.getUnsettled(), sender.getRemoteCredit(), delivery.getRemoteState(), delivery.isBuffered(), new String(delivery.getTag(), StandardCharsets.UTF_8)); diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java similarity index 90% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java index b7365737e6c0d..80b7bfccbde70 100644 --- a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java +++ b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/SessionHandler.java @@ -40,7 +40,7 @@ public ErrorContext getErrorContext() { @Override public void onSessionLocalOpen(Event e) { - logger.asVerbose().log("onSessionLocalOpen connectionId[{}], entityName[{}], condition[{}]", + logger.verbose("onSessionLocalOpen connectionId[{}], entityName[{}], condition[{}]", getConnectionId(), this.entityName, e.getSession().getCondition() == null ? ClientConstants.NOT_APPLICABLE : e.getSession().getCondition().toString()); @@ -49,7 +49,7 @@ public void onSessionLocalOpen(Event e) { try { reactorDispatcher.invoke(this::onSessionTimeout, this.openTimeout); } catch (IOException ioException) { - logger.asWarning().log("onSessionLocalOpen connectionId[{}], entityName[{}], reactorDispatcherError[{}]", + logger.warning("onSessionLocalOpen connectionId[{}], entityName[{}], reactorDispatcherError[{}]", getConnectionId(), this.entityName, ioException.getMessage()); @@ -67,7 +67,7 @@ public void onSessionLocalOpen(Event e) { public void onSessionRemoteOpen(Event e) { final Session session = e.getSession(); - logger.asInfo().log( + logger.info( "onSessionRemoteOpen connectionId[{}], entityName[{}], sessionIncCapacity[{}], sessionOutgoingWindow[{}]", getConnectionId(), entityName, session.getIncomingCapacity(), session.getOutgoingWindow()); @@ -82,7 +82,7 @@ public void onSessionRemoteOpen(Event e) { public void onSessionLocalClose(Event e) { final ErrorCondition condition = e.getSession().getCondition(); - logger.asVerbose().log("onSessionLocalClose connectionId[{}], entityName[{}], condition[{}]", + logger.verbose("onSessionLocalClose connectionId[{}], entityName[{}], condition[{}]", entityName, getConnectionId(), condition == null ? ClientConstants.NOT_APPLICABLE : condition.toString()); } @@ -91,14 +91,14 @@ entityName, getConnectionId(), public void onSessionRemoteClose(Event e) { final Session session = e.getSession(); - logger.asInfo().log("onSessionRemoteClose connectionId[{}], entityName[{}], condition[{}]", + logger.info("onSessionRemoteClose connectionId[{}], entityName[{}], condition[{}]", entityName, getConnectionId(), session == null || session.getRemoteCondition() == null ? ClientConstants.NOT_APPLICABLE : session.getRemoteCondition().toString()); ErrorCondition condition = session != null ? session.getRemoteCondition() : null; if (session != null && session.getLocalState() != EndpointState.CLOSED) { - logger.asInfo().log( + logger.info( "onSessionRemoteClose closing a local session for connectionId[{}], entityName[{}], condition[{}], description[{}]", getConnectionId(), entityName, condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, @@ -124,7 +124,7 @@ public void onSessionFinal(Event e) { final Session session = e.getSession(); final ErrorCondition condition = session != null ? session.getCondition() : null; - logger.asInfo().log("onSessionFinal connectionId[{}], entityName[{}], condition[{}], description[{}]", + logger.info("onSessionFinal connectionId[{}], entityName[{}], condition[{}], description[{}]", getConnectionId(), entityName, condition != null ? condition.getCondition() : ClientConstants.NOT_APPLICABLE, condition != null ? condition.getDescription() : ClientConstants.NOT_APPLICABLE); @@ -140,7 +140,7 @@ private void onSessionTimeout() { // TODO: handle timeout error once the proton-j bug is fixed. // if (!sessionCreated && !sessionOpenErrorDispatched) { - // logger.asWarning().log( + // logger.warning( // "SessionTimeoutHandler.onEvent - connectionId[{}], entityName[{}], session open timed out.", // this.connectionId, this.entityName); // } diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/package-info.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/package-info.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/package-info.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/handler/package-info.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/package-info.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/package-info.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/package-info.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/implementation/package-info.java diff --git a/eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/package-info.java b/sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/package-info.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/package-info.java rename to sdk/eventhubs/azure-eventhubs/src/main/java/com/azure/messaging/eventhubs/package-info.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/ConsumeEvent.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/ConsumeEvent.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/ConsumeEvent.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/ConsumeEvent.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java index 3f779a1c815da..aa1dfa9fcb95f 100644 --- a/eventhubs/client/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java +++ b/sdk/eventhubs/azure-eventhubs/src/samples/java/ConsumeEventsFromKnownSequenceNumberPosition.java @@ -66,7 +66,7 @@ public static void main(String[] args) throws InterruptedException, IOException System.out.println("Waiting for partition properties to complete..."); // Acquiring the semaphore so that this sample does not end before all the partition properties are fetched. semaphore.acquire(); - System.out.printf("Last enqueued sequence number: %s\n", lastEnqueuedSequenceNumber); + System.out.printf("Last enqueued sequence number: %s%n", lastEnqueuedSequenceNumber); // Make sure to have at least one non-empty event hub in order to continue the sample execution // if you don't have an non-empty event hub, try with another example 'SendEvent' in the same directory. diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/GetEventHubMetadata.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/GetEventHubMetadata.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/samples/java/GetEventHubMetadata.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/GetEventHubMetadata.java index 4716982af8eb2..f81a400160d4b 100644 --- a/eventhubs/client/azure-eventhubs/src/samples/java/GetEventHubMetadata.java +++ b/sdk/eventhubs/azure-eventhubs/src/samples/java/GetEventHubMetadata.java @@ -41,7 +41,7 @@ public static void main(String[] args) throws InterruptedException { System.out.println("The Event Hub has the following properties:"); System.out.printf( "Event Hub Name: %s; Partition Id: %s; Is partition empty? %s; First Sequence Number: %s; " - + "Last Enqueued Time: %s; Last Enqueued Sequence Number: %s; Last Enqueued Offset: %s \n", + + "Last Enqueued Time: %s; Last Enqueued Sequence Number: %s; Last Enqueued Offset: %s", properties.eventHubPath(), properties.id(), properties.isEmpty(), properties.beginningSequenceNumber(), properties.lastEnqueuedTime(), diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/PublishEvent.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEvent.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/PublishEvent.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEvent.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsToSpecificPartition.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsToSpecificPartition.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsToSpecificPartition.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsToSpecificPartition.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java similarity index 99% rename from eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java index ffed26869db69..e71a36f597936 100644 --- a/eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java +++ b/sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsWithCustomMetadata.java @@ -61,7 +61,7 @@ public static void main(String[] args) { EventData secEvent = new EventData("EventData Sample 2".getBytes(UTF_8)); secEvent.properties().put("EventType", "com.microsoft.samples.goodbye-event"); secEvent.properties().put("priority", "17"); - secEvent.properties().put("blob", true); + secEvent.properties().put("blob", 10); final Flux data = Flux.just(firstEvent, secEvent); diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsWithPartitionKey.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsWithPartitionKey.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/PublishEventsWithPartitionKey.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/PublishEventsWithPartitionKey.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventDataJavaDocCodeSamples.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventDataJavaDocCodeSamples.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventDataJavaDocCodeSamples.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventDataJavaDocCodeSamples.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubClientBuilderJavaDocCodeSamples.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubClientBuilderJavaDocCodeSamples.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubClientBuilderJavaDocCodeSamples.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubClientBuilderJavaDocCodeSamples.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubConsumerJavaDocCodeSamples.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubConsumerJavaDocCodeSamples.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubConsumerJavaDocCodeSamples.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubConsumerJavaDocCodeSamples.java diff --git a/eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubProducerJavaDocCodeSamples.java b/sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubProducerJavaDocCodeSamples.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubProducerJavaDocCodeSamples.java rename to sdk/eventhubs/azure-eventhubs/src/samples/java/com/azure/messaging/eventhubs/EventHubProducerJavaDocCodeSamples.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/BackCompatTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/BackCompatTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/BackCompatTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/BackCompatTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java similarity index 92% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java index 64f77935d101c..c1fb5c41fdeaf 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchIntegrationTest.java @@ -77,7 +77,7 @@ public void sendSmallEventsFullBatch() { while (batch.tryAdd(createData())) { // We only print every 100th item or it'll be really spammy. if (count % 100 == 0) { - logger.asVerbose().log("Batch size: {}", batch.getSize()); + logger.verbose("Batch size: {}", batch.getSize()); } count++; @@ -101,7 +101,7 @@ public void sendSmallEventsFullBatchPartitionKey() { while (batch.tryAdd(createData())) { // We only print every 100th item or it'll be really spammy. if (count % 100 == 0) { - logger.asVerbose().log("Batch size: {}", batch.getSize()); + logger.verbose("Batch size: {}", batch.getSize()); } count++; } @@ -152,16 +152,16 @@ public void sendBatchPartitionKeyValidate() throws InterruptedException { } if (isMatchingEvent(event, messageValue)) { - logger.asInfo().log("Event[{}] matched. Countdown: {}", event.sequenceNumber(), countDownLatch.getCount()); + logger.info("Event[{}] matched. Countdown: {}", event.sequenceNumber(), countDownLatch.getCount()); countDownLatch.countDown(); } else { - logger.asWarning().log(String.format("Event[%s] matched partition key, but not GUID. Expected: %s. Actual: %s", + logger.warning(String.format("Event[%s] matched partition key, but not GUID. Expected: %s. Actual: %s", event.sequenceNumber(), messageValue, event.properties().get(MESSAGE_TRACKING_ID))); } }, error -> { Assert.fail("An error should not have occurred:" + error.toString()); }, () -> { - logger.asInfo().log("Disposing of consumer now that the receive is complete."); + logger.info("Disposing of consumer now that the receive is complete."); dispose(consumer); }); }).collectList().block(TIMEOUT); @@ -178,7 +178,7 @@ public void sendBatchPartitionKeyValidate() throws InterruptedException { // Wait for all the events we sent to be received. countDownLatch.await(TIMEOUT.getSeconds(), TimeUnit.SECONDS); } finally { - logger.asInfo().log("Disposing of subscriptions."); + logger.info("Disposing of subscriptions."); subscriptions.dispose(); } diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataBatchTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventDataTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientBuilderTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientBuilderTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientBuilderTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientBuilderTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java similarity index 95% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java index 16df939807764..7d3deba988ecf 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientIntegrationTest.java @@ -165,10 +165,10 @@ public void parallelEventHubClients() throws InterruptedException { && event.properties().containsKey(messageTrackingId) && messageTrackingValue.equals(event.properties().get(messageTrackingId)); }).take(numberOfEvents).subscribe(event -> { - logger.asInfo().log("Event[{}] matched.", event.sequenceNumber()); + logger.info("Event[{}] matched.", event.sequenceNumber()); }, error -> Assert.fail("An error should not have occurred:" + error.toString()), () -> { long count = countDownLatch.getCount(); - logger.asInfo().log("Finished consuming events. Counting down: {}", count); + logger.info("Finished consuming events. Counting down: {}", count); countDownLatch.countDown(); }); @@ -183,9 +183,9 @@ public void parallelEventHubClients() throws InterruptedException { countDownLatch.await(TIMEOUT.getSeconds(), TimeUnit.SECONDS); Assert.assertEquals(0, countDownLatch.getCount()); - logger.asInfo().log("Completed successfully."); + logger.info("Completed successfully."); } finally { - logger.asInfo().log("Disposing of subscriptions, consumers and clients."); + logger.info("Disposing of subscriptions, consumers and clients."); subscriptions.dispose(); dispose(producer); diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientMetadataIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientMetadataIntegrationTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientMetadataIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubClientMetadataIntegrationTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java similarity index 96% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java index 19af067933ce6..dd512717b464d 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerIntegrationTest.java @@ -102,11 +102,11 @@ public void parallelCreationOfReceivers() { consumers[i] = consumer; final Disposable subscription = consumer.receive().take(numberOfEvents).subscribe(event -> { - logger.asInfo().log("Event[{}] received. partition: {}", event.sequenceNumber(), partitionId); + logger.info("Event[{}] received. partition: {}", event.sequenceNumber(), partitionId); }, error -> { Assert.fail("An error should not have occurred:" + error.toString()); }, () -> { - logger.asInfo().log("Disposing of consumer now that the receive is complete."); + logger.info("Disposing of consumer now that the receive is complete."); countDownLatch.countDown(); }); @@ -126,7 +126,7 @@ public void parallelCreationOfReceivers() { } catch (InterruptedException e) { Assert.fail("Countdown latch was interrupted:" + e.toString()); } finally { - logger.asInfo().log("Disposing of subscriptions, consumers, producers."); + logger.info("Disposing of subscriptions, consumers, producers."); subscriptions.dispose(); dispose(consumers); diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerOptionsTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerOptionsTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerOptionsTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerOptionsTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java similarity index 96% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java index 9052c7b044aa5..8b98ced4b4fb1 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubConsumerTest.java @@ -205,7 +205,7 @@ protected void hookOnNext(EventData value) { count.set(0); } - logger.asInfo().log("Event Received. {}", countDownLatch.getCount()); + logger.info("Event Received. {}", countDownLatch.getCount()); countDownLatch.countDown(); super.hookOnNext(value); } @@ -247,7 +247,7 @@ protected void hookOnNext(EventData value) { count.set(0); } - logger.asInfo().log("Event Received. {}", countDownLatch.getCount()); + logger.info("Event Received. {}", countDownLatch.getCount()); countDownLatch.countDown(); super.hookOnNext(value); } @@ -273,9 +273,9 @@ public void suppliesCreditsWhenSubscribers() { when(amqpReceiveLink.getCredits()).thenReturn(PREFETCH); final Disposable subscription = consumer.receive().subscribe( - e -> logger.asInfo().log("Event received"), + e -> logger.info("Event received"), error -> Assert.fail(error.toString()), - () -> logger.asInfo().log("Complete"), sub -> { + () -> logger.info("Complete"), sub -> { sub.request(backPressure); }); @@ -304,9 +304,9 @@ public void suppliesNoCreditsWhenNoSubscribers() { when(amqpReceiveLink.getCredits()).thenReturn(PREFETCH); final Disposable subscription = consumer.receive().subscribe( - e -> logger.asInfo().log("Event received"), + e -> logger.info("Event received"), error -> Assert.fail(error.toString()), - () -> logger.asInfo().log("Complete"), + () -> logger.info("Complete"), sub -> sub.request(backPressure)); // Capturing the credit supplier that we set when the link was received. diff --git a/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerOptionsTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerOptionsTest.java new file mode 100644 index 0000000000000..12db5b6cc92da --- /dev/null +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerOptionsTest.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.eventhubs; + +import com.azure.core.amqp.ExponentialRetry; +import com.azure.core.amqp.Retry; +import org.junit.Assert; +import org.junit.Test; + +import java.time.Duration; + +public class EventHubProducerOptionsTest { + @Test + public void cloneProperties() { + // Arrange + String partitionId = "my-partition-id"; + Duration timeout = Duration.ofMinutes(10); + Retry retry = new ExponentialRetry(Duration.ofSeconds(20), Duration.ofSeconds(30), 3); + EventHubProducerOptions options = new EventHubProducerOptions(); + + options.partitionId(partitionId) + .timeout(timeout) + .retry(retry) + .partitionId(partitionId); + + // Act + EventHubProducerOptions clone = (EventHubProducerOptions) options.clone(); + + // Assert + Assert.assertEquals(partitionId, clone.partitionId()); + Assert.assertEquals(timeout, clone.timeout()); + Assert.assertEquals(retry, clone.retry()); + + Assert.assertNotSame(retry, clone.retry()); + } +} diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubProducerTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubPropertiesTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubPropertiesTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubPropertiesTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubPropertiesTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredentialTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredentialTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredentialTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventHubSharedAccessKeyCredentialTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java index 90d2151dd9e98..d9337acf5435b 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/EventPositionIntegrationTest.java @@ -332,11 +332,11 @@ public void receiveMessageFromSequenceNumberNonInclusive() { */ private void setupEventTestData(EventHubClient client) { if (HAS_PUSHED_EVENTS.getAndSet(true)) { - logger.asInfo().log("Already pushed events to partition. Skipping."); + logger.info("Already pushed events to partition. Skipping."); return; } - logger.asInfo().log("Pushing events to partition. Message tracking value: {}", MESSAGE_TRACKING_VALUE); + logger.info("Pushing events to partition. Message tracking value: {}", MESSAGE_TRACKING_VALUE); final EventHubProducerOptions producerOptions = new EventHubProducerOptions().partitionId(PARTITION_ID); final EventHubProducer producer = client.createProducer(producerOptions); @@ -351,7 +351,7 @@ private void setupEventTestData(EventHubClient client) { } // Receiving back those events we sent so we have something to compare to. - logger.asInfo().log("Receiving the events we sent."); + logger.info("Receiving the events we sent."); final EventHubConsumer consumer = client.createConsumer(DEFAULT_CONSUMER_GROUP_NAME, PARTITION_ID, EventPosition.fromEnqueuedTime(MESSAGES_PUSHED_INSTANT.get())); final List receivedEvents; diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java similarity index 98% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java index 92e7635468b9a..d8d47b64accaf 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/InteropAmqpPropertiesTest.java @@ -160,8 +160,8 @@ private void validateAmqpProperties(Message message, Map message Assert.assertTrue(actual.systemProperties().containsKey(MessageConstant.REPLY_TO.getValue())); Assert.assertEquals(message.getReplyTo(), actual.systemProperties().get(MessageConstant.REPLY_TO.getValue())); - Assert.assertTrue(actual.systemProperties().containsKey(MessageConstant.ABSOLUTE_EXPRITY_TIME.getValue())); - Assert.assertEquals(message.getExpiryTime(), actual.systemProperties().get(MessageConstant.ABSOLUTE_EXPRITY_TIME.getValue())); + Assert.assertTrue(actual.systemProperties().containsKey(MessageConstant.ABSOLUTE_EXPIRY_TIME.getValue())); + Assert.assertEquals(message.getExpiryTime(), actual.systemProperties().get(MessageConstant.ABSOLUTE_EXPIRY_TIME.getValue())); Assert.assertEquals(PAYLOAD, UTF_8.decode(actual.body()).toString()); diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/PartitionPropertiesTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/PartitionPropertiesTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/PartitionPropertiesTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/PartitionPropertiesTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/ProxyConfigurationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/ProxyConfigurationTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/ProxyConfigurationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/ProxyConfigurationTest.java diff --git a/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SendOptionsTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SendOptionsTest.java new file mode 100644 index 0000000000000..141ee2e961fd6 --- /dev/null +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SendOptionsTest.java @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.eventhubs; + +import org.junit.Assert; +import org.junit.Test; + +public class SendOptionsTest { + + /** + * Verifies that the default values are correctly set when creating an instance. + */ + @Test + public void createDefault() { + SendOptions options = new SendOptions(); + + Assert.assertEquals(EventHubProducer.MAX_MESSAGE_LENGTH_BYTES, options.maximumSizeInBytes()); + Assert.assertNull(options.partitionKey()); + } + + /** + * Verifies we can set maximumSizeInBytes on the send options. + */ + @Test + public void setMaximumSize() { + int size = 1024; + SendOptions options = new SendOptions(); + + options.maximumSizeInBytes(size); + + Assert.assertEquals(size, options.maximumSizeInBytes()); + Assert.assertNull(options.partitionKey()); + } + + /** + * Verifies we can set partitionKey on the send options. + */ + @Test + public void setPartitionKey() { + String partitionKey = "My partition key"; + SendOptions options = new SendOptions(); + + options.partitionKey(partitionKey); + + Assert.assertEquals(EventHubProducer.MAX_MESSAGE_LENGTH_BYTES, options.maximumSizeInBytes()); + Assert.assertEquals(partitionKey, options.partitionKey()); + } + + /** + * Verifies we can create a clone that is independent of the original. + */ + @Test + public void cloneIdentical() { + // Arrange + String partitionKey = "My partition key"; + int size = 800; + SendOptions options = new SendOptions().partitionKey(partitionKey).maximumSizeInBytes(size); + + // Act + SendOptions clone = options.clone(); + + // Assert + Assert.assertNotSame(clone, options); + Assert.assertEquals(size, options.maximumSizeInBytes()); + Assert.assertEquals(partitionKey, options.partitionKey()); + + Assert.assertEquals(partitionKey, clone.partitionKey()); + Assert.assertEquals(size, clone.maximumSizeInBytes()); + } + + + /** + * Verifies we can modify contents of the clone without affecting the original. + */ + @Test + public void cloneModifyContents() { + // Arrange + String originalPartitionKey = "Some partition key"; + int originalSize = 100; + + String partitionKey = "A new partition key"; + int size = 24; + + SendOptions options = new SendOptions().partitionKey(originalPartitionKey).maximumSizeInBytes(originalSize); + SendOptions clone = options.clone(); + + // Act + clone.partitionKey(partitionKey) + .maximumSizeInBytes(size); + + // Assert + Assert.assertEquals(partitionKey, clone.partitionKey()); + Assert.assertEquals(size, clone.maximumSizeInBytes()); + + Assert.assertEquals(originalSize, options.maximumSizeInBytes()); + Assert.assertEquals(originalPartitionKey, options.partitionKey()); + } +} diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SetPrefetchCountTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SetPrefetchCountTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SetPrefetchCountTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/SetPrefetchCountTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/TestUtils.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/TestUtils.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/TestUtils.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/TestUtils.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManagerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManagerTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManagerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ActiveClientTokenManagerTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java similarity index 96% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java index 9593553705881..544c105838d2e 100644 --- a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java +++ b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ApiTestBase.java @@ -56,7 +56,7 @@ protected ApiTestBase(ClientLogger logger) { @Override @Before public void setupTest() { - logger.asInfo().log("[{}]: Performing test set-up.", testName()); + logger.info("[{}]: Performing test set-up.", testName()); final Scheduler scheduler = Schedulers.newElastic("AMQPConnection"); final String connectionString = getTestMode() == TestMode.RECORD @@ -95,7 +95,7 @@ tokenCredential, getAuthorizationType(), TIMEOUT, TransportType.AMQP, Retry.getN @Override @After public void teardownTest() { - logger.asInfo().log("[{}]: Performing test clean-up.", testName()); + logger.info("[{}]: Performing test clean-up.", testName()); afterTest(); @@ -169,7 +169,7 @@ protected void dispose(Closeable... closeables) { try { closeable.close(); } catch (IOException error) { - logger.asError().log(String.format("[%s]: %s didn't close properly.", + logger.error(String.format("[%s]: %s didn't close properly.", testName(), closeable.getClass().getSimpleName()), error); } } diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/CBSChannelTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/CBSChannelTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/CBSChannelTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/CBSChannelTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ConnectionStringPropertiesTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ConnectionStringPropertiesTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ConnectionStringPropertiesTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ConnectionStringPropertiesTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBaseTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBaseTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBaseTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/EndpointStateNotifierBaseTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorHandlerProvider.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorHandlerProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorHandlerProvider.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorHandlerProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorProvider.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorProvider.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorProvider.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/MockReactorProvider.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionIntegrationTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionIntegrationTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionIntegrationTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionIntegrationTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorConnectionTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorReceiverTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorReceiverTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorReceiverTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorReceiverTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorSessionTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorSessionTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorSessionTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/ReactorSessionTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/TokenResourceProviderTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/TokenResourceProviderTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/TokenResourceProviderTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/TokenResourceProviderTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandlerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandlerTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandlerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/ConnectionHandlerTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandlerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandlerTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandlerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/DispatchHandlerTest.java diff --git a/eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/HandlerTest.java b/sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/HandlerTest.java similarity index 100% rename from eventhubs/client/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/HandlerTest.java rename to sdk/eventhubs/azure-eventhubs/src/test/java/com/azure/messaging/eventhubs/implementation/handler/HandlerTest.java diff --git a/sdk/eventhubs/ci.yml b/sdk/eventhubs/ci.yml new file mode 100644 index 0000000000000..545d53726cace --- /dev/null +++ b/sdk/eventhubs/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/eventhubs/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/eventhubs/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: eventhubs \ No newline at end of file diff --git a/sdk/eventhubs/pom.service.xml b/sdk/eventhubs/pom.service.xml new file mode 100644 index 0000000000000..2f81bff7b40e9 --- /dev/null +++ b/sdk/eventhubs/pom.service.xml @@ -0,0 +1,15 @@ + + + 4.0.0 + com.azure + azure-eventhubs-service + pom + 1.0.0 + + ../../core + azure-eventhubs + + diff --git a/sdk/identity/azure-identity/CHANGELOG.md b/sdk/identity/azure-identity/CHANGELOG.md new file mode 100644 index 0000000000000..6d34d9d480db4 --- /dev/null +++ b/sdk/identity/azure-identity/CHANGELOG.md @@ -0,0 +1,16 @@ +# Release History + +## 1.0.0-preview.1 (2019-06-28) +Version 1.0.0-preview.1 is a preview of our efforts in creating an authentication API for Azure SDK client libraries that is developer-friendly, idiomatic +to the Java ecosystem, and as consistent across different languages and platforms as possible. The principles that guide +our efforts can be found in the [Azure SDK Design Guidelines for Java](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html). + +For details on the Azure SDK for Java (July 2019 Preview) release, you can refer to the [release announcement](https://aka.ms/azure-sdk-preview1-java). + +This release supports service principal and managed identity authentication. +See the [documentation](https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/identity/azure-identity/README.md) +for more details. User authentication will be added in an upcoming preview +release. + +This release supports only global Azure Active Directory tenants, i.e. those +using the https://login.microsoftonline.com authentication endpoint. diff --git a/sdk/identity/azure-identity/README.md b/sdk/identity/azure-identity/README.md new file mode 100644 index 0000000000000..cf15b30093182 --- /dev/null +++ b/sdk/identity/azure-identity/README.md @@ -0,0 +1,184 @@ +# Azure Identity client library for Java +The Azure Identity library provides Azure Active Directory token authentication support across the Azure SDK. It provides a set of TokenCredential implementations which can be used to construct Azure SDK clients which support AAD token authentication. + + This library is in preview and currently supports: + - [Service principal authentication](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals) + - [Managed identity authentication](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) + + [Source code][source] | API reference documentation (Coming Soon) | [Azure Active Directory documentation][aad_doc] + +## Getting started +### Adding the package to your project + +Maven dependency for Azure Secret Client library. Add it to your project's pom file. +```xml + + com.azure + azure-identity + 1.0.0-preview.1 + +``` + +### Prerequisites +* An [Azure subscription][azure_sub]. +* An existing Azure Active Directory service principal. If you need to create a service principal, you can use the Azure Portal or [Azure CLI][azure_cli]. + +#### Creating a Service Principal with the Azure CLI +Use the [Azure CLI][azure_cli] snippet below to create/get client secret credentials. + + * Create a service principal and configure its access to Azure resources: + ```bash + az ad sp create-for-rbac -n --skip-assignment + ``` + Output: + ```json + { + "appId": "generated-app-ID", + "displayName": "dummy-app-name", + "name": "http://dummy-app-name", + "password": "random-password", + "tenant": "tenant-ID" + } + ``` +* Use the returned credentials above to set **AZURE_CLIENT_ID**(appId), **AZURE_CLIENT_SECRET**(password) and **AZURE_TENANT_ID**(tenant) [environment variables](#environment-variables). + + +## Key concepts +### Credentials + +A credential is a class which contains or can obtain the data needed for a service client to authenticate requests. Service clients across Azure SDK accept credentials when they are constructed and use those credentials to authenticate requests to the service.Azure Identity offers a variety of credential classes in the `azure-identity` package capable of acquiring an AAD token. All of these credential classes are implementations of the `TokenCredential` abstract class in [Azure Core][azure_core_library], and can be used by any service client which can be constructed with a `TokenCredential`. + + +The credential types in Azure Identity differ in the types of AAD identities they can authenticate and how they are configured: + +|credential class|identity|configuration +|-|-|- +|`DefaultAzureCredential`|service principal or managed identity|none for managed identity; [environment variables](#environment-variables) for service principal +|`ManagedIdentityCredential`|managed identity|constructor parameters +|`EnvironmentCredential`|service principal|[environment variables](#environment-variables) +|`ClientSecretCredential`|service principal|constructor parameters +|`ClientCertificateCredential`|service principal|constructor parameters + +Credentials can be chained together to be tried in turn until one succeeds using the `ChainedTokenCredential`; see [chaining credentials](#chaining-credentials) for details. + +## DefaultAzureCredential +`DefaultAzureCredential` is appropriate for most scenarios where the application is intended to run in the Azure Cloud. This is because the `DefaultAzureCredential` determines the appropriate credential type based of the environment it is executing in. It supports authenticating both as a service principal or managed identity, and can be configured so that it will work both in a local development environment or when deployed to the cloud. + +The `DefaultAzureCredential` will first attempt to authenticate using credentials provided in the environment. In a development environment you can authenticate as a service principal with the `DefaultAzureCredential` by providing configuration in environment variables as described in the next section. + +If the environment configuration is not present or incomplete, the `DefaultAzureCredential` will then determine if a managed identity is available in the current environment. Authenticating as a managed identity requires no configuration, but does +require platform support. See the +[managed identity documentation](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/services-support-managed-identities) for more details on this. + +## Environment variables + +`DefaultAzureCredential` and `EnvironmentCredential` are configured for service +principal authentication with these environment variables: + +|variable name|value +|-|- +|`AZURE_CLIENT_ID`|service principal's app id +|`AZURE_TENANT_ID`|id of the principal's Azure Active Directory tenant +|`AZURE_CLIENT_SECRET`|one of the service principal's client secrets + +# Examples + +## Authenticating with `DefaultAzureCredential` +This example demonstrates authenticating the `SecretClient` from the [azure-keyvault-secrets][secrets_client_library] client library using the `DefaultAzureCredential`. +```java +// The default credential first checks environment variables for configuration as described above. +// If environment configuration is incomplete, it will try managed identity. +import com.azure.identity.credential.DefaultAzureCredential; +import com.azure.security.keyvault.secrets.SecretClient; + +DefaultAzureCredential defaultCredential = new DefaultAzureCredential(); + +// Azure SDK client builders accept the credential as a parameter + +SecretClient client = SecretClient.builder() + .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") + .credential(credential) + .build(); +``` +When executing this in a development machine you need to first [configure the environment](#environment-variables) setting the variables `AZURE_CLIENT_ID`, `AZURE_TENANT_ID` and `AZURE_CLIENT_SECRET` to the appropriate values for your service principal. + +## Authenticating a service principal with a client secret +This example demonstrates authenticating the `KeyClient` from the [azure-keyvault-keys][keys_client_library] client library using the `ClientSecretCredential`. +```java +// using a client secret +import com.azure.identity.credential.ClientSecretCredential; +import com.azure.security.keyvault.keys.KeyClient; + +// authenticate with client secret, +ClientSecretCredential clientSecretCredential = new ClientSecretCredential() + .clientId("") + .clientSecret("") + .tenantId(""); + +KeyClient client = KeyClient.builder() + .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") + .credential(clientSecretCredential) + .build(); +``` + +## Chaining credentials: +The `ChainedTokenCredential` class provides the ability to link together multiple credential instances to be tried sequentially when authenticating. The following example demonstrates creating a credential which will attempt to authenticate using managed identity, and fall back to certificate authentication if a managed identity is unavailable in the current environment. This example authenticates an `EventHubClient` from the [azure-eventhubs][eventhubs_client_library] client library using the `ChainedTokenCredential`. + +```java +import com.azure.identity.credential.ClientSecretCredential; +import com.azure.security.keyvault.secrets.SecretClient; + +ManagedIdentityCredential managedIdentityCredential = new ManagedIdentityCredential() + .clientId(""); + +ClientSecretcredential secondServicePrincipal = new ClientSecretCredential() + .clientId("") + .clientSecret("") + .tenantId(""); + +// when an access token is requested, the chain will try each +// credential in order, stopping when one provides a token + +ChainedTokenCredential credentialChain = new ChainedTokenCredential() + .addLast(managedIdentityCredential) + .addLast(secondServicePrincipal); + +// the chain can be used anywhere a credential is required + +// The fully qualified host name for the Event Hubs namespace. This is likely to be similar to: +// {your-namespace}.servicebus.windows.net +String host = "<< EVENT HUBS HOST >>" +String eventHubPath = "<< NAME OF THE EVENT HUB >>"; +EventHubClient client = new EventHubClientBuilder() + .credential(host, eventHubPath, credentialChain) + .buildAsyncClient(); +``` + +## Troubleshooting +Credentials raise exceptions when they fail to authenticate. `ClientAuthenticationException` has a `message` attribute which +describes why authentication failed. When raised by `ChainedTokenCredential`, the message collects error messages from each credential in the chain. + +## Next steps +Currently the following client libraries support authenticating with `TokenCredential` and the Azure Identity library. You can learn more about their use, and find additional documentation on use of these client libraries along samples with can be found in the links below. + +- [azure-eventhubs][eventhubs_client_library] +- [azure-keyvault-keys][keys_client_library] +- [azure-keyvault-secrets][secrets_client_library] + +## Contributing +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. + + +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[source]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/identity/azure-identity +[aad_doc]: https://docs.microsoft.com/en-us/azure/active-directory/ +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ +[keys_client_library]: https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/ +[secrets_client_library]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/client/secrets/ +[eventhubs_client_library]: https://github.com/Azure/azure-sdk-for-java/tree/master/eventhubs/client/ +[azure_core_library]: https://github.com/Azure/azure-sdk-for-java/tree/master/core/ diff --git a/identity/client/pom.xml b/sdk/identity/azure-identity/pom.xml similarity index 91% rename from identity/client/pom.xml rename to sdk/identity/azure-identity/pom.xml index 64ccae2bceccc..e346e06f88f33 100644 --- a/identity/client/pom.xml +++ b/sdk/identity/azure-identity/pom.xml @@ -11,8 +11,8 @@ com.azure azure-client-sdk-parent - 1.0.0 - ../../pom.client.xml + 1.1.0 + ../../../pom.client.xml diff --git a/identity/client/src/main/java/com/azure/identity/IdentityClient.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/IdentityClient.java similarity index 92% rename from identity/client/src/main/java/com/azure/identity/IdentityClient.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/IdentityClient.java index ce0863799fdd7..88715ab17fa7d 100644 --- a/identity/client/src/main/java/com/azure/identity/IdentityClient.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/IdentityClient.java @@ -55,6 +55,7 @@ public IdentityClient() { /** * Creates an IdentityClient with the given options. + * * @param options the options configuring the client. */ public IdentityClient(IdentityClientOptions options) { @@ -63,10 +64,11 @@ public IdentityClient(IdentityClientOptions options) { /** * Asynchronously acquire a token from Active Directory with a client secret. - * @param tenantId the tenant ID of the application - * @param clientId the client ID of the application + * + * @param tenantId the tenant ID of the application + * @param clientId the client ID of the application * @param clientSecret the client secret of the application - * @param scopes the scopes to authenticate to + * @param scopes the scopes to authenticate to * @return a Publisher that emits an AccessToken */ public Mono authenticateWithClientSecret(String tenantId, String clientId, String clientSecret, String[] scopes) { @@ -85,11 +87,12 @@ public Mono authenticateWithClientSecret(String tenantId, String cl /** * Asynchronously acquire a token from Active Directory with a PKCS12 certificate. - * @param tenantId the tenant ID of the application - * @param clientId the client ID of the application - * @param pfxCertificatePath the path to the PKCS12 certificate of the application + * + * @param tenantId the tenant ID of the application + * @param clientId the client ID of the application + * @param pfxCertificatePath the path to the PKCS12 certificate of the application * @param pfxCertificatePassword the password protecting the PFX certificate - * @param scopes the scopes to authenticate to + * @param scopes the scopes to authenticate to * @return a Publisher that emits an AccessToken */ public Mono authenticateWithPfxCertificate(String tenantId, String clientId, String pfxCertificatePath, String pfxCertificatePassword, String[] scopes) { @@ -112,10 +115,11 @@ public Mono authenticateWithPfxCertificate(String tenantId, String /** * Asynchronously acquire a token from Active Directory with a PEM certificate. - * @param tenantId the tenant ID of the application - * @param clientId the client ID of the application + * + * @param tenantId the tenant ID of the application + * @param clientId the client ID of the application * @param pemCertificatePath the path to the PEM certificate of the application - * @param scopes the scopes to authenticate to + * @param scopes the scopes to authenticate to * @return a Publisher that emits an AccessToken */ public Mono authenticateWithPemCertificate(String tenantId, String clientId, String pemCertificatePath, String[] scopes) { @@ -149,12 +153,13 @@ private static AuthenticationContext createAuthenticationContext(ExecutorService return context; } - /** + /** * Asynchronously acquire a token from the App Service Managed Service Identity endpoint. + * * @param msiEndpoint the endpoint to acquire token from - * @param msiSecret the secret to acquire token with - * @param clientId the client ID of the application service - * @param scopes the scopes to authenticate to + * @param msiSecret the secret to acquire token with + * @param clientId the client ID of the application service + * @param scopes the scopes to authenticate to * @return a Publisher that emits an AccessToken */ public Mono authenticateToManagedIdentityEnpoint(String msiEndpoint, String msiSecret, String clientId, String[] scopes) { @@ -201,8 +206,9 @@ public Mono authenticateToManagedIdentityEnpoint(String msiEndpoint /** * Asynchronously acquire a token from the Virtual Machine IMDS endpoint. + * * @param clientId the client ID of the virtual machine - * @param scopes the scopes to authenticate to + * @param scopes the scopes to authenticate to * @return a Publisher that emits an AccessToken */ public Mono authenticateToIMDSEndpoint(String clientId, String[] scopes) { diff --git a/identity/client/src/main/java/com/azure/identity/IdentityClientOptions.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/IdentityClientOptions.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/IdentityClientOptions.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/IdentityClientOptions.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/AadCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/AadCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/AadCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/AadCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/AppServiceMSICredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/AppServiceMSICredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/AppServiceMSICredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/AppServiceMSICredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/ChainedTokenCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ChainedTokenCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/ChainedTokenCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ChainedTokenCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/ClientCertificateCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ClientCertificateCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/ClientCertificateCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ClientCertificateCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/ClientSecretCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ClientSecretCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/ClientSecretCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ClientSecretCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/DefaultAzureCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/DefaultAzureCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/DefaultAzureCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/DefaultAzureCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/EnvironmentCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/EnvironmentCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/EnvironmentCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/EnvironmentCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/ManagedIdentityCredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ManagedIdentityCredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/ManagedIdentityCredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/ManagedIdentityCredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/VirtualMachineMSICredential.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/VirtualMachineMSICredential.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/VirtualMachineMSICredential.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/VirtualMachineMSICredential.java diff --git a/identity/client/src/main/java/com/azure/identity/credential/package-info.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/package-info.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/credential/package-info.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/credential/package-info.java diff --git a/identity/client/src/main/java/com/azure/identity/implementation/MSIToken.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/MSIToken.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/implementation/MSIToken.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/MSIToken.java diff --git a/identity/client/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java similarity index 94% rename from identity/client/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java index 934f4cdbce2e4..723cedb30c66c 100644 --- a/identity/client/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java +++ b/sdk/identity/azure-identity/src/main/java/com/azure/identity/implementation/util/Adal4jUtil.java @@ -37,11 +37,11 @@ public final class Adal4jUtil { * @param callback the Mono emitter * @return the callback to pass into adal4j */ - public static AuthenticationCallback authenticationDelegate(final MonoSink callback) { - return new AuthenticationCallback() { + public static AuthenticationCallback authenticationDelegate(final MonoSink callback) { + return new AuthenticationCallback() { @Override - public void onSuccess(Object o) { - callback.success((AuthenticationResult) o); + public void onSuccess(AuthenticationResult o) { + callback.success(o); } @Override diff --git a/identity/client/src/main/java/com/azure/identity/package-info.java b/sdk/identity/azure-identity/src/main/java/com/azure/identity/package-info.java similarity index 100% rename from identity/client/src/main/java/com/azure/identity/package-info.java rename to sdk/identity/azure-identity/src/main/java/com/azure/identity/package-info.java diff --git a/identity/client/src/test/java/com/azure/identity/EnvironmentCredentialTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java similarity index 100% rename from identity/client/src/test/java/com/azure/identity/EnvironmentCredentialTests.java rename to sdk/identity/azure-identity/src/test/java/com/azure/identity/EnvironmentCredentialTests.java diff --git a/identity/client/src/test/java/com/azure/identity/ManagedIdentityCredentialTests.java b/sdk/identity/azure-identity/src/test/java/com/azure/identity/ManagedIdentityCredentialTests.java similarity index 100% rename from identity/client/src/test/java/com/azure/identity/ManagedIdentityCredentialTests.java rename to sdk/identity/azure-identity/src/test/java/com/azure/identity/ManagedIdentityCredentialTests.java diff --git a/sdk/identity/ci.yml b/sdk/identity/ci.yml new file mode 100644 index 0000000000000..ae4d32447fdfd --- /dev/null +++ b/sdk/identity/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/identity/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/identity/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: identity \ No newline at end of file diff --git a/sdk/identity/pom.service.xml b/sdk/identity/pom.service.xml new file mode 100644 index 0000000000000..6b09f2a0921b2 --- /dev/null +++ b/sdk/identity/pom.service.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.azure + azure-identity-service + pom + 1.0.0 + + azure-identity + + diff --git a/keyvault/data-plane/.gitignore b/sdk/keyvault/.gitignore similarity index 100% rename from keyvault/data-plane/.gitignore rename to sdk/keyvault/.gitignore diff --git a/sdk/keyvault/LICENSE b/sdk/keyvault/LICENSE new file mode 100644 index 0000000000000..21071075c2459 --- /dev/null +++ b/sdk/keyvault/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/keyvault/data-plane/README.md b/sdk/keyvault/README.md similarity index 100% rename from keyvault/data-plane/README.md rename to sdk/keyvault/README.md diff --git a/keyvault/data-plane/REGENERATING.md b/sdk/keyvault/REGENERATING.md similarity index 100% rename from keyvault/data-plane/REGENERATING.md rename to sdk/keyvault/REGENERATING.md diff --git a/sdk/keyvault/azure-keyvault-keys/CHANGELOG.md b/sdk/keyvault/azure-keyvault-keys/CHANGELOG.md new file mode 100644 index 0000000000000..63af0c66276ac --- /dev/null +++ b/sdk/keyvault/azure-keyvault-keys/CHANGELOG.md @@ -0,0 +1,34 @@ +# Release History + +## 4.0.0-preview.1 (2019-06-28) +Version 4.0.0-preview.1 is a preview of our efforts in creating a client library that is developer-friendly, idiomatic to the Java ecosystem, and as consistent across different languages and platforms as possible. The principles that guide our efforts can be found in the [Azure SDK Design Guidelines for Java](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html). + +For details on the Azure SDK for Java (July 2019 Preview) release, you can refer to the [release announcement](https://aka.ms/azure-sdk-preview1-java). + +This library is not a direct replacement for keys management operations from [microsoft-azure-keyvault](https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/microsoft-azure-keyvault). Applications using that library would require code changes to use `azure-keyvault-keys`. +This package's +[documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/README.md) +and +[samples](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java) +demonstrate the new API. + + +### Major changes from `azure-keyvault` +- Packages scoped by functionality + - `azure-keyvault-keys` contains a `KeyClient` and `KeyAsyncClient` for key operations, + `azure-keyvault-secrets` contains a `SecretClient` and `SecretAsyncClient` for secret operations +- Client instances are scoped to vaults (an instance interacts with one vault +only) +- Reactive streams support using [Project Reactor](https://projectreactor.io/). +- Authentication using `azure-identity` credentials + - see this package's + [documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/README.md) + , and the + [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/identity/azure-identity/README.md) + for more information + +### `azure-keyvault` features not implemented in this library +- Certificate management APIs +- Cryptographic operations, e.g. sign, un/wrap, verify, encrypt and decrypt +- National cloud support. This release supports public global cloud vaults, + e.g. https://{vault-name}.vault.azure.net diff --git a/keyvault/client/keys/README.md b/sdk/keyvault/azure-keyvault-keys/README.md similarity index 91% rename from keyvault/client/keys/README.md rename to sdk/keyvault/azure-keyvault-keys/README.md index c0747193da20c..33419a0b7dd58 100644 --- a/keyvault/client/keys/README.md +++ b/sdk/keyvault/azure-keyvault-keys/README.md @@ -12,9 +12,9 @@ Azure Key Vault allows you to create and store keys in the Key Vault. Azure Key Maven dependency for Azure Key Client library. Add it to your project's pom file. ```xml - com.azure.security + com.azure azure-keyvault-keys - 1.0.0-preview.1 + 4.0.0-preview.1 ``` @@ -78,10 +78,10 @@ Once you've populated the **AZURE_CLIENT_ID**, **AZURE_CLIENT_SECRET** and **AZU import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.keys.KeyClient; -KeyClient client = KeyClient.builder() +KeyClient client = new KeyClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildClient); ``` > NOTE: For using Asynchronous client use KeyAsyncClient instead of KeyClient @@ -116,10 +116,10 @@ import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.KeyClient; -KeyClient keyClient = KeyClient.builder() +KeyClient keyClient = new KeyClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); Key rsaKey = keyClient.createRsaKey(new RsaKeyCreateOptions("CloudRsaKey") .expires(OffsetDateTime.now().plusYears(1)) @@ -190,10 +190,10 @@ import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.KeyAsyncClient; -KeyAsyncClient keyAsyncClient = KeyAsyncClient.builder() +KeyAsyncClient keyAsyncClient = new KeyClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); keyAsyncClient.createRsaKey(new RsaKeyCreateOptions("CloudRsaKey") .expires(OffsetDateTime.now().plusYears(1)) @@ -302,7 +302,7 @@ When you submit a pull request, a CLA-bot will automatically determine whether y This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. -[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src +[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src [api_documentation]: not-valid-link [azkeyvault_docs]: https://docs.microsoft.com/en-us/azure/key-vault/ [azure_identity]: https://github.com/Azure/azure-sdk-for-java/tree/master/identity/client @@ -315,12 +315,12 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope [azure_create_application_in_portal]:https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal [azure_keyvault_cli]:https://docs.microsoft.com/en-us/azure/key-vault/quick-create-cli [azure_keyvault_cli_full]:https://docs.microsoft.com/en-us/cli/azure/keyvault?view=azure-cli-latest -[keys_samples]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys -[sample_helloWorld]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/HelloWorld.java -[sample_helloWorldAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/HelloWorldAsync.java -[sample_list]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/ListOperations.java -[sample_listAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/ListOperationsAsync.java -[sample_BackupRestore]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperations.java -[sample_BackupRestoreAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperationsAsync.java -[sample_ManageDeleted]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeys.java -[sample_ManageDeletedAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeysAsync.java +[keys_samples]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys +[sample_helloWorld]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorld.java +[sample_helloWorldAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorldAsync.java +[sample_list]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperations.java +[sample_listAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperationsAsync.java +[sample_BackupRestore]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperations.java +[sample_BackupRestoreAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperationsAsync.java +[sample_ManageDeleted]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeys.java +[sample_ManageDeletedAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeysAsync.java diff --git a/keyvault/client/keys/pom.xml b/sdk/keyvault/azure-keyvault-keys/pom.xml similarity index 93% rename from keyvault/client/keys/pom.xml rename to sdk/keyvault/azure-keyvault-keys/pom.xml index 64691e81960e2..340ef6f343eb3 100644 --- a/keyvault/client/keys/pom.xml +++ b/sdk/keyvault/azure-keyvault-keys/pom.xml @@ -6,7 +6,7 @@ azure-keyvault-parent com.azure 4.0.0-preview.1 - ../pom.xml + ../pom.client.xml 4.0.0 @@ -36,7 +36,7 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 @@ -59,7 +59,7 @@ com.azure azure-core-test - 1.0.0-preview.1 + 1.0.0-preview.3 test diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/AzureKeyVaultConfiguration.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/AzureKeyVaultConfiguration.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/AzureKeyVaultConfiguration.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/AzureKeyVaultConfiguration.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java similarity index 86% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java index 1020434051e20..da44d45f04a26 100644 --- a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java +++ b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClient.java @@ -43,17 +43,13 @@ * supports creating, retrieving, updating, deleting, purging, backing up, restoring and listing the {@link Key keys}. The client * also supports listing {@link DeletedKey deleted keys} for a soft-delete enabled Azure Key Vault. * - *

    Samples to construct the client

    - *
    - * KeyAsyncClient.builder()
    - *   .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net")
    - *   .credential(new DefaultAzureCredential())
    - *   .build()
    - * 
    + *

    Samples to construct the async client

    * - * @see KeyAsyncClientBuilder + * {@codesnippet com.azure.security.keyvault.keys.async.keyclient.instantiation} + * + * @see KeyClientBuilder */ -@ServiceClient(builder = KeyAsyncClientBuilder.class, isAsync = true, serviceInterfaces = KeyService.class) +@ServiceClient(builder = KeyClientBuilder.class, isAsync = true, serviceInterfaces = KeyService.class) public final class KeyAsyncClient { static final String API_VERSION = "7.0"; static final String ACCEPT_LANGUAGE = "en-US"; @@ -61,7 +57,7 @@ public final class KeyAsyncClient { static final String CONTENT_TYPE_HEADER_VALUE = "application/json"; static final String KEY_VAULT_SCOPE = "https://vault.azure.net/.default"; - private String endpoint; + private final String endpoint; private final KeyService service; private final ClientLogger logger = new ClientLogger(KeyAsyncClient.class); @@ -78,14 +74,6 @@ public final class KeyAsyncClient { this.service = RestProxy.create(KeyService.class, pipeline); } - /** - * Creates a builder that can configure options for the KeyAsyncClient before creating an instance of it. - * @return A new builder to create a KeyAsyncClient from. - */ - public static KeyAsyncClientBuilder builder() { - return new KeyAsyncClientBuilder(); - } - /** * Creates a new key and stores it in the key vault. The create key operation can be used to create any key type in * key vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the {@code keys/create} permission. @@ -109,9 +97,9 @@ public static KeyAsyncClientBuilder builder() { public Mono> createKey(String name, KeyType keyType) { KeyRequestParameters parameters = new KeyRequestParameters().kty(keyType); return service.createKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Creating key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Created key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to create key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Creating key - {}", name)) + .doOnSuccess(response -> logger.info("Created key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to create key - {}", name, error)); } /** @@ -149,9 +137,9 @@ public Mono> createKey(KeyCreateOptions keyCreateOptions) { .keyOps(keyCreateOptions.keyOperations()) .keyAttributes(new KeyRequestAttributes(keyCreateOptions)); return service.createKey(endpoint, keyCreateOptions.name(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Creating key - {}", keyCreateOptions.name())) - .doOnSuccess(response -> logger.asInfo().log("Created key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to create key - {}", keyCreateOptions.name(), error)); + .doOnRequest(ignored -> logger.info("Creating key - {}", keyCreateOptions.name())) + .doOnSuccess(response -> logger.info("Created key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to create key - {}", keyCreateOptions.name(), error)); } /** @@ -192,9 +180,9 @@ public Mono> createRsaKey(RsaKeyCreateOptions rsaKeyCreateOptions) .keyOps(rsaKeyCreateOptions.keyOperations()) .keyAttributes(new KeyRequestAttributes(rsaKeyCreateOptions)); return service.createKey(endpoint, rsaKeyCreateOptions.name(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Creating Rsa key - {}", rsaKeyCreateOptions.name())) - .doOnSuccess(response -> logger.asInfo().log("Created Rsa key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to create Rsa key - {}", rsaKeyCreateOptions.name(), error)); + .doOnRequest(ignored -> logger.info("Creating Rsa key - {}", rsaKeyCreateOptions.name())) + .doOnSuccess(response -> logger.info("Created Rsa key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to create Rsa key - {}", rsaKeyCreateOptions.name(), error)); } /** @@ -235,9 +223,9 @@ public Mono> createEcKey(EcKeyCreateOptions ecKeyCreateOptions) { .keyOps(ecKeyCreateOptions.keyOperations()) .keyAttributes(new KeyRequestAttributes(ecKeyCreateOptions)); return service.createKey(endpoint, ecKeyCreateOptions.name(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Creating Ec key - {}", ecKeyCreateOptions.name())) - .doOnSuccess(response -> logger.asInfo().log("Created Ec key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to create Ec key - {}", ecKeyCreateOptions.name(), error)); + .doOnRequest(ignored -> logger.info("Creating Ec key - {}", ecKeyCreateOptions.name())) + .doOnSuccess(response -> logger.info("Created Ec key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to create Ec key - {}", ecKeyCreateOptions.name(), error)); } /** @@ -260,9 +248,9 @@ public Mono> createEcKey(EcKeyCreateOptions ecKeyCreateOptions) { public Mono> importKey(String name, JsonWebKey keyMaterial) { KeyImportRequestParameters parameters = new KeyImportRequestParameters().key(keyMaterial); return service.importKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Importing key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Imported key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to import key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Importing key - {}", name)) + .doOnSuccess(response -> logger.info("Imported key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to import key - {}", name, error)); } /** @@ -298,9 +286,9 @@ public Mono> importKey(KeyImportOptions keyImportOptions) { .hsm(keyImportOptions.hsm()) .keyAttributes(new KeyRequestAttributes(keyImportOptions)); return service.importKey(endpoint, keyImportOptions.name(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Importing key - {}", keyImportOptions.name())) - .doOnSuccess(response -> logger.asInfo().log("Imported key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to import key - {}", keyImportOptions.name(), error)); + .doOnRequest(ignored -> logger.info("Importing key - {}", keyImportOptions.name())) + .doOnSuccess(response -> logger.info("Imported key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to import key - {}", keyImportOptions.name(), error)); } /** @@ -328,9 +316,9 @@ public Mono> getKey(String name, String version) { keyVersion = version; } return service.getKey(endpoint, name, keyVersion, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Retrieving key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Retrieving key - {}", name)) + .doOnSuccess(response -> logger.info("Retrieved key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get key - {}", name, error)); } /** @@ -353,9 +341,9 @@ public Mono> getKey(String name, String version) { */ public Mono> getKey(String name) { return getKey(name, "") - .doOnRequest(ignored -> logger.asInfo().log("Retrieving key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Retrieving key - {}", name)) + .doOnSuccess(response -> logger.info("Retrieved key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get key - {}", name, error)); } @@ -384,9 +372,9 @@ public Mono> getKey(KeyBase keyBase) { keyVersion = keyBase.version(); } return service.getKey(endpoint, keyBase.name(), keyVersion, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Retrieving key - {}", keyBase.name())) - .doOnSuccess(response -> logger.asInfo().log("Retrieved key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get key - {}", keyBase.name(), error)); + .doOnRequest(ignored -> logger.info("Retrieving key - {}", keyBase.name())) + .doOnSuccess(response -> logger.info("Retrieved key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get key - {}", keyBase.name(), error)); } /** @@ -420,9 +408,9 @@ public Mono> updateKey(KeyBase key) { .keyAttributes(new KeyRequestAttributes(key)); return service.updateKey(endpoint, key.name(), key.version(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Updating key - {}", key.name())) - .doOnSuccess(response -> logger.asInfo().log("Updated key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to update key - {}", key.name(), error)); + .doOnRequest(ignored -> logger.info("Updating key - {}", key.name())) + .doOnSuccess(response -> logger.info("Updated key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to update key - {}", key.name(), error)); } /** @@ -458,9 +446,9 @@ public Mono> updateKey(KeyBase key, KeyOperation... keyOperations) .keyAttributes(new KeyRequestAttributes(key)); return service.updateKey(endpoint, key.name(), key.version(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Updating key - {}", key.name())) - .doOnSuccess(response -> logger.asInfo().log("Updated key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to update key - {}", key.name(), error)); + .doOnRequest(ignored -> logger.info("Updating key - {}", key.name())) + .doOnSuccess(response -> logger.info("Updated key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to update key - {}", key.name(), error)); } /** @@ -485,9 +473,9 @@ public Mono> updateKey(KeyBase key, KeyOperation... keyOperations) */ public Mono> deleteKey(String name) { return service.deleteKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Deleting key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Deleted key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to delete key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Deleting key - {}", name)) + .doOnSuccess(response -> logger.info("Deleted key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to delete key - {}", name, error)); } /** @@ -510,9 +498,9 @@ public Mono> deleteKey(String name) { */ public Mono> getDeletedKey(String name) { return service.getDeletedKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Retrieving deleted key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved deleted key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Retrieving deleted key - {}", name)) + .doOnSuccess(response -> logger.info("Retrieved deleted key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get key - {}", name, error)); } /** @@ -535,9 +523,9 @@ public Mono> getDeletedKey(String name) { */ public Mono purgeDeletedKey(String name) { return service.purgeDeletedKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Purging deleted key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Purged deleted key - {}", name)) - .doOnError(error -> logger.asWarning().log("Failed to purge deleted key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Purging deleted key - {}", name)) + .doOnSuccess(response -> logger.info("Purged deleted key - {}", name)) + .doOnError(error -> logger.warning("Failed to purge deleted key - {}", name, error)); } /** @@ -561,9 +549,9 @@ public Mono purgeDeletedKey(String name) { */ public Mono> recoverDeletedKey(String name) { return service.recoverDeletedKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Recovering deleted key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Recovered deleted key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to recover deleted key - {}", name, error)); + .doOnRequest(ignored -> logger.info("Recovering deleted key - {}", name)) + .doOnSuccess(response -> logger.info("Recovered deleted key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to recover deleted key - {}", name, error)); } /** @@ -591,9 +579,9 @@ public Mono> recoverDeletedKey(String name) { */ public Mono> backupKey(String name) { return service.backupKey(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Backing up key - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Backed up key - {}", name)) - .doOnError(error -> logger.asWarning().log("Failed to backup key - {}", name, error)) + .doOnRequest(ignored -> logger.info("Backing up key - {}", name)) + .doOnSuccess(response -> logger.info("Backed up key - {}", name)) + .doOnError(error -> logger.warning("Failed to backup key - {}", name, error)) .flatMap(base64URLResponse -> Mono.just(new SimpleResponse(base64URLResponse.request(), base64URLResponse.statusCode(), base64URLResponse.headers(), base64URLResponse.value().value()))); } @@ -623,9 +611,9 @@ public Mono> backupKey(String name) { public Mono> restoreKey(byte[] backup) { KeyRestoreRequestParameters parameters = new KeyRestoreRequestParameters().keyBackup(backup); return service.restoreKey(endpoint, API_VERSION, parameters, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Attempting to restore key")) - .doOnSuccess(response -> logger.asInfo().log("Restored Key - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to restore key - {}", error)); + .doOnRequest(ignored -> logger.info("Attempting to restore key")) + .doOnSuccess(response -> logger.info("Restored Key - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to restore key - {}", error)); } /** @@ -645,9 +633,9 @@ public Mono> restoreKey(byte[] backup) { */ public Flux listKeys() { return service.getKeys(endpoint, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing keys")) - .doOnSuccess(response -> logger.asInfo().log("Listed keys")) - .doOnError(error -> logger.asWarning().log("Failed to list keys", error)) + .doOnRequest(ignored -> logger.info("Listing keys")) + .doOnSuccess(response -> logger.info("Listed keys")) + .doOnError(error -> logger.warning("Failed to list keys", error)) .flatMapMany(r -> extractAndFetchKeys(r, Context.NONE)); } @@ -668,9 +656,9 @@ public Flux listKeys() { */ public Flux listDeletedKeys() { return service.getDeletedKeys(endpoint, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing deleted keys")) - .doOnSuccess(response -> logger.asInfo().log("Listed deleted keys")) - .doOnError(error -> logger.asWarning().log("Failed to list deleted keys", error)) + .doOnRequest(ignored -> logger.info("Listing deleted keys")) + .doOnSuccess(response -> logger.info("Listed deleted keys")) + .doOnError(error -> logger.warning("Failed to list deleted keys", error)) .flatMapMany(r -> extractAndFetchDeletedKeys(r, Context.NONE)); } @@ -695,9 +683,9 @@ public Flux listDeletedKeys() { */ public Flux listKeyVersions(String name) { return service.getKeyVersions(endpoint, name, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing key versions - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Listed key versions - {}", name)) - .doOnError(error -> logger.asWarning().log(String.format("Failed to list key versions - {}", name), error)) + .doOnRequest(ignored -> logger.info("Listing key versions - {}", name)) + .doOnSuccess(response -> logger.info("Listed key versions - {}", name)) + .doOnError(error -> logger.warning(String.format("Failed to list key versions - {}", name), error)) .flatMapMany(r -> extractAndFetchKeys(r, Context.NONE)); } diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyBackup.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyBackup.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyBackup.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyBackup.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java similarity index 98% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java index 3d35c5668ed13..44e8bac28851e 100644 --- a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java +++ b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClient.java @@ -28,19 +28,14 @@ * supports creating, retrieving, updating, deleting, purging, backing up, restoring and listing the {@link Key keys}. The client * also supports listing {@link DeletedKey deleted keys} for a soft-delete enabled Azure Key Vault. * - *

    Samples to construct the client

    - *
    - * KeyClient.builder()
    - *   .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net")
    - *   .credential(new DefaultAzureCredential())
    - *   .build()
    - * 
    + *

    Samples to construct the sync client

    + * {@codesnippet com.azure.security.keyvault.keys.keyclient.instantiation} * * @see KeyClientBuilder */ @ServiceClient(builder = KeyClientBuilder.class, serviceInterfaces = KeyService.class) public final class KeyClient { - private KeyAsyncClient client; + private final KeyAsyncClient client; /** * Creates a KeyClient that uses {@code pipeline} to service requests @@ -51,14 +46,6 @@ public final class KeyClient { this.client = client; } - /** - * Creates a builder that can configure options for the KeyClient before creating an instance of it. - * @return A new builder to create a KeyClient from. - */ - public static KeyClientBuilder builder() { - return new KeyClientBuilder(); - } - /** * Creates a new key and stores it in the key vault. The create key operation can be used to create any key type in * key vault. If the named key already exists, Azure Key Vault creates a new version of the key. It requires the {@code keys/create} permission. diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClientBuilder.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java similarity index 60% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClientBuilder.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java index 373daceaab265..63cf4e554a5f8 100644 --- a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyAsyncClientBuilder.java +++ b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java @@ -15,6 +15,7 @@ import com.azure.core.http.policy.RetryPolicy; import com.azure.core.http.policy.UserAgentPolicy; import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.core.implementation.annotation.ServiceClientBuilder; import java.net.MalformedURLException; import java.net.URL; @@ -23,43 +24,35 @@ import java.util.Objects; /** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link KeyAsyncClient secret async client}, - * calling {@link KeyAsyncClientBuilder#build() build} constructs an instance of the client. + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link KeyAsyncClient secret async client} and {@link KeyClient secret sync client}, + * by calling {@link KeyClientBuilder#buildAsyncClient() buildAsyncClient} and {@link KeyClientBuilder#buildClient() buildClient} respectively + * It constructs an instance of the desired client. * - *

    The minimal configuration options required by {@link KeyAsyncClientBuilder secretClientBuilder} to build {@link KeyAsyncClient} + *

    The minimal configuration options required by {@link KeyClientBuilder} to build {@link KeyAsyncClient} * are {@link String endpoint} and {@link TokenCredential credential}.

    - *
    - * KeyAsyncClient.builder()
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .credential(new DefaultAzureCredential())
    - *   .build();
    - * 
    + * + * {@codesnippet com.azure.security.keyvault.keys.async.keyclient.instantiation} * *

    The {@link HttpLogDetailLevel log detail level}, multiple custom {@link HttpLoggingPolicy policies} and custom - * {@link HttpClient http client} can be optionally configured in the {@link KeyAsyncClientBuilder}.

    - *
    - * KeyAsyncClient secretAsyncClient = KeyAsyncClient.builder()
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .credential(new DefaultAzureCredential())
    - *   .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
    - *   .addPolicy(customPolicyOne)
    - *   .addPolicy(customPolicyTwo)
    - *   .httpClient(client)
    - *   .build();
    - * 
    + * {@link HttpClient http client} can be optionally configured in the {@link KeyClientBuilder}.

    + + * {@codesnippet com.azure.security.keyvault.keys.async.keyclient.withhttpclient.instantiation} * *

    Alternatively, custom {@link HttpPipeline http pipeline} with custom {@link HttpPipelinePolicy} policies and {@link String endpoint} - * can be specified. It provides finer control over the construction of {@link KeyAsyncClient client}

    - *
    - * KeyAsyncClient.builder()
    - *   .pipeline(new HttpPipeline(customPoliciesList))
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .build()
    - * 
    + * can be specified. It provides finer control over the construction of {@link KeyAsyncClient} and {@link KeyClient}

    + * + * {@codesnippet com.azure.security.keyvault.keys.async.keyclient.pipeline.instantiation} + * + *

    The minimal configuration options required by {@link KeyClientBuilder secretClientBuilder} to build {@link KeyClient} + * are {@link String endpoint} and {@link TokenCredential credential}.

    + * + * {@codesnippet com.azure.security.keyvault.keys.keyclient.instantiation} * * @see KeyAsyncClient + * @see KeyClient */ -public final class KeyAsyncClientBuilder { +@ServiceClientBuilder(serviceClients = KeyClient.class) +public final class KeyClientBuilder { private final List policies; private TokenCredential credential; private HttpPipeline pipeline; @@ -69,27 +62,47 @@ public final class KeyAsyncClientBuilder { private RetryPolicy retryPolicy; private Configuration configuration; - KeyAsyncClientBuilder() { + /** + * The constructor with defaults. + */ + public KeyClientBuilder() { retryPolicy = new RetryPolicy(); httpLogDetailLevel = HttpLogDetailLevel.NONE; policies = new ArrayList<>(); } + /** + * Creates a {@link KeyClient} based on options set in the builder. + * Every time {@code buildClient()} is called, a new instance of {@link KeyClient} is created. + * + *

    If {@link KeyClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link KeyClientBuilder#endpoint(String) serviceEndpoint} are used to create the + * {@link KeyClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, + * then {@link KeyClientBuilder#credential(TokenCredential) key vault credential} and + * {@link KeyClientBuilder#endpoint(String) key vault endpoint} are required to build the {@link KeyClient client}.

    + * + * @return A {@link KeyClient} with the options set from the builder. + * @throws IllegalStateException If {@link KeyClientBuilder#credential(TokenCredential)} or + * {@link KeyClientBuilder#endpoint(String)} have not been set. + */ + public KeyClient buildClient() { + return new KeyClient(buildAsyncClient()); + } /** * Creates a {@link KeyAsyncClient} based on options set in the builder. - * Every time {@code build()} is called, a new instance of {@link KeyAsyncClient} is created. + * Every time {@code buildAsyncClient()} is called, a new instance of {@link KeyAsyncClient} is created. * - *

    If {@link KeyAsyncClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link KeyAsyncClientBuilder#endpoint(String) serviceEndpoint} are used to create the - * {@link KeyAsyncClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, - * then {@link KeyAsyncClientBuilder#credential(TokenCredential) key vault credential and - * {@link KeyAsyncClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link KeyAsyncClient client}.}

    + *

    If {@link KeyClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link KeyClientBuilder#endpoint(String) serviceEndpoint} are used to create the + * {@link KeyClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, + * then {@link KeyClientBuilder#credential(TokenCredential) key vault credential and + * {@link KeyClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link KeyAsyncClient client}.}

    * - * @return A KeyAsyncClient with the options set from the builder. - * @throws IllegalStateException If {@link KeyAsyncClientBuilder#credential(TokenCredential)} or - * {@link KeyAsyncClientBuilder#endpoint(String)} have not been set. + * @return A {@link KeyAsyncClient} with the options set from the builder. + * @throws IllegalStateException If {@link KeyClientBuilder#credential(TokenCredential)} or + * {@link KeyClientBuilder#endpoint(String)} have not been set. */ - public KeyAsyncClient build() { + public KeyAsyncClient buildAsyncClient() { Configuration buildConfiguration = (configuration == null) ? ConfigurationManager.getConfiguration().clone() : configuration; URL buildEndpoint = getBuildEndpoint(buildConfiguration); @@ -124,13 +137,13 @@ public KeyAsyncClient build() { /** * Sets the vault endpoint url to send HTTP requests to. * - * @param endPoint The vault endpoint url is used as destination on Azure to send requests to. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @param endpoint The vault endpoint url is used as destination on Azure to send requests to. + * @return the updated ServiceClientBuilder object. * @throws IllegalArgumentException if {@code endpoint} is null or it cannot be parsed into a valid URL. */ - public KeyAsyncClientBuilder endpoint(String endPoint) { + public KeyClientBuilder endpoint(String endpoint) { try { - this.endpoint = new URL(endPoint); + this.endpoint = new URL(endpoint); } catch (MalformedURLException e) { throw new IllegalArgumentException("The Azure Key Vault endpoint url is malformed."); } @@ -141,10 +154,10 @@ public KeyAsyncClientBuilder endpoint(String endPoint) { * Sets the credential to use when authenticating HTTP requests. * * @param credential The credential to use for authenticating HTTP requests. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @return the updated {@link KeyClientBuilder} object. * @throws NullPointerException if {@code credential} is {@code null}. */ - public KeyAsyncClientBuilder credential(TokenCredential credential) { + public KeyClientBuilder credential(TokenCredential credential) { Objects.requireNonNull(credential); this.credential = credential; return this; @@ -156,24 +169,23 @@ public KeyAsyncClientBuilder credential(TokenCredential credential) { *

    logLevel is optional. If not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

    * * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @return the updated {@link KeyClientBuilder} object. * @throws NullPointerException if {@code logLevel} is {@code null}. */ - public KeyAsyncClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + public KeyClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { Objects.requireNonNull(logLevel); httpLogDetailLevel = logLevel; return this; } /** - * Adds a policy to the set of existing policies that are executed after - * {@link KeyAsyncClient} required policies. + * Adds a policy to the set of existing policies that are executed after {@link KeyAsyncClient} and {@link KeyClient} required policies. * * @param policy The {@link HttpPipelinePolicy policy} to be added. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @return the updated {@link KeyClientBuilder} object. * @throws NullPointerException if {@code policy} is {@code null}. */ - public KeyAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { + public KeyClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy); policies.add(policy); return this; @@ -183,10 +195,10 @@ public KeyAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { * Sets the HTTP client to use for sending and receiving requests to and from the service. * * @param client The HTTP client to use for requests. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @return the updated {@link KeyClientBuilder} object. * @throws NullPointerException If {@code client} is {@code null}. */ - public KeyAsyncClientBuilder httpClient(HttpClient client) { + public KeyClientBuilder httpClient(HttpClient client) { Objects.requireNonNull(client); this.httpClient = client; return this; @@ -196,12 +208,12 @@ public KeyAsyncClientBuilder httpClient(HttpClient client) { * Sets the HTTP pipeline to use for the service client. * * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link KeyAsyncClientBuilder#endpoint(String) endpoint} to build {@link KeyAsyncClient}. + * {@link KeyClientBuilder#endpoint(String) endpoint} to build {@link KeyClient} or {@link KeyAsyncClient}. * * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return the updated {@link KeyAsyncClientBuilder} object. + * @return the updated {@link KeyClientBuilder} object. */ - public KeyAsyncClientBuilder pipeline(HttpPipeline pipeline) { + public KeyClientBuilder pipeline(HttpPipeline pipeline) { Objects.requireNonNull(pipeline); this.pipeline = pipeline; return this; @@ -214,9 +226,9 @@ public KeyAsyncClientBuilder pipeline(HttpPipeline pipeline) { * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. * * @param configuration The configuration store used to - * @return The updated {@link KeyAsyncClientBuilder} object. + * @return The updated KeyClientBuilder object. */ - public KeyAsyncClientBuilder configuration(Configuration configuration) { + public KeyClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; } diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyImportRequestParameters.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyImportRequestParameters.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyImportRequestParameters.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyImportRequestParameters.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestAttributes.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestAttributes.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestAttributes.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestAttributes.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestParameters.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestParameters.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestParameters.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRequestParameters.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRestoreRequestParameters.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRestoreRequestParameters.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyRestoreRequestParameters.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyRestoreRequestParameters.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyService.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyService.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyService.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyService.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyVaultErrorCodeStrings.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyVaultErrorCodeStrings.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/KeyVaultErrorCodeStrings.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyVaultErrorCodeStrings.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/implementation/DeletedKeyPage.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/DeletedKeyPage.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/implementation/DeletedKeyPage.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/DeletedKeyPage.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/implementation/KeyBasePage.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/KeyBasePage.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/implementation/KeyBasePage.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/implementation/KeyBasePage.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/DeletedKey.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/DeletedKey.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/DeletedKey.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/DeletedKey.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/EcKeyCreateOptions.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/EcKeyCreateOptions.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/EcKeyCreateOptions.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/EcKeyCreateOptions.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/Key.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/Key.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/Key.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/Key.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java similarity index 99% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java index cfd6c2b7176e5..562527c0bbf6f 100644 --- a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java +++ b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyBase.java @@ -240,6 +240,7 @@ public String version() { * @param attributes The key value mapping of the key attributes */ @JsonProperty("attributes") + @SuppressWarnings("unchecked") private void unpackAttributes(Map attributes) { this.enabled = (Boolean) attributes.get("enabled"); this.notBefore = epochToOffsetDateTime(attributes.get("nbf")); @@ -290,6 +291,7 @@ List getKeyOperations(List jsonWebKeyOps) { return output; } + @SuppressWarnings("unchecked") JsonWebKey createKeyMaterialFromJson(Map key) { final Base64 base64 = new Base64(-1, null, true); JsonWebKey outputKey = new JsonWebKey() diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyCreateOptions.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyCreateOptions.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyCreateOptions.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyCreateOptions.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyImportOptions.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyImportOptions.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/KeyImportOptions.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyImportOptions.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/RsaKeyCreateOptions.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/RsaKeyCreateOptions.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/RsaKeyCreateOptions.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/RsaKeyCreateOptions.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/package-info.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/package-info.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/package-info.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/package-info.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonDeserializer.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonDeserializer.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonDeserializer.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonDeserializer.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonSerializer.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonSerializer.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonSerializer.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/Base64UrlJsonSerializer.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/ByteExtensions.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/ByteExtensions.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/ByteExtensions.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/ByteExtensions.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/JsonWebKey.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/JsonWebKey.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/JsonWebKey.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/JsonWebKey.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyCurveName.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyCurveName.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyCurveName.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyCurveName.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyOperation.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyOperation.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyOperation.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyOperation.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyType.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyType.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyType.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/KeyType.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/package-info.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/package-info.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/package-info.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/webkey/package-info.java diff --git a/keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/package-info.java b/sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/package-info.java similarity index 100% rename from keyvault/client/keys/src/main/java/com/azure/security/keyvault/keys/package-info.java rename to sdk/keyvault/azure-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/package-info.java diff --git a/keyvault/client/keys/src/main/resources/kvErrorStrings.properties b/sdk/keyvault/azure-keyvault-keys/src/main/resources/kvErrorStrings.properties similarity index 100% rename from keyvault/client/keys/src/main/resources/kvErrorStrings.properties rename to sdk/keyvault/azure-keyvault-keys/src/main/resources/kvErrorStrings.properties diff --git a/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperations.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperations.java similarity index 96% rename from keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperations.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperations.java index dfe79bc38a12d..e54ebdad9d157 100644 --- a/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperations.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperations.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyClient; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -32,10 +31,10 @@ public static void main(String[] args) throws IOException, InterruptedException, // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyClient keyClient = KeyClient.builder() + KeyClient keyClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create a Rsa key valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. diff --git a/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperationsAsync.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperationsAsync.java similarity index 92% rename from keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperationsAsync.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperationsAsync.java index 85aa8b40157a6..c1b1191e861e9 100644 --- a/keyvault/client/keys/src/samples/java/keys/BackupAndRestoreOperationsAsync.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/BackupAndRestoreOperationsAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyAsyncClient; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; import java.io.File; @@ -31,10 +30,10 @@ public static void main(String[] args) throws IOException, InterruptedException, // Instantiate async key client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyAsyncClient keyAsyncClient = KeyAsyncClient.builder() + KeyAsyncClient keyAsyncClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create Cloud Rsa key valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. @@ -65,7 +64,7 @@ public static void main(String[] args) throws IOException, InterruptedException, // If the vault is soft-delete enabled, then you need to purge the key as well for permanent deletion. keyAsyncClient.purgeDeletedKey("CloudRsaKey").subscribe(purgeResponse -> - System.out.printf("Purge Status response %d \n", purgeResponse.statusCode())); + System.out.printf("Purge Status response %d \n", purgeResponse.statusCode())); //To ensure file is purged on server side. Thread.sleep(15000); @@ -73,7 +72,7 @@ public static void main(String[] args) throws IOException, InterruptedException, // After sometime, the key is required again. We can use the backup value to restore it in the key vault. byte[] backupFromFile = Files.readAllBytes(new File(backupFilePath).toPath()); keyAsyncClient.restoreKey(backupFromFile).subscribe(keyResponse -> - System.out.printf("Restored Key with name %s \n", keyResponse.value().name())); + System.out.printf("Restored Key with name %s \n", keyResponse.value().name())); //To ensure key is restored on server side. Thread.sleep(15000); diff --git a/keyvault/client/keys/src/samples/java/keys/HelloWorld.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorld.java similarity index 95% rename from keyvault/client/keys/src/samples/java/keys/HelloWorld.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorld.java index 139d4dbe1a09d..c9b3a3866ed80 100644 --- a/keyvault/client/keys/src/samples/java/keys/HelloWorld.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorld.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyClient; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -27,10 +26,10 @@ public static void main(String[] args) throws InterruptedException, IllegalArgum // Instantiate a key client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyClient keyClient = KeyClient.builder() + KeyClient keyClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create a Rsa key valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. diff --git a/keyvault/client/keys/src/samples/java/keys/HelloWorldAsync.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorldAsync.java similarity index 86% rename from keyvault/client/keys/src/samples/java/keys/HelloWorldAsync.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorldAsync.java index 411164238116c..257b79b48c500 100644 --- a/keyvault/client/keys/src/samples/java/keys/HelloWorldAsync.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/HelloWorldAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyAsyncClient; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -26,10 +25,10 @@ public static void main(String[] args) throws InterruptedException { // Instantiate an async key client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyAsyncClient keyAsyncClient = KeyAsyncClient.builder() + KeyAsyncClient keyAsyncClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create Cloud Rsa key valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. @@ -51,11 +50,11 @@ public static void main(String[] args) throws InterruptedException { // After one year, the Cloud Rsa Key is still required, we need to update the expiry time of the key. // The update method can be used to update the expiry attribute of the key. keyAsyncClient.getKey("CloudRsaKey").subscribe(keyResponse -> { - Key key = keyResponse.value(); - //Update the expiry time of the key. - key.expires(key.expires().plusYears(1)); - keyAsyncClient.updateKey(key).subscribe(updatedKeyResponse -> - System.out.printf("Key's updated expiry time %s \n", updatedKeyResponse.value().expires().toString())); + Key key = keyResponse.value(); + //Update the expiry time of the key. + key.expires(key.expires().plusYears(1)); + keyAsyncClient.updateKey(key).subscribe(updatedKeyResponse -> + System.out.printf("Key's updated expiry time %s \n", updatedKeyResponse.value().expires().toString())); }); Thread.sleep(2000); @@ -72,7 +71,7 @@ public static void main(String[] args) throws InterruptedException { // The Cloud Rsa Key is no longer needed, need to delete it from the key vault. keyAsyncClient.deleteKey("CloudRsaKey").subscribe(deletedKeyResponse -> - System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); + System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); //To ensure key is deleted on server side. Thread.sleep(30000); diff --git a/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..6f63be8f59b68 --- /dev/null +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/KeyClientJavaDocCodeSnippets.java @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.keys; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.test.models.RecordedData; +import com.azure.core.test.policy.RecordNetworkCallPolicy; +import com.azure.identity.credential.DefaultAzureCredential; +import com.azure.security.keyvault.keys.models.Key; +import com.azure.security.keyvault.keys.models.KeyBase; +import com.azure.security.keyvault.keys.models.webkey.KeyType; + +/** + * This class contains code samples for generating javadocs through doclets for {@link KeyClient} + */ +public final class KeyClientJavaDocCodeSnippets { + + /** + * Generates code sample for creating a {@link KeyAsyncClient} + * @return An instance of {@link KeyAsyncClient} + */ + public KeyAsyncClient createAsyncClientWithHttpClient() { + // BEGIN: com.azure.security.keyvault.keys.async.keyclient.withhttpclient.instantiation + RecordedData networkData = new RecordedData(); + KeyAsyncClient keyClient = new KeyClientBuilder() + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .addPolicy(new RecordNetworkCallPolicy(networkData)) + .httpClient(HttpClient.createDefault()) + .buildAsyncClient(); + // END: com.azure.security.keyvault.keys.async.keyclient.withhttpclient.instantiation + return keyClient; + } + + /** + * Generates code sample for creating a {@link KeyClient} + * @return An instance of {@link KeyClient} + */ + public KeyClient createClient() { + // BEGIN: com.azure.security.keyvault.keys.keyclient.instantiation + KeyClient keyClient = new KeyClientBuilder() + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .buildClient(); + // END: com.azure.security.keyvault.keys.keyclient.instantiation + return keyClient; + } + + /** + * Generates code sample for creating a {@link KeyAsyncClient} + * @return An instance of {@link KeyAsyncClient} + */ + public KeyAsyncClient createAsyncClient() { + // BEGIN: com.azure.security.keyvault.keys.async.keyclient.instantiation + KeyAsyncClient keyClient = new KeyClientBuilder() + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .buildAsyncClient(); + // END: com.azure.security.keyvault.keys.async.keyclient.instantiation + return keyClient; + } + + /** + * Generates code sample for creating a {@link KeyAsyncClient} + * @return An instance of {@link KeyAsyncClient} + */ + public KeyAsyncClient createAsyncClientWithPipeline() { + // BEGIN: com.azure.security.keyvault.keys.async.keyclient.pipeline.instantiation + RecordedData networkData = new RecordedData(); + HttpPipeline pipeline = HttpPipeline.builder().policies(new RecordNetworkCallPolicy(networkData)).build(); + KeyAsyncClient keyClient = new KeyClientBuilder() + .pipeline(pipeline) + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .buildAsyncClient(); + // END: com.azure.security.keyvault.keys.async.keyclient.pipeline.instantiation + return keyClient; + } + + + /** + * Generates a code sample for using {@link KeyClient#createKey(String, KeyType)} + */ + public void createKey() { + KeyClient keyClient = createClient(); + // BEGIN: com.azure.keyvault.keys.keyclient.createKey#string-keyType + Key retKey = keyClient.createKey("keyName", KeyType.EC).value(); + System.out.printf("Key is created with name %s and id %s %n", retKey.name(), retKey.id()); + // END: com.azure.keyvault.keys.keyclient.createKey#string-keyType + } + + /** + * Generates code sample for using {@link KeyClient#listKeyVersions(String)} + */ + public void listKeyVersions() { + KeyClient keyClient = createClient(); + // BEGIN: com.azure.keyvault.keys.keyclient.listKeyVersions + for (KeyBase key : keyClient.listKeyVersions("keyName")) { + Key keyWithMaterial = keyClient.getKey(key).value(); + System.out.printf("Received key's version with name %s, type %s and version %s", keyWithMaterial.name(), + keyWithMaterial.keyMaterial().kty(), keyWithMaterial.version()); + } + // END: com.azure.keyvault.keys.keyclient.listKeyVersions + } + + /** + * Implementation not provided for this method + * @return {@code null} + */ + private TokenCredential getKeyVaultCredential() { + return null; + } +} diff --git a/keyvault/client/keys/src/samples/java/keys/ListOperations.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperations.java similarity index 95% rename from keyvault/client/keys/src/samples/java/keys/ListOperations.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperations.java index 3cc9401f22fc0..b719d6970856f 100644 --- a/keyvault/client/keys/src/samples/java/keys/ListOperations.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperations.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyClient; import com.azure.security.keyvault.keys.models.EcKeyCreateOptions; import com.azure.security.keyvault.keys.models.Key; import com.azure.security.keyvault.keys.models.KeyBase; @@ -27,10 +26,10 @@ public static void main(String[] args) throws IllegalArgumentException { // Instantiate a keyClient that will be used to call the service. Notice that the keyClient is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyClient keyClient = KeyClient.builder() + KeyClient keyClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create Ec and Rsa keys valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. diff --git a/keyvault/client/keys/src/samples/java/keys/ListOperationsAsync.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperationsAsync.java similarity index 87% rename from keyvault/client/keys/src/samples/java/keys/ListOperationsAsync.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperationsAsync.java index a86a5c9bdfb34..f82d562845589 100644 --- a/keyvault/client/keys/src/samples/java/keys/ListOperationsAsync.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ListOperationsAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyAsyncClient; import com.azure.security.keyvault.keys.models.EcKeyCreateOptions; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -26,10 +25,10 @@ public static void main(String[] args) throws InterruptedException { // Instantiate an async key client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyAsyncClient keyAsyncClient = KeyAsyncClient.builder() + KeyAsyncClient keyAsyncClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create Ec and Rsa keys valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. @@ -50,17 +49,17 @@ public static void main(String[] args) throws InterruptedException { // You need to check te type of keys already exist in your key vault. Let's list the keys and print their types. // List operations don't return the keys with key material information. So, for each returned key we call getKey to get the key with its key material information. keyAsyncClient.listKeys() - .subscribe(keyBase -> - keyAsyncClient.getKey(keyBase).subscribe(keyResponse -> - System.out.printf("Received key with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty()))); + .subscribe(keyBase -> + keyAsyncClient.getKey(keyBase).subscribe(keyResponse -> + System.out.printf("Received key with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty()))); Thread.sleep(15000); // We need the Cloud Rsa key with bigger key size, so you want to update the key in key vault to ensure it has the required size. // Calling createRsaKey on an existing key creates a new version of the key in the key vault with the new specified size. keyAsyncClient.createRsaKey(new RsaKeyCreateOptions("CloudRsaKey") - .keySize(4096) - .expires(OffsetDateTime.now().plusYears(1))).subscribe(keyResponse -> + .keySize(4096) + .expires(OffsetDateTime.now().plusYears(1))).subscribe(keyResponse -> System.out.printf("Key is created with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty())); Thread.sleep(2000); diff --git a/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeys.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeys.java similarity index 94% rename from keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeys.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeys.java index c64b8e47cd86d..bf668578f15f1 100644 --- a/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeys.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeys.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyClient; import com.azure.security.keyvault.keys.models.DeletedKey; import com.azure.security.keyvault.keys.models.EcKeyCreateOptions; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -31,10 +30,10 @@ public static void main(String[] args) throws IllegalArgumentException, Interrup // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyClient keyClient = KeyClient.builder() + KeyClient keyClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create Ec and Rsa keys valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. @@ -53,7 +52,7 @@ public static void main(String[] args) throws IllegalArgumentException, Interrup // We accidentally Cloud Ec key. Let's recover it. // A deleted key can only be recovered if the key vault is soft-delete enabled. - keyClient.recoverDeletedKey("CloudEcKey"); + keyClient.recoverDeletedKey("CloudEcKey"); //To ensure key is recovered on server side. Thread.sleep(30000); diff --git a/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeysAsync.java b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeysAsync.java similarity index 73% rename from keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeysAsync.java rename to sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeysAsync.java index 385175a599ff8..a9a206453ba8e 100644 --- a/keyvault/client/keys/src/samples/java/keys/ManagingDeletedKeysAsync.java +++ b/sdk/keyvault/azure-keyvault-keys/src/samples/java/com/azure/security/keyvault/keys/ManagingDeletedKeysAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package keys; +package com.azure.security.keyvault.keys; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.keys.KeyAsyncClient; import com.azure.security.keyvault.keys.models.EcKeyCreateOptions; import com.azure.security.keyvault.keys.models.RsaKeyCreateOptions; @@ -30,45 +29,45 @@ public static void main(String[] args) throws InterruptedException { // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - KeyAsyncClient keyAsyncClient = KeyAsyncClient.builder() + KeyAsyncClient keyAsyncClient = new KeyClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create Ec and Rsa keys valid for 1 year. if the key // already exists in the key vault, then a new version of the key is created. keyAsyncClient.createEcKey(new EcKeyCreateOptions("CloudEcKey") .expires(OffsetDateTime.now().plusYears(1))) .subscribe(keyResponse -> - System.out.printf("Key is created with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty())); + System.out.printf("Key is created with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty())); Thread.sleep(2000); keyAsyncClient.createRsaKey(new RsaKeyCreateOptions("CloudRsaKey") .expires(OffsetDateTime.now().plusYears(1))) .subscribe(keyResponse -> - System.out.printf("Key is created with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty())); + System.out.printf("Key is created with name %s and type %s \n", keyResponse.value().name(), keyResponse.value().keyMaterial().kty())); Thread.sleep(2000); // The Cloud Rsa Key is no longer needed, need to delete it from the key vault. keyAsyncClient.deleteKey("CloudEcKey").subscribe(deletedKeyResponse -> - System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); + System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); //To ensure key is deleted on server side. Thread.sleep(30000); // We accidentally deleted Cloud Ec key. Let's recover it. // A deleted key can only be recovered if the key vault is soft-delete enabled. - keyAsyncClient.recoverDeletedKey("CloudEcKey").subscribe(recoveredKeyResponse -> - System.out.printf("Recovered Key with name %s \n", recoveredKeyResponse.value().name())); + keyAsyncClient.recoverDeletedKey("CloudEcKey").subscribe(recoveredKeyResponse -> + System.out.printf("Recovered Key with name %s \n", recoveredKeyResponse.value().name())); //To ensure key is recovered on server side. Thread.sleep(10000); // The Cloud Ec and Rsa keys are no longer needed, need to delete them from the key vault. keyAsyncClient.deleteKey("CloudEcKey").subscribe(deletedKeyResponse -> - System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); + System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); keyAsyncClient.deleteKey("CloudRsaKey").subscribe(deletedKeyResponse -> System.out.printf("Deleted Key's Recovery Id %s \n", deletedKeyResponse.value().recoveryId())); @@ -78,16 +77,16 @@ public static void main(String[] args) throws InterruptedException { // You can list all the deleted and non-purged keys, assuming key vault is soft-delete enabled. keyAsyncClient.listDeletedKeys().subscribe(deletedKey -> - System.out.printf("Deleted key's recovery Id %s \n", deletedKey.recoveryId())); + System.out.printf("Deleted key's recovery Id %s \n", deletedKey.recoveryId())); Thread.sleep(15000); // If the keyvault is soft-delete enabled, then for permanent deletion deleted keys need to be purged. - keyAsyncClient.purgeDeletedKey("CloudRsaKey").subscribe(purgeResponse -> - System.out.printf("Storage account key purge status response %d \n", purgeResponse.statusCode())); + keyAsyncClient.purgeDeletedKey("CloudRsaKey").subscribe(purgeResponse -> + System.out.printf("Storage account key purge status response %d \n", purgeResponse.statusCode())); - keyAsyncClient.purgeDeletedKey("CloudEcKey").subscribe(purgeResponse -> - System.out.printf("Bank account key purge status response %d \n", purgeResponse.statusCode())); + keyAsyncClient.purgeDeletedKey("CloudEcKey").subscribe(purgeResponse -> + System.out.printf("Bank account key purge status response %d \n", purgeResponse.statusCode())); // To ensure key is purged on server side. Thread.sleep(15000); diff --git a/keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java b/sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java similarity index 98% rename from keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java rename to sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java index 6a2eae7922cc8..2600b68df917c 100644 --- a/keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java +++ b/sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyAsyncClientTest.java @@ -33,21 +33,21 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> KeyAsyncClient.builder() + client = clientSetup(credentials -> new KeyClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildAsyncClient()); } else { - client = clientSetup(credentials -> KeyAsyncClient.builder() + client = clientSetup(credentials -> new KeyClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildAsyncClient()); } } diff --git a/keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java b/sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java similarity index 98% rename from keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java rename to sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java index 56a6b416039e0..8b3eb47ac5763 100644 --- a/keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java +++ b/sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTest.java @@ -32,21 +32,21 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> KeyClient.builder() + client = clientSetup(credentials -> new KeyClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildClient()); } else { - client = clientSetup(credentials -> KeyClient.builder() + client = clientSetup(credentials -> new KeyClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildClient()); } } diff --git a/keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTestBase.java b/sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTestBase.java similarity index 100% rename from keyvault/client/keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTestBase.java rename to sdk/keyvault/azure-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/KeyClientTestBase.java diff --git a/keyvault/client/keys/src/test/resources/session-records/backupKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/backupKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/backupKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/backupKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/backupKeyNotFound.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/backupKeyNotFound.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/backupKeyNotFound.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/backupKeyNotFound.json diff --git a/keyvault/client/keys/src/test/resources/session-records/deleteKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/deleteKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/deleteKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/deleteKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/deleteKeyNotFound.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/deleteKeyNotFound.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/deleteKeyNotFound.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/deleteKeyNotFound.json diff --git a/keyvault/client/keys/src/test/resources/session-records/getDeletedKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getDeletedKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/getDeletedKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getDeletedKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/getDeletedKeyNotFound.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getDeletedKeyNotFound.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/getDeletedKeyNotFound.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getDeletedKeyNotFound.json diff --git a/keyvault/client/keys/src/test/resources/session-records/getKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/getKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/getKeyNotFound.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKeyNotFound.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/getKeyNotFound.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKeyNotFound.json diff --git a/keyvault/client/keys/src/test/resources/session-records/getKeySpecificVersion.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKeySpecificVersion.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/getKeySpecificVersion.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/getKeySpecificVersion.json diff --git a/keyvault/client/keys/src/test/resources/session-records/listDeletedKeys.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listDeletedKeys.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/listDeletedKeys.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listDeletedKeys.json diff --git a/keyvault/client/keys/src/test/resources/session-records/listKeyVersions.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listKeyVersions.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/listKeyVersions.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listKeyVersions.json diff --git a/keyvault/client/keys/src/test/resources/session-records/listKeys.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listKeys.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/listKeys.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/listKeys.json diff --git a/keyvault/client/keys/src/test/resources/session-records/recoverDeletedKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/recoverDeletedKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/recoverDeletedKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/recoverDeletedKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/recoverDeletedKeyNotFound.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/recoverDeletedKeyNotFound.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/recoverDeletedKeyNotFound.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/recoverDeletedKeyNotFound.json diff --git a/keyvault/client/keys/src/test/resources/session-records/restoreKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/restoreKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/restoreKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/restoreKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/restoreKeyFromMalformedBackup.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/restoreKeyFromMalformedBackup.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/restoreKeyFromMalformedBackup.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/restoreKeyFromMalformedBackup.json diff --git a/keyvault/client/keys/src/test/resources/session-records/setKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/setKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/setKeyEmptyName.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyEmptyName.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/setKeyEmptyName.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyEmptyName.json diff --git a/keyvault/client/keys/src/test/resources/session-records/setKeyNull.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyNull.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/setKeyNull.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyNull.json diff --git a/keyvault/client/keys/src/test/resources/session-records/setKeyNullType.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyNullType.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/setKeyNullType.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/setKeyNullType.json diff --git a/keyvault/client/keys/src/test/resources/session-records/updateDisabledKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/updateDisabledKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/updateDisabledKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/updateDisabledKey.json diff --git a/keyvault/client/keys/src/test/resources/session-records/updateKey.json b/sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/updateKey.json similarity index 100% rename from keyvault/client/keys/src/test/resources/session-records/updateKey.json rename to sdk/keyvault/azure-keyvault-keys/src/test/resources/session-records/updateKey.json diff --git a/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md b/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md new file mode 100644 index 0000000000000..c8fb10caf152e --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/CHANGELOG.md @@ -0,0 +1,33 @@ +# Release History + +## 4.0.0-preview.1 (2019-06-28) +Version 4.0.0-preview.1 is a preview of our efforts in creating a client library that is developer-friendly, idiomatic to the Java ecosystem, and as consistent across different languages and platforms as possible. The principles that guide our efforts can be found in the [Azure SDK Design Guidelines for Java](https://azuresdkspecs.z5.web.core.windows.net/JavaSpec.html). + +For details on the Azure SDK for Java (July 2019 Preview) release, you can refer to the [release announcement](https://aka.ms/azure-sdk-preview1-java). + +This library is not a direct replacement for secrets management operations from [microsoft-azure-keyvault](https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/microsoft-azure-keyvault). Applications using that library would require code changes to use `azure-keyvault-secrets`. +This package's +[documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/README.md) +and +[samples](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java) +demonstrate the new API. + + +### Major changes from `azure-keyvault` +- Packages scoped by functionality + - `azure-keyvault-secrets` contains a `SecretClient` and `SecretAsyncClient` for secret operations, + `azure-keyvault-keys` contains a `KeyClient` and `KeyAsyncClient` for key operations +- Client instances are scoped to vaults (an instance interacts with one vault +only) +- Reactive streams support using [Project Reactor](https://projectreactor.io/). +- Authentication using `azure-identity` credentials + - see this package's + [documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/README.md) + , and the + [Azure Identity documentation](https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/identity/azure-identity/README.md) + for more information + +### `azure-keyvault` features not implemented in this library +- Certificate management APIs +- National cloud support. This release supports public global cloud vaults, + e.g. https://{vault-name}.vault.azure.net diff --git a/keyvault/client/secrets/README.md b/sdk/keyvault/azure-keyvault-secrets/README.md similarity index 90% rename from keyvault/client/secrets/README.md rename to sdk/keyvault/azure-keyvault-secrets/README.md index ab07b7131362a..e8ffe95e55d5e 100644 --- a/keyvault/client/secrets/README.md +++ b/sdk/keyvault/azure-keyvault-secrets/README.md @@ -13,9 +13,9 @@ Use the secret client library to create and manage secrets. Maven dependency for Azure Secret Client library. Add it to your project's pom file. ```xml - com.azure.security + com.azure azure-keyvault-secrets - 1.0.0-preview.1 + 4.0.0-preview.1 ``` @@ -79,10 +79,10 @@ Once you've populated the **AZURE_CLIENT_ID**, **AZURE_CLIENT_SECRET** and **AZU import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.secrets.SecretClient; -SecretClient client = SecretClient.builder() +SecretClient client = new SecretClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); ``` > NOTE: For using Asynchronous client use SecretAsyncClient instead of SecretClient @@ -117,10 +117,10 @@ import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.models.Secret; -SecretClient secretClient = SecretClient.builder() +SecretClient secretClient = new SecretClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); Secret secret = secretClient.setSecret("secret_name", "secret_value").value(); System.out.printf("Secret is created with name %s and value %s \n", secret.name(), secret.value()); @@ -182,10 +182,10 @@ import com.azure.identity.credential.DefaultAzureCredential; import com.azure.security.keyvault.secrets.SecretAsyncClient; import com.azure.security.keyvault.secrets.models.Secret; -SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder() +SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .endpoint() .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); secretAsyncClient.setSecret("secret_name", "secret_value").subscribe(secretResponse -> System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); @@ -286,7 +286,7 @@ When you submit a pull request, a CLA-bot will automatically determine whether y This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. -[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src +[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src [api_documentation]: not-valid-link [azure_identity]: https://github.com/Azure/azure-sdk-for-java/tree/master/identity/client [azkeyvault_docs]: https://docs.microsoft.com/en-us/azure/key-vault/ @@ -299,12 +299,12 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope [azure_create_application_in_portal]:https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal [azure_keyvault_cli]:https://docs.microsoft.com/en-us/azure/key-vault/quick-create-cli [azure_keyvault_cli_full]:https://docs.microsoft.com/en-us/cli/azure/keyvault?view=azure-cli-latest -[secrets_samples]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets -[sample_helloWorld]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/HelloWorld.java -[sample_helloWorldAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/HelloWorldAsync.java -[sample_list]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/ListOperations.java -[sample_listAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/ListOperationsAsync.java -[sample_BackupRestore]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperations.java -[sample_BackupRestoreAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperationsAsync.java -[sample_ManageDeleted]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecrets.java -[sample_ManageDeletedAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecretsAsync.java +[secrets_samples]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets +[sample_helloWorld]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorld.java +[sample_helloWorldAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorldAsync.java +[sample_list]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperations.java +[sample_listAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperationsAsync.java +[sample_BackupRestore]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperations.java +[sample_BackupRestoreAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperationsAsync.java +[sample_ManageDeleted]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecrets.java +[sample_ManageDeletedAsync]:https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecretsAsync.java diff --git a/keyvault/client/secrets/pom.xml b/sdk/keyvault/azure-keyvault-secrets/pom.xml similarity index 93% rename from keyvault/client/secrets/pom.xml rename to sdk/keyvault/azure-keyvault-secrets/pom.xml index e04ba45e29af8..7f86407dd1dfb 100644 --- a/keyvault/client/secrets/pom.xml +++ b/sdk/keyvault/azure-keyvault-secrets/pom.xml @@ -6,7 +6,7 @@ com.azure azure-keyvault-parent 4.0.0-preview.1 - ../pom.xml + ../pom.client.xml com.azure @@ -34,7 +34,7 @@ com.azure azure-core - 1.0.0-preview.1 + 1.0.0-preview.3 @@ -57,7 +57,7 @@ com.azure azure-core-test - 1.0.0-preview.1 + 1.0.0-preview.3 test diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/AzureKeyVaultConfiguration.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/AzureKeyVaultConfiguration.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/AzureKeyVaultConfiguration.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/AzureKeyVaultConfiguration.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/KeyVaultErrorCodeStrings.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/KeyVaultErrorCodeStrings.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/KeyVaultErrorCodeStrings.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/KeyVaultErrorCodeStrings.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java similarity index 82% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java index c04938b44398a..0ed4b9d76c89c 100644 --- a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClient.java @@ -34,17 +34,12 @@ * supports creating, retrieving, updating, deleting, purging, backing up, restoring and listing the {@link Secret secrets}. The client * also supports listing {@link DeletedSecret deleted secrets} for a soft-delete enabled Azure Key Vault. * - *

    Samples to construct the client

    - *
    - * SecretAsyncClient.builder()
    - *   .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net")
    - *   .credential(new DefaultAzureCredential())
    - *   .build()
    - * 
    + *

    Samples to construct the async client

    + * {@codesnippet com.azure.security.keyvault.secretclient.async.construct} * - * @see SecretAsyncClientBuilder + * @see SecretClientBuilder */ -@ServiceClient(builder = SecretAsyncClientBuilder.class, isAsync = true, serviceInterfaces = SecretService.class) +@ServiceClient(builder = SecretClientBuilder.class, isAsync = true, serviceInterfaces = SecretService.class) public final class SecretAsyncClient { static final String API_VERSION = "7.0"; static final String ACCEPT_LANGUAGE = "en-US"; @@ -52,7 +47,7 @@ public final class SecretAsyncClient { static final String CONTENT_TYPE_HEADER_VALUE = "application/json"; static final String KEY_VAULT_SCOPE = "https://vault.azure.net/.default"; - private String endpoint; + private final String endpoint; private final SecretService service; private final ClientLogger logger = new ClientLogger(SecretAsyncClient.class); @@ -68,14 +63,6 @@ public final class SecretAsyncClient { this.service = RestProxy.create(SecretService.class, pipeline); } - /** - * Creates a builder that can configure options for the SecretAsyncClient before creating an instance of it. - * @return A new builder to create a SecretAsyncClient from. - */ - public static SecretAsyncClientBuilder builder() { - return new SecretAsyncClientBuilder(); - } - /** * The set operation adds a secret to the key vault. If the named secret already exists, Azure Key Vault creates * a new version of that secret. This operation requires the {@code secrets/set} permission. @@ -111,9 +98,9 @@ public Mono> setSecret(Secret secret) { .secretAttributes(new SecretRequestAttributes(secret)); return service.setSecret(endpoint, secret.name(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Setting secret - {}", secret.name())) - .doOnSuccess(response -> logger.asInfo().log("Set secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to set secret - {}", secret.name(), error)); + .doOnRequest(ignored -> logger.info("Setting secret - {}", secret.name())) + .doOnSuccess(response -> logger.info("Set secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to set secret - {}", secret.name(), error)); } /** @@ -137,9 +124,9 @@ public Mono> setSecret(Secret secret) { public Mono> setSecret(String name, String value) { SecretRequestParameters parameters = new SecretRequestParameters().value(value); return service.setSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Setting secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Set secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to set secret - {}", name, error)); + .doOnRequest(ignored -> logger.info("Setting secret - {}", name)) + .doOnSuccess(response -> logger.info("Set secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to set secret - {}", name, error)); } /** @@ -168,9 +155,9 @@ public Mono> getSecret(String name, String version) { secretVersion = version; } return service.getSecret(endpoint, name, secretVersion, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get secret - {}", name, error)); + .doOnRequest(ignoredValue -> logger.info("Retrieving secret - {}", name)) + .doOnSuccess(response -> logger.info("Retrieved secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get secret - {}", name, error)); } /** @@ -198,9 +185,9 @@ public Mono> getSecret(SecretBase secretBase) { secretVersion = secretBase.version(); } return service.getSecret(endpoint, secretBase.name(), secretVersion, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving secret - {}", secretBase.name())) - .doOnSuccess(response -> logger.asInfo().log("Retrieved secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to get secret - {}", secretBase.name(), error)); + .doOnRequest(ignoredValue -> logger.info("Retrieving secret - {}", secretBase.name())) + .doOnSuccess(response -> logger.info("Retrieved secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to get secret - {}", secretBase.name(), error)); } /** * Get the latest version of the specified secret from the key vault. The get operation is applicable to any secret stored in Azure Key Vault. @@ -257,9 +244,9 @@ public Mono> updateSecret(SecretBase secret) { .secretAttributes(new SecretRequestAttributes(secret)); return service.updateSecret(endpoint, secret.name(), secret.version(), API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Updating secret - {}", secret.name())) - .doOnSuccess(response -> logger.asInfo().log("Updated secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to update secret - {}", secret.name(), error)); + .doOnRequest(ignored -> logger.info("Updating secret - {}", secret.name())) + .doOnSuccess(response -> logger.info("Updated secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to update secret - {}", secret.name(), error)); } /** @@ -282,9 +269,9 @@ public Mono> updateSecret(SecretBase secret) { */ public Mono> deleteSecret(String name) { return service.deleteSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Deleting secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Deleted secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to delete secret - {}", name, error)); + .doOnRequest(ignored -> logger.info("Deleting secret - {}", name)) + .doOnSuccess(response -> logger.info("Deleted secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to delete secret - {}", name, error)); } /** @@ -307,9 +294,9 @@ public Mono> deleteSecret(String name) { */ public Mono> getDeletedSecret(String name) { return service.getDeletedSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Retrieving deleted secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved deleted secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to retrieve deleted secret - {}", name, error)); + .doOnRequest(ignored -> logger.info("Retrieving deleted secret - {}", name)) + .doOnSuccess(response -> logger.info("Retrieved deleted secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to retrieve deleted secret - {}", name, error)); } /** @@ -332,9 +319,9 @@ public Mono> getDeletedSecret(String name) { */ public Mono purgeDeletedSecret(String name) { return service.purgeDeletedSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Purging deleted secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Purged deleted secret - {}", name)) - .doOnError(error -> logger.asWarning().log("Failed to purge deleted secret - {}", name, error)); + .doOnRequest(ignored -> logger.info("Purging deleted secret - {}", name)) + .doOnSuccess(response -> logger.info("Purged deleted secret - {}", name)) + .doOnError(error -> logger.warning("Failed to purge deleted secret - {}", name, error)); } /** @@ -357,9 +344,9 @@ public Mono purgeDeletedSecret(String name) { */ public Mono> recoverDeletedSecret(String name) { return service.recoverDeletedSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Recovering deleted secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Recovered deleted secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to recover deleted secret - {}", name, error)); + .doOnRequest(ignored -> logger.info("Recovering deleted secret - {}", name)) + .doOnSuccess(response -> logger.info("Recovered deleted secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to recover deleted secret - {}", name, error)); } /** @@ -381,9 +368,9 @@ public Mono> recoverDeletedSecret(String name) { */ public Mono> backupSecret(String name) { return service.backupSecret(endpoint, name, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Backing up secret - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Backed up secret - {}", name)) - .doOnError(error -> logger.asWarning().log("Failed to back up secret - {}", name, error)) + .doOnRequest(ignored -> logger.info("Backing up secret - {}", name)) + .doOnSuccess(response -> logger.info("Backed up secret - {}", name)) + .doOnError(error -> logger.warning("Failed to back up secret - {}", name, error)) .flatMap(base64URLResponse -> Mono.just(new SimpleResponse(base64URLResponse.request(), base64URLResponse.statusCode(), base64URLResponse.headers(), base64URLResponse.value().value()))); } @@ -407,9 +394,9 @@ public Mono> backupSecret(String name) { public Mono> restoreSecret(byte[] backup) { SecretRestoreRequestParameters parameters = new SecretRestoreRequestParameters().secretBackup(backup); return service.restoreSecret(endpoint, API_VERSION, ACCEPT_LANGUAGE, parameters, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Attempting to restore secret")) - .doOnSuccess(response -> logger.asInfo().log("Restored secret - {}", response.value().name())) - .doOnError(error -> logger.asWarning().log("Failed to restore secret", error)); + .doOnRequest(ignored -> logger.info("Attempting to restore secret")) + .doOnSuccess(response -> logger.info("Restored secret - {}", response.value().name())) + .doOnError(error -> logger.warning("Failed to restore secret", error)); } /** @@ -429,9 +416,9 @@ public Mono> restoreSecret(byte[] backup) { */ public Flux listSecrets() { return service.getSecrets(endpoint, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing secrets")) - .doOnSuccess(response -> logger.asInfo().log("Listed secrets")) - .doOnError(error -> logger.asWarning().log("Failed to list secrets", error)) + .doOnRequest(ignored -> logger.info("Listing secrets")) + .doOnSuccess(response -> logger.info("Listed secrets")) + .doOnError(error -> logger.warning("Failed to list secrets", error)) .flatMapMany(r -> extractAndFetchSecrets(r, Context.NONE)); } @@ -451,9 +438,9 @@ public Flux listSecrets() { */ public Flux listDeletedSecrets() { return service.getDeletedSecrets(endpoint, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing deleted secrets")) - .doOnSuccess(response -> logger.asInfo().log("Listed deleted secrets")) - .doOnError(error -> logger.asWarning().log("Failed to list deleted secrets", error)) + .doOnRequest(ignored -> logger.info("Listing deleted secrets")) + .doOnSuccess(response -> logger.info("Listed deleted secrets")) + .doOnError(error -> logger.warning("Failed to list deleted secrets", error)) .flatMapMany(r -> extractAndFetchDeletedSecrets(r, Context.NONE)); } @@ -478,9 +465,9 @@ public Flux listDeletedSecrets() { */ public Flux listSecretVersions(String name) { return service.getSecretVersions(endpoint, name, DEFAULT_MAX_PAGE_RESULTS, API_VERSION, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignored -> logger.asInfo().log("Listing secret versions - {}", name)) - .doOnSuccess(response -> logger.asInfo().log("Listed secret versions - {}", name)) - .doOnError(error -> logger.asWarning().log(String.format("Failed to list secret versions - {}", name), error)) + .doOnRequest(ignored -> logger.info("Listing secret versions - {}", name)) + .doOnSuccess(response -> logger.info("Listed secret versions - {}", name)) + .doOnError(error -> logger.warning(String.format("Failed to list secret versions - {}", name), error)) .flatMapMany(r -> extractAndFetchSecrets(r, Context.NONE)); } @@ -493,9 +480,9 @@ public Flux listSecretVersions(String name) { */ private Flux listSecretsNext(String nextPageLink, Context context) { return service.getSecrets(endpoint, nextPageLink, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving the next listing page - Page {}", nextPageLink)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved the next listing page - Page {}", nextPageLink)) - .doOnError(error -> logger.asWarning().log("Failed to retrieve the next listing page - Page {}", nextPageLink, error)) + .doOnRequest(ignoredValue -> logger.info("Retrieving the next listing page - Page {}", nextPageLink)) + .doOnSuccess(response -> logger.info("Retrieved the next listing page - Page {}", nextPageLink)) + .doOnError(error -> logger.warning("Failed to retrieve the next listing page - Page {}", nextPageLink, error)) .flatMapMany(r -> extractAndFetchSecrets(r, context)); } @@ -512,9 +499,9 @@ private Publisher extractAndFetchSecrets(PagedResponse p */ private Flux listDeletedSecretsNext(String nextPageLink, Context context) { return service.getDeletedSecrets(endpoint, nextPageLink, ACCEPT_LANGUAGE, CONTENT_TYPE_HEADER_VALUE) - .doOnRequest(ignoredValue -> logger.asInfo().log("Retrieving the next listing page - Page {}", nextPageLink)) - .doOnSuccess(response -> logger.asInfo().log("Retrieved the next listing page - Page {}", nextPageLink)) - .doOnError(error -> logger.asWarning().log("Failed to retrieve the next listing page - Page {}", nextPageLink, error)) + .doOnRequest(ignoredValue -> logger.info("Retrieving the next listing page - Page {}", nextPageLink)) + .doOnSuccess(response -> logger.info("Retrieved the next listing page - Page {}", nextPageLink)) + .doOnError(error -> logger.warning("Failed to retrieve the next listing page - Page {}", nextPageLink, error)) .flatMapMany(r -> extractAndFetchDeletedSecrets(r, context)); } diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretBackup.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretBackup.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretBackup.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretBackup.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java similarity index 97% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java index 03a37c908e4e7..dab070eda1560 100644 --- a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClient.java @@ -20,13 +20,8 @@ * supports creating, retrieving, updating, deleting, purging, backing up, restoring and listing the {@link Secret secrets}. The client * also supports listing {@link DeletedSecret deleted secrets} for a soft-delete enabled Azure Key Vault. * - *

    Samples to construct the client

    - *
    - * SecretClient.builder()
    - *   .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net")
    - *   .credential(new DefaultAzureCredential())
    - *   .build()
    - * 
    + *

    Samples to construct the sync client

    + * {@codesnippet com.azure.security.keyvault.secretclient.sync.construct} * * @see SecretClientBuilder */ @@ -44,14 +39,6 @@ public final class SecretClient { this.client = client; } - /** - * Creates a builder that can configure options for the SecretClient before creating an instance of it. - * @return A new builder to create a SecretClient from. - */ - public static SecretClientBuilder builder() { - return new SecretClientBuilder(); - } - /** * The set operation adds a secret to the Azure Key Vault. If the named secret already exists, a new version of the secret * is created in the key vault. This operation requires the {@code secrets/set} permission. @@ -131,7 +118,7 @@ public Response getSecret(String name, String version) { *

    The list operations {@link SecretClient#listSecrets()} and {@link SecretClient#listSecretVersions(String)} return * the {@link List} containing {@link SecretBase base secret} as output excluding the include the value of the secret. * This operation can then be used to get the full secret with its value from {@code secretBase}.

    - * {@codesnippet com.azure.keyvault.secretclient.getSecret#secretBase} + * {@codesnippet com.azure.security.keyvault.secretclient.getSecret#secretBase} * * @param secretBase The {@link SecretBase base secret} holding attributes of the secret being requested. * @throws ResourceNotFoundException when a secret with {@link SecretBase#name() name} and {@link SecretBase#version() version} doesn't exist in the key vault. diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClientBuilder.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java similarity index 61% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClientBuilder.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java index 704e84010c07f..87ef153de03dc 100644 --- a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretAsyncClientBuilder.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java @@ -24,44 +24,37 @@ import java.util.Objects; /** - * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link SecretAsyncClient secret async client}, - * calling {@link SecretAsyncClientBuilder#build() build} constructs an instance of the client. + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link SecretAsyncClient secret async client} and {@link SecretClient secret client}, + * by calling {@link SecretClientBuilder#buildAsyncClient() buildAsyncClient} and {@link SecretClientBuilder#buildClient() buildClient} respectively. + * It constructs an instance of the desired client. * - *

    The minimal configuration options required by {@link SecretAsyncClientBuilder secretClientBuilder} to build {@link SecretAsyncClient} - * are {@link String endpoint} and {@link TokenCredential credential}.

    - *
    - * SecretAsyncClient.builder()
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .credential(new DefaultAzureCredential())
    - *   .build();
    - * 
    + *

    The minimal configuration options required by {@link SecretClientBuilder secretClientBuilder} to build + * {@link SecretAsyncClient} are {@link String endpoint} and {@link TokenCredential credential}.

    + * + * {@codesnippet com.azure.security.keyvault.secretclient.async.construct} + * + *

    Samples to construct the sync client

    + * {@codesnippet com.azure.security.keyvault.secretclient.sync.construct} * *

    The {@link HttpLogDetailLevel log detail level}, multiple custom {@link HttpLoggingPolicy policies} and custom - * {@link HttpClient http client} can be optionally configured in the {@link SecretAsyncClientBuilder}.

    - *
    - * SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder()
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .credential(new DefaultAzureCredential())
    - *   .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
    - *   .addPolicy(customPolicyOne)
    - *   .addPolicy(customPolicyTwo)
    - *   .httpClient(client)
    - *   .build();
    - * 
    + * {@link HttpClient http client} can be optionally configured in the {@link SecretClientBuilder}.

    + * + * {@codesnippet com.azure.security.keyvault.keys.async.secretclient.withhttpclient.instantiation} * *

    Alternatively, custom {@link HttpPipeline http pipeline} with custom {@link HttpPipelinePolicy} policies and {@link String endpoint} * can be specified. It provides finer control over the construction of {@link SecretAsyncClient client}

    - *
    - * SecretAsyncClient.builder()
    - *   .pipeline(new HttpPipeline(customPoliciesList))
    - *   .endpoint("https://myvault.vault.azure.net/")
    - *   .build()
    - * 
    + + * {@codesnippet com.azure.security.keyvault.keys.async.secretclient.pipeline.instantiation} * + * @see SecretClient +<<<<<<< HEAD +<<<<<<< HEAD +======= +>>>>>>> master * @see SecretAsyncClient */ -@ServiceClientBuilder(serviceClients = SecretAsyncClient.class) -public final class SecretAsyncClientBuilder { +@ServiceClientBuilder(serviceClients = SecretClient.class) +public final class SecretClientBuilder { private final List policies; private TokenCredential credential; private HttpPipeline pipeline; @@ -71,27 +64,48 @@ public final class SecretAsyncClientBuilder { private RetryPolicy retryPolicy; private Configuration configuration; - SecretAsyncClientBuilder() { + /** + * The constructor with defaults. + */ + public SecretClientBuilder() { retryPolicy = new RetryPolicy(); httpLogDetailLevel = HttpLogDetailLevel.NONE; policies = new ArrayList<>(); } + /** + * Creates a {@link SecretClient} based on options set in the builder. + * Every time {@code buildClient()} is called, a new instance of {@link SecretClient} is created. + * + *

    If {@link SecretClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link SecretClientBuilder#endpoint(String) serviceEndpoint} are used to create the + * {@link SecretClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, + * then {@link SecretClientBuilder#credential(TokenCredential) key vault credential and + * {@link SecretClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link SecretClient client}.}

    + * + * @return A SecretClient with the options set from the builder. + * @throws IllegalStateException If {@link SecretClientBuilder#credential(TokenCredential)} or + * {@link SecretClientBuilder#endpoint(String)} have not been set. + */ + public SecretClient buildClient() { + return new SecretClient(buildAsyncClient()); + } + /** * Creates a {@link SecretAsyncClient} based on options set in the builder. - * Every time {@code build()} is called, a new instance of {@link SecretAsyncClient} is created. + * Every time {@code buildAsyncClient()} is called, a new instance of {@link SecretAsyncClient} is created. * - *

    If {@link SecretAsyncClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and - * {@link SecretAsyncClientBuilder#endpoint(String) serviceEndpoint} are used to create the - * {@link SecretAsyncClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, - * then {@link SecretAsyncClientBuilder#credential(TokenCredential) key vault credential and - * {@link SecretAsyncClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link SecretAsyncClient client}.}

    + *

    If {@link SecretClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link SecretClientBuilder#endpoint(String) serviceEndpoint} are used to create the + * {@link SecretClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, + * then {@link SecretClientBuilder#credential(TokenCredential) key vault credential and + * {@link SecretClientBuilder#endpoint(String)} key vault endpoint are required to build the {@link SecretAsyncClient client}.}

    * * @return A SecretAsyncClient with the options set from the builder. - * @throws IllegalStateException If {@link SecretAsyncClientBuilder#credential(TokenCredential)} or - * {@link SecretAsyncClientBuilder#endpoint(String)} have not been set. + * @throws IllegalStateException If {@link SecretClientBuilder#credential(TokenCredential)} or + * {@link SecretClientBuilder#endpoint(String)} have not been set. */ - public SecretAsyncClient build() { + public SecretAsyncClient buildAsyncClient() { Configuration buildConfiguration = (configuration == null) ? ConfigurationManager.getConfiguration().clone() : configuration; URL buildEndpoint = getBuildEndpoint(buildConfiguration); @@ -127,13 +141,13 @@ public SecretAsyncClient build() { /** * Sets the vault endpoint url to send HTTP requests to. * - * @param endPoint The vault endpoint url is used as destination on Azure to send requests to. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @param endpoint The vault endpoint url is used as destination on Azure to send requests to. + * @return the updated {@link SecretClientBuilder} object. * @throws IllegalArgumentException if {@code endpoint} is null or it cannot be parsed into a valid URL. */ - public SecretAsyncClientBuilder endpoint(String endPoint) { + public SecretClientBuilder endpoint(String endpoint) { try { - this.endpoint = new URL(endPoint); + this.endpoint = new URL(endpoint); } catch (MalformedURLException e) { throw new IllegalArgumentException("The Azure Key Vault endpoint url is malformed."); } @@ -144,10 +158,10 @@ public SecretAsyncClientBuilder endpoint(String endPoint) { * Sets the credential to use when authenticating HTTP requests. * * @param credential The credential to use for authenticating HTTP requests. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @return the updated {@link SecretClientBuilder} object. * @throws NullPointerException if {@code credential} is {@code null}. */ - public SecretAsyncClientBuilder credential(TokenCredential credential) { + public SecretClientBuilder credential(TokenCredential credential) { Objects.requireNonNull(credential); this.credential = credential; return this; @@ -159,10 +173,10 @@ public SecretAsyncClientBuilder credential(TokenCredential credential) { *

    logLevel is optional. If not provided, default value of {@link HttpLogDetailLevel#NONE} is set.

    * * @param logLevel The amount of logging output when sending and receiving HTTP requests/responses. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @return the updated {@link SecretClientBuilder} object. * @throws NullPointerException if {@code logLevel} is {@code null}. */ - public SecretAsyncClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + public SecretClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { Objects.requireNonNull(logLevel); httpLogDetailLevel = logLevel; return this; @@ -170,13 +184,13 @@ public SecretAsyncClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) /** * Adds a policy to the set of existing policies that are executed after - * {@link SecretAsyncClient} required policies. + * {@link SecretAsyncClient} or {@link SecretClient} required policies. * * @param policy The {@link HttpPipelinePolicy policy} to be added. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @return the updated {@link SecretClientBuilder} object. * @throws NullPointerException if {@code policy} is {@code null}. */ - public SecretAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { + public SecretClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy); policies.add(policy); return this; @@ -186,10 +200,10 @@ public SecretAsyncClientBuilder addPolicy(HttpPipelinePolicy policy) { * Sets the HTTP client to use for sending and receiving requests to and from the service. * * @param client The HTTP client to use for requests. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @return the updated {@link SecretClientBuilder} object. * @throws NullPointerException If {@code client} is {@code null}. */ - public SecretAsyncClientBuilder httpClient(HttpClient client) { + public SecretClientBuilder httpClient(HttpClient client) { Objects.requireNonNull(client); this.httpClient = client; return this; @@ -199,12 +213,12 @@ public SecretAsyncClientBuilder httpClient(HttpClient client) { * Sets the HTTP pipeline to use for the service client. * * If {@code pipeline} is set, all other settings are ignored, aside from - * {@link SecretAsyncClientBuilder#endpoint(String) endpoint} to build {@link SecretAsyncClient}. + * {@link SecretClientBuilder#endpoint(String) endpoint} to build {@link SecretAsyncClient} or {@link SecretClient}. * * @param pipeline The HTTP pipeline to use for sending service requests and receiving responses. - * @return the updated {@link SecretAsyncClientBuilder} object. + * @return the updated {@link SecretClientBuilder} object. */ - public SecretAsyncClientBuilder pipeline(HttpPipeline pipeline) { + public SecretClientBuilder pipeline(HttpPipeline pipeline) { Objects.requireNonNull(pipeline); this.pipeline = pipeline; return this; @@ -217,9 +231,9 @@ public SecretAsyncClientBuilder pipeline(HttpPipeline pipeline) { * configuration store}, use {@link Configuration#NONE} to bypass using configuration settings during construction. * * @param configuration The configuration store used to - * @return The updated {@link SecretAsyncClientBuilder} object. + * @return The updated SecretClientBuilder object. */ - public SecretAsyncClientBuilder configuration(Configuration configuration) { + public SecretClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; } diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestAttributes.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestAttributes.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestAttributes.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestAttributes.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestParameters.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestParameters.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestParameters.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRequestParameters.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRestoreRequestParameters.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRestoreRequestParameters.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRestoreRequestParameters.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretRestoreRequestParameters.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretService.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretService.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/SecretService.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretService.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/DeletedSecretPage.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/DeletedSecretPage.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/DeletedSecretPage.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/DeletedSecretPage.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/SecretBasePage.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/SecretBasePage.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/SecretBasePage.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/implementation/SecretBasePage.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/DeletedSecret.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/DeletedSecret.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/DeletedSecret.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/DeletedSecret.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/Secret.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/Secret.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/Secret.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/Secret.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java similarity index 99% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java index 19d2017ae6bc7..2f64ee5fbc24b 100644 --- a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/SecretBase.java @@ -307,6 +307,7 @@ private void unpackId(String id) { * @param attributes The key value mapping of the Secret attributes */ @JsonProperty("attributes") + @SuppressWarnings("unchecked") private void unpackAttributes(Map attributes) { this.enabled = (Boolean) attributes.get("enabled"); this.notBefore = epochToOffsetDateTime(attributes.get("nbf")); diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/package-info.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/package-info.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/models/package-info.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/package-info.java diff --git a/keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/package-info.java b/sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/package-info.java similarity index 100% rename from keyvault/client/secrets/src/main/java/com/azure/security/keyvault/secrets/package-info.java rename to sdk/keyvault/azure-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/package-info.java diff --git a/keyvault/client/secrets/src/main/resources/kvErrorStrings.properties b/sdk/keyvault/azure-keyvault-secrets/src/main/resources/kvErrorStrings.properties similarity index 100% rename from keyvault/client/secrets/src/main/resources/kvErrorStrings.properties rename to sdk/keyvault/azure-keyvault-secrets/src/main/resources/kvErrorStrings.properties diff --git a/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperations.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperations.java similarity index 95% rename from keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperations.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperations.java index 5bceb419cf488..f905fd0cbc38d 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperations.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperations.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.models.Secret; import java.io.File; import java.io.FileOutputStream; @@ -30,10 +29,10 @@ public static void main(String[] args) throws IOException, InterruptedException, // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretClient client = SecretClient.builder() + SecretClient client = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create secrets holding storage account credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. diff --git a/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperationsAsync.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperationsAsync.java similarity index 86% rename from keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperationsAsync.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperationsAsync.java index c7f448f5a5d31..7b4bebaf5224f 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/BackupAndRestoreOperationsAsync.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/BackupAndRestoreOperationsAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretAsyncClient; import com.azure.security.keyvault.secrets.models.Secret; import java.io.File; import java.io.FileOutputStream; @@ -30,17 +29,17 @@ public static void main(String[] args) throws IOException, InterruptedException, // Instantiate async secret client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder() + SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create secrets holding storage account credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. secretAsyncClient.setSecret(new Secret("StorageAccountPassword", "f4G34fMh8v-fdsgjsk2323=-asdsdfsdf") - .expires(OffsetDateTime.now().plusYears(1))) - .subscribe(secretResponse -> - System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); + .expires(OffsetDateTime.now().plusYears(1))) + .subscribe(secretResponse -> + System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); Thread.sleep(2000); @@ -63,7 +62,7 @@ public static void main(String[] args) throws IOException, InterruptedException, // If the vault is soft-delete enabled, then you need to purge the secret as well for permanent deletion. secretAsyncClient.purgeDeletedSecret("StorageAccountPassword").subscribe(purgeResponse -> - System.out.printf("Purge Status response %d \n", purgeResponse.statusCode())); + System.out.printf("Purge Status response %d \n", purgeResponse.statusCode())); //To ensure file is purged on server side. Thread.sleep(15000); @@ -71,7 +70,7 @@ public static void main(String[] args) throws IOException, InterruptedException, // After sometime, the secret is required again. We can use the backup value to restore it in the key vault. byte[] backupFromFile = Files.readAllBytes(new File(backupFilePath).toPath()); secretAsyncClient.restoreSecret(backupFromFile).subscribe(secretResponse -> - System.out.printf("Restored Secret with name %s \n", secretResponse.value().name())); + System.out.printf("Restored Secret with name %s \n", secretResponse.value().name())); //To ensure secret is restored on server side. Thread.sleep(15000); diff --git a/keyvault/client/secrets/src/samples/java/secrets/HelloWorld.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorld.java similarity index 95% rename from keyvault/client/secrets/src/samples/java/secrets/HelloWorld.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorld.java index 380d13577c150..94f50ed062d15 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/HelloWorld.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorld.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.models.Secret; import com.azure.security.keyvault.secrets.models.SecretBase; import java.time.OffsetDateTime; @@ -26,10 +25,10 @@ public static void main(String[] args) throws InterruptedException, IllegalArgum // Instantiate a secret client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretClient secretClient = SecretClient.builder() + SecretClient secretClient = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create a secret holding bank account credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. diff --git a/keyvault/client/secrets/src/samples/java/secrets/HelloWorldAsync.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorldAsync.java similarity index 74% rename from keyvault/client/secrets/src/samples/java/secrets/HelloWorldAsync.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorldAsync.java index 90c8374317408..9f368c85c576d 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/HelloWorldAsync.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/HelloWorldAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretAsyncClient; import com.azure.security.keyvault.secrets.models.Secret; import java.time.OffsetDateTime; @@ -24,16 +23,16 @@ public static void main(String[] args) throws InterruptedException { // Instantiate an async secret client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder() + SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create a secret holding bank account credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. secretAsyncClient.setSecret(new Secret("BankAccountPassword", "f4G34fMh8v") - .expires(OffsetDateTime.now().plusYears(1))).subscribe(secretResponse -> - System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); + .expires(OffsetDateTime.now().plusYears(1))).subscribe(secretResponse -> + System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); Thread.sleep(2000); @@ -47,11 +46,11 @@ public static void main(String[] args) throws InterruptedException { // The update method can be used to update the expiry attribute of the secret. It cannot be used to update // the value of the secret. secretAsyncClient.getSecret("BankAccountPassword").subscribe(secretResponse -> { - Secret secret = secretResponse.value(); - //Update the expiry time of the secret. - secret.expires(secret.expires().plusYears(1)); - secretAsyncClient.updateSecret(secret).subscribe(updatedSecretResponse -> - System.out.printf("Secret's updated expiry time %s \n", updatedSecretResponse.value().expires().toString())); + Secret secret = secretResponse.value(); + //Update the expiry time of the secret. + secret.expires(secret.expires().plusYears(1)); + secretAsyncClient.updateSecret(secret).subscribe(updatedSecretResponse -> + System.out.printf("Secret's updated expiry time %s \n", updatedSecretResponse.value().expires().toString())); }); Thread.sleep(2000); @@ -60,20 +59,20 @@ public static void main(String[] args) throws InterruptedException { // To achieve this, we need to create a new version of the secret in the key vault. The update operation cannot // change the value of the secret. secretAsyncClient.setSecret("BankAccountPassword", "bhjd4DDgsa").subscribe(secretResponse -> - System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); + System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); Thread.sleep(2000); // The bank account was closed, need to delete its credentials from the key vault. secretAsyncClient.deleteSecret("BankAccountPassword").subscribe(deletedSecretResponse -> - System.out.printf("Deleted Secret's Recovery Id %s \n", deletedSecretResponse.value().recoveryId())); + System.out.printf("Deleted Secret's Recovery Id %s \n", deletedSecretResponse.value().recoveryId())); //To ensure secret is deleted on server side. Thread.sleep(30000); // If the key vault is soft-delete enabled, then for permanent deletion deleted secrets need to be purged. secretAsyncClient.purgeDeletedSecret("BankAccountPassword").subscribe(purgeResponse -> - System.out.printf("Bank account secret purge status response %d \n", purgeResponse.statusCode())); + System.out.printf("Bank account secret purge status response %d \n", purgeResponse.statusCode())); //To ensure secret is purged on server side. Thread.sleep(15000); diff --git a/keyvault/client/secrets/src/samples/java/secrets/ListOperations.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperations.java similarity index 95% rename from keyvault/client/secrets/src/samples/java/secrets/ListOperations.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperations.java index 87508fbc69229..f45e97af158f4 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/ListOperations.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperations.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.models.Secret; import com.azure.security.keyvault.secrets.models.SecretBase; @@ -25,10 +24,10 @@ public static void main(String[] args) throws IllegalArgumentException { // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretClient client = SecretClient.builder() + SecretClient client = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create secrets holding storage and bank accounts credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. diff --git a/keyvault/client/secrets/src/samples/java/secrets/ListOperationsAsync.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperationsAsync.java similarity index 85% rename from keyvault/client/secrets/src/samples/java/secrets/ListOperationsAsync.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperationsAsync.java index a362486474664..af085d95627b4 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/ListOperationsAsync.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ListOperationsAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretAsyncClient; import com.azure.security.keyvault.secrets.models.Secret; import java.time.OffsetDateTime; @@ -17,16 +16,17 @@ public class ListOperationsAsync { * * @param args Unused. Arguments to the program. * @throws IllegalArgumentException when invalid key vault endpoint is passed. + * @throws InterruptedException when the thread is interrupted in sleep mode. */ public static void main(String[] args) throws InterruptedException { // Instantiate an async secret client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder() + SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create secrets holding storage and bank accounts credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. @@ -47,16 +47,16 @@ public static void main(String[] args) throws InterruptedException { // You need to check if any of the secrets are sharing same values. Let's list the secrets and print their values. // List operations don't return the secrets with value information. So, for each returned secret we call getSecret to get the secret with its value information. secretAsyncClient.listSecrets() - .subscribe(secretBase -> - secretAsyncClient.getSecret(secretBase).subscribe(secretResponse -> - System.out.printf("Received secret with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value()))); + .subscribe(secretBase -> + secretAsyncClient.getSecret(secretBase).subscribe(secretResponse -> + System.out.printf("Received secret with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value()))); Thread.sleep(15000); // The bank account password got updated, so you want to update the secret in key vault to ensure it reflects the new password. // Calling setSecret on an existing secret creates a new version of the secret in the key vault with the new value. secretAsyncClient.setSecret(new Secret("BankAccountPassword", "sskdjfsdasdjsd") - .expires(OffsetDateTime.now().plusYears(1))).subscribe(secretResponse -> + .expires(OffsetDateTime.now().plusYears(1))).subscribe(secretResponse -> System.out.printf("Secret is created with name %s and value %s \n", secretResponse.value().name(), secretResponse.value().value())); Thread.sleep(2000); diff --git a/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecrets.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecrets.java similarity index 94% rename from keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecrets.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecrets.java index ad0b6e78232d8..b42b3f0c38700 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecrets.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecrets.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretClient; import com.azure.security.keyvault.secrets.models.DeletedSecret; import com.azure.security.keyvault.secrets.models.Secret; import java.time.OffsetDateTime; @@ -29,10 +28,10 @@ public static void main(String[] args) throws IllegalArgumentException, Interrup // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretClient client = SecretClient.builder() + SecretClient client = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildClient(); // Let's create secrets holding storage and bank accounts credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. @@ -50,7 +49,7 @@ public static void main(String[] args) throws IllegalArgumentException, Interrup // We accidentally deleted bank account secret. Let's recover it. // A deleted secret can only be recovered if the key vault is soft-delete enabled. - client.recoverDeletedSecret("BankAccountPassword"); + client.recoverDeletedSecret("BankAccountPassword"); //To ensure secret is recovered on server side. Thread.sleep(30000); diff --git a/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecretsAsync.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecretsAsync.java similarity index 84% rename from keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecretsAsync.java rename to sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecretsAsync.java index d1c06ec768de5..fa9e5a0915fb0 100644 --- a/keyvault/client/secrets/src/samples/java/secrets/ManagingDeletedSecretsAsync.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/ManagingDeletedSecretsAsync.java @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -package secrets; +package com.azure.security.keyvault.secrets; import com.azure.identity.credential.DefaultAzureCredential; -import com.azure.security.keyvault.secrets.SecretAsyncClient; import com.azure.security.keyvault.secrets.models.Secret; import java.time.OffsetDateTime; @@ -28,10 +27,10 @@ public static void main(String[] args) throws InterruptedException { // Instantiate a client that will be used to call the service. Notice that the client is using default Azure // credentials. To make default credentials work, ensure that environment variables 'AZURE_CLIENT_ID', // 'AZURE_CLIENT_KEY' and 'AZURE_TENANT_ID' are set with the service principal credentials. - SecretAsyncClient secretAsyncClient = SecretAsyncClient.builder() + SecretAsyncClient secretAsyncClient = new SecretClientBuilder() .endpoint("https://{YOUR_VAULT_NAME}.vault.azure.net") .credential(new DefaultAzureCredential()) - .build(); + .buildAsyncClient(); // Let's create secrets holding storage and bank accounts credentials valid for 1 year. if the secret // already exists in the key vault, then a new version of the secret is created. @@ -56,8 +55,8 @@ public static void main(String[] args) throws InterruptedException { // We accidentally deleted bank account secret. Let's recover it. // A deleted secret can only be recovered if the key vault is soft-delete enabled. - secretAsyncClient.recoverDeletedSecret("BankAccountPassword").subscribe(recoveredSecretResponse -> - System.out.printf("Recovered Secret with name %s \n", recoveredSecretResponse.value().name())); + secretAsyncClient.recoverDeletedSecret("BankAccountPassword").subscribe(recoveredSecretResponse -> + System.out.printf("Recovered Secret with name %s \n", recoveredSecretResponse.value().name())); //To ensure secret is recovered on server side. Thread.sleep(10000); @@ -80,11 +79,11 @@ public static void main(String[] args) throws InterruptedException { Thread.sleep(15000); // If the key vault is soft-delete enabled, then for permanent deletion deleted secrets need to be purged. - secretAsyncClient.purgeDeletedSecret("StorageAccountPassword").subscribe(purgeResponse -> - System.out.printf("Storage account secret purge status response %d \n", purgeResponse.statusCode())); + secretAsyncClient.purgeDeletedSecret("StorageAccountPassword").subscribe(purgeResponse -> + System.out.printf("Storage account secret purge status response %d \n", purgeResponse.statusCode())); - secretAsyncClient.purgeDeletedSecret("BankAccountPassword").subscribe(purgeResponse -> - System.out.printf("Bank account secret purge status response %d \n", purgeResponse.statusCode())); + secretAsyncClient.purgeDeletedSecret("BankAccountPassword").subscribe(purgeResponse -> + System.out.printf("Bank account secret purge status response %d \n", purgeResponse.statusCode())); // To ensure secret is purged on server side. Thread.sleep(15000); diff --git a/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java new file mode 100644 index 0000000000000..16875208d6e89 --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/src/samples/java/com/azure/security/keyvault/secrets/SecretClientJavaDocCodeSnippets.java @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.secrets; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.test.models.RecordedData; +import com.azure.core.test.policy.RecordNetworkCallPolicy; +import com.azure.identity.credential.DefaultAzureCredential; +import com.azure.security.keyvault.secrets.models.Secret; +import com.azure.security.keyvault.secrets.models.SecretBase; + +/** + * This class contains code samples for generating javadocs through doclets for {@link SecretClient] + */ +public final class SecretClientJavaDocCodeSnippets { + + /** + * Generates code sample for creating a {@link SecretAsyncClient} + * @return An instance of {@link SecretAsyncClient} + */ + public SecretAsyncClient createAsyncClientWithHttpclient() { + // BEGIN: com.azure.security.keyvault.keys.async.secretclient.withhttpclient.instantiation + RecordedData networkData = new RecordedData(); + HttpPipeline pipeline = HttpPipeline.builder().policies(new RecordNetworkCallPolicy(networkData)).build(); + SecretAsyncClient keyClient = new SecretClientBuilder() + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .addPolicy(new RecordNetworkCallPolicy(networkData)) + .httpClient(HttpClient.createDefault()) + .buildAsyncClient(); + // END: com.azure.security.keyvault.keys.async.secretclient.withhttpclient.instantiation + return keyClient; + } + + /** + * Method to insert code snippets for {@link SecretClient#getSecret(SecretBase)} + */ + public void getSecret() { + SecretClient secretClient = getSecretClient(); + // BEGIN: com.azure.security.keyvault.secretclient.getSecret#secretBase + for (SecretBase secret : secretClient.listSecrets()) { + Secret secretWithValue = secretClient.getSecret(secret).value(); + System.out.printf("Secret is returned with name %s and value %s %n", secretWithValue.name(), + secretWithValue.value()); + } + // END: com.azure.security.keyvault.secretclient.getSecret#secretBase + } + + /** + * Implementation for async SecretAsyncClient + * @return sync SecretAsyncClient + */ + private SecretAsyncClient getAsyncSecretClient() { + + // BEGIN: com.azure.security.keyvault.secretclient.async.construct + SecretAsyncClient secretClient = new SecretClientBuilder() + .credential(new DefaultAzureCredential()) + .endpoint("https://myvault.vault.azure.net/") + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildAsyncClient(); + // END: com.azure.security.keyvault.secretclient.async.construct + return secretClient; + } + + /** + * Implementation for sync SecretClient + * @return sync SecretClient + */ + private SecretClient getSyncSecretClient() { + + // BEGIN: com.azure.security.keyvault.secretclient.sync.construct + SecretClient secretClient = new SecretClientBuilder() + .credential(new DefaultAzureCredential()) + .endpoint("https://myvault.vault.azure.net/") + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .buildClient(); + // END: com.azure.security.keyvault.secretclient.sync.construct + return secretClient; + } + + /** + * Generates code sample for creating a {@link SecretAsyncClient} + * @return An instance of {@link SecretAsyncClient} + */ + public SecretAsyncClient createAsyncClientWithPipeline() { + // BEGIN: com.azure.security.keyvault.keys.async.secretclient.pipeline.instantiation + RecordedData networkData = new RecordedData(); + HttpPipeline pipeline = HttpPipeline.builder().policies(new RecordNetworkCallPolicy(networkData)).build(); + SecretAsyncClient keyClient = new SecretClientBuilder() + .pipeline(pipeline) + .endpoint("https://myvault.azure.net/") + .credential(new DefaultAzureCredential()) + .buildAsyncClient(); + // END: com.azure.security.keyvault.keys.async.secretclient.pipeline.instantiation + return keyClient; + } + + /** + * Implementation not provided for this method + * @return {@code null} + */ + private SecretClient getSecretClient() { + return null; + } +} diff --git a/keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java b/sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java similarity index 98% rename from keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java rename to sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java index 72bdc602c10e9..bbae5720cb30b 100644 --- a/keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretAsyncClientTest.java @@ -33,21 +33,21 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> SecretAsyncClient.builder() + client = clientSetup(credentials -> new SecretClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildAsyncClient()); } else { - client = clientSetup(credentials -> SecretAsyncClient.builder() + client = clientSetup(credentials -> new SecretClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildAsyncClient()); } } diff --git a/keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java b/sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java similarity index 98% rename from keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java rename to sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java index 3ff562cfc28f8..3500c5dec3c7c 100644 --- a/keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java +++ b/sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTest.java @@ -30,21 +30,21 @@ protected void beforeTest() { beforeTestSetup(); if (interceptorManager.isPlaybackMode()) { - client = clientSetup(credentials -> SecretClient.builder() + client = clientSetup(credentials -> new SecretClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(interceptorManager.getPlaybackClient()) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) - .build()); + .buildClient()); } else { - client = clientSetup(credentials -> SecretClient.builder() + client = clientSetup(credentials -> new SecretClientBuilder() .credential(credentials) .endpoint(getEndpoint()) .httpClient(HttpClient.createDefault().wiretap(true)) .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) .addPolicy(interceptorManager.getRecordPolicy()) .addPolicy(new RetryPolicy()) - .build()); + .buildClient()); } } diff --git a/keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTestBase.java b/sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTestBase.java similarity index 100% rename from keyvault/client/secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTestBase.java rename to sdk/keyvault/azure-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/SecretClientTestBase.java diff --git a/keyvault/client/secrets/src/test/resources/session-records/backupSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/backupSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/backupSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/backupSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/backupSecretNotFound.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/backupSecretNotFound.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/backupSecretNotFound.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/backupSecretNotFound.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/deleteSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/deleteSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/deleteSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/deleteSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/deleteSecretNotFound.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/deleteSecretNotFound.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/deleteSecretNotFound.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/deleteSecretNotFound.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/getDeletedSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getDeletedSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/getDeletedSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getDeletedSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/getDeletedSecretNotFound.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getDeletedSecretNotFound.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/getDeletedSecretNotFound.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getDeletedSecretNotFound.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/getSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/getSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/getSecretNotFound.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecretNotFound.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/getSecretNotFound.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecretNotFound.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/getSecretSpecificVersion.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecretSpecificVersion.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/getSecretSpecificVersion.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/getSecretSpecificVersion.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/listDeletedSecrets.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listDeletedSecrets.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/listDeletedSecrets.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listDeletedSecrets.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/listSecretVersions.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listSecretVersions.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/listSecretVersions.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listSecretVersions.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/listSecrets.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listSecrets.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/listSecrets.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/listSecrets.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/recoverDeletedSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/recoverDeletedSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/recoverDeletedSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/recoverDeletedSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/recoverDeletedSecretNotFound.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/recoverDeletedSecretNotFound.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/recoverDeletedSecretNotFound.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/recoverDeletedSecretNotFound.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/restoreSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/restoreSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/restoreSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/restoreSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/restoreSecretFromMalformedBackup.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/restoreSecretFromMalformedBackup.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/restoreSecretFromMalformedBackup.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/restoreSecretFromMalformedBackup.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/setSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/setSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/setSecretEmptyName.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretEmptyName.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/setSecretEmptyName.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretEmptyName.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/setSecretEmptyValue.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretEmptyValue.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/setSecretEmptyValue.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretEmptyValue.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/setSecretNull.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretNull.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/setSecretNull.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/setSecretNull.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/updateDisabledSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateDisabledSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/updateDisabledSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateDisabledSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/updateSecret.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateSecret.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/updateSecret.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateSecret.json diff --git a/keyvault/client/secrets/src/test/resources/session-records/updateSetting.json b/sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateSetting.json similarity index 100% rename from keyvault/client/secrets/src/test/resources/session-records/updateSetting.json rename to sdk/keyvault/azure-keyvault-secrets/src/test/resources/session-records/updateSetting.json diff --git a/keyvault/data-plane/history.md b/sdk/keyvault/history.md similarity index 100% rename from keyvault/data-plane/history.md rename to sdk/keyvault/history.md diff --git a/keyvault/data-plane/azure-keyvault-complete/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-complete/pom.xml similarity index 97% rename from keyvault/data-plane/azure-keyvault-complete/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-complete/pom.xml index d9d090442fb9c..52b486d560c35 100644 --- a/keyvault/data-plane/azure-keyvault-complete/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-complete/pom.xml @@ -8,7 +8,7 @@ the MIT License. See License.txt in the project root for license information. -- com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml com.microsoft.azure diff --git a/keyvault/data-plane/azure-keyvault-core/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-core/pom.xml similarity index 97% rename from keyvault/data-plane/azure-keyvault-core/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-core/pom.xml index 85059fc4aa9d6..ac37e02c8f659 100644 --- a/keyvault/data-plane/azure-keyvault-core/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-core/pom.xml @@ -9,7 +9,7 @@ com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml com.microsoft.azure diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java b/sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java rename to sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKey.java diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java b/sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java rename to sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/IKeyResolver.java diff --git a/keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java b/sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault-core/src/main/java/com/microsoft/azure/keyvault/core/package-info.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-cryptography/pom.xml similarity index 98% rename from keyvault/data-plane/azure-keyvault-cryptography/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/pom.xml index b0b295a50453f..b89291571a57c 100644 --- a/keyvault/data-plane/azure-keyvault-cryptography/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-cryptography/pom.xml @@ -8,7 +8,7 @@ com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml com.microsoft.azure diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Algorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AlgorithmResolver.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricEncryptionAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/AsymmetricSignatureAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ByteExtensions.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EcKey.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/EncryptionAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/IAuthenticatedCryptoTransform.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ICryptoTransform.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/ISignatureTransform.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/KeyWrapAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/RsaKey.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SignatureEncoding.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/Strings.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricEncryptionAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/SymmetricKey.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128Cbc.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes128CbcHmacSha256.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192Cbc.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes192CbcHmacSha384.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256Cbc.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Aes256CbcHmacSha512.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbc.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesCbcHmacSha2.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw128.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw192.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/AesKw256.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Ecdsa.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es256k.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es384.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Es512.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rs256.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/Rsa15.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaEncryption.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaOaep.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/RsaSignature.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/algorithms/package-info.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/main/java/com/microsoft/azure/keyvault/cryptography/package-info.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcHmacShaTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesCbcTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/AesKwTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/ECKeyTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/PemFile.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/PemFile.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/PemFile.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/PemFile.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/RsaKeyTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/java/com/microsoft/azure/keyvault/cryptography/test/SymmetricKeyTest.java diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/SECP256key.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/SECP256key.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/SECP256key.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/SECP256key.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/byte_array.bin b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/byte_array.bin similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/byte_array.bin rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/byte_array.bin diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256key.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256key.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256key.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256key.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256keynew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256keynew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256keynew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256keynew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256keypubnew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256keypubnew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256keypubnew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256keypubnew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256sig.der b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256sig.der similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p256sig.der rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p256sig.der diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384keynew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384keynew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384keynew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384keynew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384keypubnew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384keypubnew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384keypubnew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384keypubnew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384sig.der b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384sig.der similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p384sig.der rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p384sig.der diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521keynew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521keynew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521keynew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521keynew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521keypubnew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521keypubnew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521keypubnew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521keypubnew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521sig.der b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521sig.der similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/p521sig.der rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/p521sig.der diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256keynew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256keynew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256keynew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256keynew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256keypubnew.pem b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256keypubnew.pem similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256keypubnew.pem rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256keypubnew.pem diff --git a/keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256sig.der b/sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256sig.der similarity index 100% rename from keyvault/data-plane/azure-keyvault-cryptography/src/test/resources/secp256sig.der rename to sdk/keyvault/microsoft-azure-keyvault-cryptography/src/test/resources/secp256sig.der diff --git a/keyvault/data-plane/azure-keyvault-extensions/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-extensions/pom.xml similarity index 98% rename from keyvault/data-plane/azure-keyvault-extensions/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-extensions/pom.xml index 17bda8b4fe68e..40eb0fbb486a7 100644 --- a/keyvault/data-plane/azure-keyvault-extensions/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-extensions/pom.xml @@ -9,7 +9,7 @@ com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml azure-keyvault-extensions diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/AggregateKeyResolver.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/CachingKeyResolver.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKey.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/KeyVaultKeyResolver.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/Strings.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/main/java/com/microsoft/azure/keyvault/extensions/package.html diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/CachingKeyResolverTest.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultClientIntegrationTestBase.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverBCProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/java/com/microsoft/azure/keyvault/extensions/test/KeyVaultKeyResolverDefaultProviderTest.java diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverBCProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverBCProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverBCProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverBCProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverDefaultProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverDefaultProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverDefaultProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/keyKeyVaultKeyResolverDefaultProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverBCProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverBCProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverBCProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverBCProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverDefaultProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverDefaultProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverDefaultProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret128Base64KeyVaultKeyResolverDefaultProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverBCProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverBCProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverBCProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverBCProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverDefaultProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverDefaultProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverDefaultProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret192Base64KeyVaultKeyResolverDefaultProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverBCProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverBCProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverBCProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverBCProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverDefaultProviderTest.json b/sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverDefaultProviderTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverDefaultProviderTest.json rename to sdk/keyvault/microsoft-azure-keyvault-extensions/src/test/resources/session-records/secret256Base64KeyVaultKeyResolverDefaultProviderTest.json diff --git a/keyvault/data-plane/azure-keyvault-test/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-test/pom.xml similarity index 98% rename from keyvault/data-plane/azure-keyvault-test/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-test/pom.xml index 6d3a3cf985cd5..f8dd24695ff9f 100644 --- a/keyvault/data-plane/azure-keyvault-test/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-test/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml azure-keyvault-test azure-keyvault-test diff --git a/keyvault/data-plane/azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java b/sdk/keyvault/microsoft-azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-test/src/test/java/com/microsoft/azure/keyvault/test/EcKeyIntegrationTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/pom.xml b/sdk/keyvault/microsoft-azure-keyvault-webkey/pom.xml similarity index 98% rename from keyvault/data-plane/azure-keyvault-webkey/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault-webkey/pom.xml index 7091c9630d612..f79a9cda82ce4 100644 --- a/keyvault/data-plane/azure-keyvault-webkey/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault-webkey/pom.xml @@ -7,7 +7,7 @@ com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml azure-keyvault-webkey diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonDeserializer.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/Base64UrlJsonSerializer.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/ByteExtensions.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/ByteExtensions.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/ByteExtensions.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/ByteExtensions.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java similarity index 99% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java index bece713ef94a9..097fefdeb5b4b 100644 --- a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java +++ b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKey.java @@ -1154,7 +1154,10 @@ public int hashCode() { } else if (JsonWebKeyType.EC.equals(kty)) { hashCode += hashCode(x); hashCode += hashCode(y); - hashCode += crv.hashCode(); + + if (crv != null) { + hashCode += crv.hashCode(); + } } else if (JsonWebKeyType.RSA_HSM.equals(kty) || JsonWebKeyType.EC_HSM.equals(kty)) { hashCode += hashCode(t); } diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyCurveName.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyEncryptionAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyOperation.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeySignatureAlgorithm.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/JsonWebKeyType.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/main/java/com/microsoft/azure/keyvault/webkey/package-info.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/AesValidationTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/ClearMemoryTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcHsmValidationTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/EcValidationTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaHsmValidationTests.java diff --git a/keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java b/sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java similarity index 100% rename from keyvault/data-plane/azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java rename to sdk/keyvault/microsoft-azure-keyvault-webkey/src/test/java/com/microsoft/azure/keyvault/webkey/test/RsaValidationTests.java diff --git a/keyvault/data-plane/azure-keyvault/pom.xml b/sdk/keyvault/microsoft-azure-keyvault/pom.xml similarity index 99% rename from keyvault/data-plane/azure-keyvault/pom.xml rename to sdk/keyvault/microsoft-azure-keyvault/pom.xml index efccc7a35fac6..482acf233fe3c 100644 --- a/keyvault/data-plane/azure-keyvault/pom.xml +++ b/sdk/keyvault/microsoft-azure-keyvault/pom.xml @@ -7,7 +7,7 @@ the MIT License. See License.txt in the project root for license information. -- com.microsoft.azure azure-keyvault-parent 1.2.1 - ../pom.xml + ../pom.data.xml com.microsoft.azure diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/CertificateOperationIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/IssuerIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClient.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientBase.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientCustom.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientCustom.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientCustom.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientCustom.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientImpl.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientImpl.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientImpl.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/KeyVaultClientImpl.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/ObjectIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/ObjectIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/ObjectIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/ObjectIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/SecretIdentifier.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/SecretIdentifier.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/SecretIdentifier.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/SecretIdentifier.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/AuthenticationResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/AuthenticationResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/AuthenticationResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/AuthenticationResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/ChallengeCache.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/ChallengeCache.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/ChallengeCache.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/ChallengeCache.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/KeyVaultCredentials.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/authentication/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientBaseImpl.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientBaseImpl.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientBaseImpl.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientBaseImpl.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientCustomImpl.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientCustomImpl.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientCustomImpl.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/KeyVaultClientCustomImpl.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/implementation/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/HttpMessageSecurity.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEHeader.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEHeader.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEHeader.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEHeader.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEObject.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEObject.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEObject.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWEObject.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSHeader.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSHeader.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSHeader.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSHeader.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSObject.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSObject.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSObject.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/JWSObject.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/MessageSecurityHelper.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/messagesecurity/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Action.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Action.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Action.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Action.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/ActionType.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/ActionType.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/ActionType.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/ActionType.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/AdministratorDetails.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/AdministratorDetails.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/AdministratorDetails.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/AdministratorDetails.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Attributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Attributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Attributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Attributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupCertificateResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupCertificateResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupCertificateResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupCertificateResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupKeyResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupKeyResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupKeyResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupKeyResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupSecretResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupSecretResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupSecretResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupSecretResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupStorageResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupStorageResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupStorageResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/BackupStorageResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateCreateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateCreateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateCreateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateCreateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateImportParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateImportParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateImportParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateImportParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerSetParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerSetParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerSetParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerSetParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateIssuerUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateMergeParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateMergeParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateMergeParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateMergeParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperation.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperation.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperation.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperation.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperationUpdateParameter.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperationUpdateParameter.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperationUpdateParameter.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateOperationUpdateParameter.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificatePolicy.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificatePolicy.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificatePolicy.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificatePolicy.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateRestoreParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateRestoreParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateRestoreParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateRestoreParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/CertificateUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contact.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contact.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contact.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contact.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contacts.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contacts.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contacts.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Contacts.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedCertificateItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedKeyItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSasDefinitionItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedSecretItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageAccountItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageAccountItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageAccountItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageAccountItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletedStorageBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletionRecoveryLevel.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletionRecoveryLevel.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletionRecoveryLevel.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/DeletionRecoveryLevel.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Error.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Error.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Error.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Error.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerCredentials.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerCredentials.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerCredentials.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerCredentials.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/IssuerParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/JsonWebKeyCurveName.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/JsonWebKeyCurveName.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/JsonWebKeyCurveName.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/JsonWebKeyCurveName.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyCreateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyCreateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyCreateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyCreateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyImportParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyImportParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyImportParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyImportParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationsParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationsParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationsParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyOperationsParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyProperties.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyProperties.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyProperties.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyProperties.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyRestoreParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyRestoreParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyRestoreParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyRestoreParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeySignParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeySignParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeySignParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeySignParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUsageType.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUsageType.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUsageType.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyUsageType.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultError.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultError.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultError.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultError.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultErrorException.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultErrorException.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultErrorException.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVaultErrorException.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/KeyVerifyResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/LifetimeAction.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/LifetimeAction.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/LifetimeAction.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/LifetimeAction.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/OrganizationDetails.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/OrganizationDetails.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/OrganizationDetails.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/OrganizationDetails.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PageImpl.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PageImpl.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PageImpl.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PageImpl.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PendingCertificateSigningRequestResult.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PendingCertificateSigningRequestResult.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PendingCertificateSigningRequestResult.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/PendingCertificateSigningRequestResult.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionCreateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionCreateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionCreateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionCreateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasDefinitionUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasTokenType.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasTokenType.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasTokenType.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SasTokenType.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretProperties.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretProperties.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretProperties.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretProperties.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretRestoreParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretRestoreParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretRestoreParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretRestoreParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretSetParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretSetParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretSetParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretSetParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SecretUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountAttributes.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountAttributes.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountAttributes.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountAttributes.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountCreateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountCreateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountCreateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountCreateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountItem.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountItem.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountItem.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountItem.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountRegenerteKeyParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountRegenerteKeyParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountRegenerteKeyParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountRegenerteKeyParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountUpdateParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountUpdateParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountUpdateParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageAccountUpdateParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageRestoreParameters.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageRestoreParameters.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageRestoreParameters.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/StorageRestoreParameters.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SubjectAlternativeNames.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SubjectAlternativeNames.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SubjectAlternativeNames.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/SubjectAlternativeNames.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Trigger.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Trigger.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Trigger.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/Trigger.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/X509CertificateProperties.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/X509CertificateProperties.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/X509CertificateProperties.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/X509CertificateProperties.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateOperation.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateOperation.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateOperation.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/CertificateOperation.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/IssuerBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/IssuerBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/IssuerBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/IssuerBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/KeyBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/KeyBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/KeyBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/KeyBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/SecretBundle.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/SecretBundle.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/SecretBundle.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/SecretBundle.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/custom/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/models/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateCertificateRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateCertificateRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateCertificateRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateCertificateRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateKeyRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateKeyRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateKeyRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/CreateKeyRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportCertificateRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportCertificateRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportCertificateRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportCertificateRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportKeyRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportKeyRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportKeyRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/ImportKeyRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/MergeCertificateRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/MergeCertificateRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/MergeCertificateRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/MergeCertificateRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetCertificateIssuerRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetCertificateIssuerRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetCertificateIssuerRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetCertificateIssuerRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetSecretRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetSecretRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetSecretRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/SetSecretRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateIssuerRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateIssuerRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateIssuerRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateIssuerRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateOperationRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateOperationRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateOperationRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateOperationRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificatePolicyRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificatePolicyRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificatePolicyRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificatePolicyRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateCertificateRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateKeyRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateKeyRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateKeyRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateKeyRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateSecretRequest.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateSecretRequest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateSecretRequest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/UpdateSecretRequest.java diff --git a/keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/package-info.java b/sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/package-info.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/package-info.java rename to sdk/keyvault/microsoft-azure-keyvault/src/main/java/com/microsoft/azure/keyvault/requests/package-info.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/AsyncOperationsTest.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/AsyncOperationsTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/AsyncOperationsTest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/AsyncOperationsTest.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/CertificateOperationsTest.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/CertificateOperationsTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/CertificateOperationsTest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/CertificateOperationsTest.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/EnhancedKeyVaultTest.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/EnhancedKeyVaultTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/EnhancedKeyVaultTest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/EnhancedKeyVaultTest.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/ITManagedStorageAccountKey.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/ITManagedStorageAccountKey.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/ITManagedStorageAccountKey.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/ITManagedStorageAccountKey.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyOperationsTest.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyOperationsTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyOperationsTest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyOperationsTest.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyVaultClientIntegrationTestBase.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyVaultClientIntegrationTestBase.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyVaultClientIntegrationTestBase.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/KeyVaultClientIntegrationTestBase.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/SecretOperationsTest.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/SecretOperationsTest.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/SecretOperationsTest.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/SecretOperationsTest.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/crudNames.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/crudNames.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/crudNames.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/crudNames.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/resources/MockUserTokenCredentials.java b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/resources/MockUserTokenCredentials.java similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/resources/MockUserTokenCredentials.java rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/resources/MockUserTokenCredentials.java diff --git a/keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/sasNames.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/sasNames.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/sasNames.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/java/com/microsoft/azure/keyvault/test/sasNames.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/backupRestoreForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/backupRestoreForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/backupRestoreForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/backupRestoreForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateAsyncForAsyncOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateAsyncForAsyncOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateAsyncForAsyncOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateAsyncForAsyncOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateAsyncRequestCancellationForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateAsyncRequestCancellationForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateAsyncRequestCancellationForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateAsyncRequestCancellationForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateContactsAsyncForAsyncOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateContactsAsyncForAsyncOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateContactsAsyncForAsyncOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateContactsAsyncForAsyncOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateUpdateForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateUpdateForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/certificateUpdateForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/certificateUpdateForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/contactsCrudOperationsForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/contactsCrudOperationsForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/contactsCrudOperationsForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/contactsCrudOperationsForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCertificatePemForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCertificatePemForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCertificatePemForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCertificatePemForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCertificatePkcs12ForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCertificatePkcs12ForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCertificatePkcs12ForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCertificatePkcs12ForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCsrForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCsrForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createCsrForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createCsrForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePemForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePemForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePemForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePemForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePkcs12ForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePkcs12ForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePkcs12ForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/createSelfSignedCertificatePkcs12ForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/crudOperationsForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/crudOperationsForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/crudOperationsForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/crudOperationsForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/crudOperationsForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/crudOperationsForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/crudOperationsForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/crudOperationsForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/deserializeWithExtraFieldTestForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/deserializeWithExtraFieldTestForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/deserializeWithExtraFieldTestForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/deserializeWithExtraFieldTestForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/disabledSecretGetForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/disabledSecretGetForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/disabledSecretGetForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/disabledSecretGetForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/encryptDecryptOperationsForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/encryptDecryptOperationsForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/encryptDecryptOperationsForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/encryptDecryptOperationsForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/importCertificatePkcs12ForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/importCertificatePkcs12ForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/importCertificatePkcs12ForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/importCertificatePkcs12ForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/importKeyOperationForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/importKeyOperationForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/importKeyOperationForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/importKeyOperationForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/issuerAsyncForAsyncOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/issuerAsyncForAsyncOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/issuerAsyncForAsyncOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/issuerAsyncForAsyncOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/issuerCrudOperationsForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/issuerCrudOperationsForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/issuerCrudOperationsForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/issuerCrudOperationsForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/keyAsyncForAsyncOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/keyAsyncForAsyncOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/keyAsyncForAsyncOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/keyAsyncForAsyncOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listCertificateVersionsForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listCertificateVersionsForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listCertificateVersionsForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listCertificateVersionsForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listCertificatesForCertificateOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listCertificatesForCertificateOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listCertificatesForCertificateOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listCertificatesForCertificateOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listKeyVersionsForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listKeyVersionsForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listKeyVersionsForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listKeyVersionsForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listKeysForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listKeysForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listKeysForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listKeysForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listSecretVersionsForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listSecretVersionsForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listSecretVersionsForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listSecretVersionsForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listSecretsForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listSecretsForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/listSecretsForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/listSecretsForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/secretAsyncForAsyncOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/secretAsyncForAsyncOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/secretAsyncForAsyncOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/secretAsyncForAsyncOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/signVerifyOperationsForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/signVerifyOperationsForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/signVerifyOperationsForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/signVerifyOperationsForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/testCrudOperationsForManagedStorageAccountKey.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/testCrudOperationsForManagedStorageAccountKey.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/testCrudOperationsForManagedStorageAccountKey.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/testCrudOperationsForManagedStorageAccountKey.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/testSetAndGetSasDefinitionForManagedStorageAccountKey.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/testSetAndGetSasDefinitionForManagedStorageAccountKey.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/testSetAndGetSasDefinitionForManagedStorageAccountKey.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/testSetAndGetSasDefinitionForManagedStorageAccountKey.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/transparentAuthenticationForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/transparentAuthenticationForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/transparentAuthenticationForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/transparentAuthenticationForKeyOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/transparentAuthenticationForSecretOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/transparentAuthenticationForSecretOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/transparentAuthenticationForSecretOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/transparentAuthenticationForSecretOperationsTest.json diff --git a/keyvault/data-plane/azure-keyvault/src/test/resources/session-records/wrapUnwrapOperationsForKeyOperationsTest.json b/sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/wrapUnwrapOperationsForKeyOperationsTest.json similarity index 100% rename from keyvault/data-plane/azure-keyvault/src/test/resources/session-records/wrapUnwrapOperationsForKeyOperationsTest.json rename to sdk/keyvault/microsoft-azure-keyvault/src/test/resources/session-records/wrapUnwrapOperationsForKeyOperationsTest.json diff --git a/keyvault/client/pom.xml b/sdk/keyvault/pom.client.xml similarity index 90% rename from keyvault/client/pom.xml rename to sdk/keyvault/pom.client.xml index 70be876c33f2d..56af4e99df0b5 100644 --- a/keyvault/client/pom.xml +++ b/sdk/keyvault/pom.client.xml @@ -6,7 +6,7 @@ com.azure azure-client-sdk-parent - 1.0.0 + 1.1.0 ../../pom.client.xml @@ -32,7 +32,7 @@ - ./keys - ./secrets + azure-keyvault-keys + azure-keyvault-secrets diff --git a/keyvault/data-plane/pom.xml b/sdk/keyvault/pom.data.xml similarity index 90% rename from keyvault/data-plane/pom.xml rename to sdk/keyvault/pom.data.xml index c3bac6c2f660a..9c56b7e650792 100644 --- a/keyvault/data-plane/pom.xml +++ b/sdk/keyvault/pom.data.xml @@ -9,7 +9,7 @@ com.azure azure-data-sdk-parent - 1.0.0 + 1.1.0 ../../pom.data.xml @@ -110,11 +110,11 @@ - ./azure-keyvault - ./azure-keyvault-core - ./azure-keyvault-webkey - ./azure-keyvault-cryptography - ./azure-keyvault-extensions - ./azure-keyvault-complete + microsoft-azure-keyvault + microsoft-azure-keyvault-core + microsoft-azure-keyvault-webkey + microsoft-azure-keyvault-cryptography + microsoft-azure-keyvault-extensions + microsoft-azure-keyvault-complete diff --git a/sdk/keyvault/pom.service.xml b/sdk/keyvault/pom.service.xml index ffc5061e45ff4..862a0ba0d96ee 100644 --- a/sdk/keyvault/pom.service.xml +++ b/sdk/keyvault/pom.service.xml @@ -9,6 +9,21 @@ pom 1.0.0 + + microsoft-azure-keyvault + microsoft-azure-keyvault-core + microsoft-azure-keyvault-webkey + microsoft-azure-keyvault-cryptography + microsoft-azure-keyvault-extensions + microsoft-azure-keyvault-complete + + + ../../core + ../identity/azure-identity + azure-keyvault-keys + azure-keyvault-secrets + + diff --git a/keyvault/data-plane/regenerate_and_fix_sdk.py b/sdk/keyvault/regenerate_and_fix_sdk.py similarity index 100% rename from keyvault/data-plane/regenerate_and_fix_sdk.py rename to sdk/keyvault/regenerate_and_fix_sdk.py diff --git a/keyvault/data-plane/tests.yml b/sdk/keyvault/tests.yml similarity index 100% rename from keyvault/data-plane/tests.yml rename to sdk/keyvault/tests.yml diff --git a/sdk/loganalytics/ci.yml b/sdk/loganalytics/ci.yml new file mode 100644 index 0000000000000..a115776c40a5e --- /dev/null +++ b/sdk/loganalytics/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/loganalytics/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/loganalytics/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: loganalytics \ No newline at end of file diff --git a/loganalytics/data-plane/README.md b/sdk/loganalytics/microsoft-azure-loganalytics/README.md similarity index 100% rename from loganalytics/data-plane/README.md rename to sdk/loganalytics/microsoft-azure-loganalytics/README.md diff --git a/loganalytics/data-plane/pom.xml b/sdk/loganalytics/microsoft-azure-loganalytics/pom.xml similarity index 100% rename from loganalytics/data-plane/pom.xml rename to sdk/loganalytics/microsoft-azure-loganalytics/pom.xml diff --git a/loganalytics/data-plane/samples/pom.xml b/sdk/loganalytics/microsoft-azure-loganalytics/samples/pom.xml similarity index 100% rename from loganalytics/data-plane/samples/pom.xml rename to sdk/loganalytics/microsoft-azure-loganalytics/samples/pom.xml diff --git a/loganalytics/data-plane/samples/src/main/java/com/microsoft/azure/loganalytics/samples/BasicSample.java b/sdk/loganalytics/microsoft-azure-loganalytics/samples/src/main/java/com/microsoft/azure/loganalytics/samples/BasicSample.java similarity index 100% rename from loganalytics/data-plane/samples/src/main/java/com/microsoft/azure/loganalytics/samples/BasicSample.java rename to sdk/loganalytics/microsoft-azure-loganalytics/samples/src/main/java/com/microsoft/azure/loganalytics/samples/BasicSample.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClient.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClient.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClient.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClient.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/implementation/LogAnalyticsDataClientImpl.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/implementation/LogAnalyticsDataClientImpl.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/implementation/LogAnalyticsDataClientImpl.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/implementation/LogAnalyticsDataClientImpl.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/implementation/package-info.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/implementation/package-info.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/implementation/package-info.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/implementation/package-info.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/Column.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/Column.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/Column.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/Column.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorDetail.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorDetail.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorDetail.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorDetail.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorInfo.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorInfo.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorInfo.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorInfo.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponse.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponse.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponse.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponse.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponseException.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponseException.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponseException.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/ErrorResponseException.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/QueryBody.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/QueryBody.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/QueryBody.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/QueryBody.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/QueryResults.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/QueryResults.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/QueryResults.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/QueryResults.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/Table.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/Table.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/Table.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/Table.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/package-info.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/package-info.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/models/package-info.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/models/package-info.java diff --git a/loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/package-info.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/package-info.java similarity index 100% rename from loganalytics/data-plane/src/main/java/com/microsoft/azure/loganalytics/package-info.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/main/java/com/microsoft/azure/loganalytics/package-info.java diff --git a/loganalytics/data-plane/src/test/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClientTests.java b/sdk/loganalytics/microsoft-azure-loganalytics/src/test/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClientTests.java similarity index 100% rename from loganalytics/data-plane/src/test/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClientTests.java rename to sdk/loganalytics/microsoft-azure-loganalytics/src/test/java/com/microsoft/azure/loganalytics/LogAnalyticsDataClientTests.java diff --git a/sdk/loganalytics/pom.service.xml b/sdk/loganalytics/pom.service.xml new file mode 100644 index 0000000000000..b33477163e7d2 --- /dev/null +++ b/sdk/loganalytics/pom.service.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.azure + azure-loganalytics-service + pom + 1.0.0 + + microsoft-azure-loganalytics + + diff --git a/sdk/mediaservices/ci.yml b/sdk/mediaservices/ci.yml new file mode 100644 index 0000000000000..92324f8824980 --- /dev/null +++ b/sdk/mediaservices/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/mediaservices/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/mediaservices/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: mediaservices \ No newline at end of file diff --git a/mediaservices/data-plane/pom.xml b/sdk/mediaservices/microsoft-azure-media/pom.xml old mode 100755 new mode 100644 similarity index 96% rename from mediaservices/data-plane/pom.xml rename to sdk/mediaservices/microsoft-azure-media/pom.xml index 131d0d400eb67..128f58207f272 --- a/mediaservices/data-plane/pom.xml +++ b/sdk/mediaservices/microsoft-azure-media/pom.xml @@ -22,6 +22,14 @@ This package contains Microsoft Azure SDK for Media Services. https://github.com/Azure/azure-sdk-for-java + + com.azure + azure-data-sdk-parent + 1.0.0 + ../../../pom.data.xml + + + The Apache Software License, Version 2.0 diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobConfiguration.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobConfiguration.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobConfiguration.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobConfiguration.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobContract.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobContract.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobContract.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobContract.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobService.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobService.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/BlobService.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/BlobService.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/Exports.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobExceptionProcessor.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobExceptionProcessor.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobExceptionProcessor.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobExceptionProcessor.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobOperationRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobOperationRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobOperationRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobOperationRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/BlobRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/ContainerACLDateAdapter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/HmacSHA256Sign.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/HmacSHA256Sign.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/HmacSHA256Sign.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/HmacSHA256Sign.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/MetadataAdapter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/MetadataAdapter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/MetadataAdapter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/MetadataAdapter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyLiteFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyUtils.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyUtils.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyUtils.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/SharedKeyUtils.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/implementation/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/implementation/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AccessCondition.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AccessCondition.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AccessCondition.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AccessCondition.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/AcquireLeaseResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobProperties.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobProperties.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobProperties.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobProperties.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobServiceOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobServiceOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobServiceOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlobServiceOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlockList.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlockList.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BlockList.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BlockList.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BreakLeaseResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BreakLeaseResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/BreakLeaseResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/BreakLeaseResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CommitBlobBlocksOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CommitBlobBlocksOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CommitBlobBlocksOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CommitBlobBlocksOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/Constants.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/Constants.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/Constants.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/Constants.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ContainerACL.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ContainerACL.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ContainerACL.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ContainerACL.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CopyBlobResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobBlockOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobBlockOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobBlockOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobBlockOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobPagesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateBlobSnapshotResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateContainerOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateContainerOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateContainerOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/CreateContainerOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteBlobOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteBlobOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteBlobOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteBlobOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteContainerOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteContainerOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteContainerOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/DeleteContainerOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobMetadataResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobPropertiesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetBlobResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerACLResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerACLResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerACLResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerACLResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerPropertiesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerPropertiesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerPropertiesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetContainerPropertiesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetServicePropertiesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetServicePropertiesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/GetServicePropertiesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/GetServicePropertiesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobBlocksResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobRegionsResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListBlobsResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ListContainersResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/PageRange.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/PageRange.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/PageRange.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/PageRange.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ServiceProperties.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ServiceProperties.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/ServiceProperties.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/ServiceProperties.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobMetadataResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetBlobPropertiesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetContainerMetadataOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetContainerMetadataOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/SetContainerMetadataOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/SetContainerMetadataOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/models/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/models/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/blob/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/blob/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/EncryptionUtils.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/EncryptionUtils.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/EncryptionUtils.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/EncryptionUtils.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/Exports.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/Exports.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/Exports.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/Exports.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaConfiguration.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaContract.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaService.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaService.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/MediaService.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/MediaService.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/OperationUtils.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/OperationUtils.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/OperationUtils.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/OperationUtils.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/WritableBlobContainerContract.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdAccessToken.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdAccessToken.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdAccessToken.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdAccessToken.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientSymmetricKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientSymmetricKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientSymmetricKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientSymmetricKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientUsernamePassword.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientUsernamePassword.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientUsernamePassword.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdClientUsernamePassword.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentialType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentialType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentialType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentialType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentials.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentials.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentials.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenCredentials.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenFactory.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenFactory.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenFactory.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenFactory.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenProvider.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenProvider.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenProvider.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureAdTokenProvider.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironment.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironment.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironment.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironment.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironmentConstants.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironmentConstants.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironmentConstants.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironmentConstants.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironments.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironments.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironments.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/AzureEnvironments.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/TokenProvider.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/TokenProvider.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/TokenProvider.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/TokenProvider.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/authentication/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/authentication/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultActionOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultActionOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultActionOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultActionOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultDeleteOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultDeleteOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultDeleteOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultDeleteOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityActionOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityActionOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityActionOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityActionOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityTypeActionOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityTypeActionOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityTypeActionOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultEntityTypeActionOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultGetOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultGetOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultGetOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultGetOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultListOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultListOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultListOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/DefaultListOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionBodyParameterMapper.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionBodyParameterMapper.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionBodyParameterMapper.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionBodyParameterMapper.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityActionOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityBatchOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityBatchOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityBatchOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityBatchOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityContract.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityContract.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityContract.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityContract.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityCreateOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityCreateOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityCreateOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityCreateOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityDeleteOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityDeleteOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityDeleteOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityDeleteOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityGetOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityGetOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityGetOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityGetOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityLinkOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityLinkOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityLinkOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityLinkOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityListOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityListOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityListOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityListOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationBase.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationBase.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationBase.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResultBase.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResultBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResultBase.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityOperationSingleResultBase.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityProxyData.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityProxyData.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityProxyData.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityProxyData.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityTypeActionOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityTypeActionOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityTypeActionOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityTypeActionOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUnlinkOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUnlinkOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUnlinkOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUnlinkOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUpdateOperation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUpdateOperation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUpdateOperation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityUpdateOperation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityWithOperationIdentifier.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityWithOperationIdentifier.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityWithOperationIdentifier.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/EntityWithOperationIdentifier.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/entityoperations/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ActiveToken.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ActiveToken.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ActiveToken.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ActiveToken.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipart.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipart.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipart.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipart.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipartBodyWritter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipartBodyWritter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipartBodyWritter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/BatchMimeMultipartBodyWritter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperations.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperations.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperations.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperations.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobContainerWriter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaBlobRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaContentProvider.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaContentProvider.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaContentProvider.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaContentProvider.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaExceptionProcessor.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/MediaRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/OAuthFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/OAuthFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/OAuthFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/OAuthFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomMarshaller.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomUnmarshaller.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomUnmarshaller.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomUnmarshaller.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataAtomUnmarshaller.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataDateAdapter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataDateAdapter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataDateAdapter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataDateAdapter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntity.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntity.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntity.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntity.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityCollectionProvider.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityCollectionProvider.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityCollectionProvider.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityCollectionProvider.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityProvider.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityProvider.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityProvider.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ODataEntityProvider.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/RedirectFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/RedirectFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/RedirectFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/RedirectFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManager.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManager.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManager.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManager.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/SetBoundaryMultipartDataSource.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/SetBoundaryMultipartDataSource.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/SetBoundaryMultipartDataSource.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/SetBoundaryMultipartDataSource.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/StatusLine.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/StatusLine.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/StatusLine.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/StatusLine.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/VersionHeadersFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/VersionHeadersFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/VersionHeadersFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/VersionHeadersFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/CategoryType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/CategoryType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/CategoryType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/CategoryType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ContentType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ContentType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ContentType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ContentType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/DateTimeType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/DateTimeType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/DateTimeType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/DateTimeType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/EntryType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/EntryType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/EntryType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/EntryType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/FeedType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/FeedType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/FeedType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/FeedType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/GeneratorType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/GeneratorType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/GeneratorType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/GeneratorType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IconType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IconType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IconType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IconType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IdType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IdType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IdType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/IdType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LinkType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LinkType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LinkType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LinkType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LogoType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LogoType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LogoType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/LogoType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ObjectFactory.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ObjectFactory.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ObjectFactory.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/ObjectFactory.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/PersonType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/PersonType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/PersonType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/PersonType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/SourceType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/SourceType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/SourceType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/SourceType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/TextType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/TextType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/TextType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/TextType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/UriType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/UriType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/UriType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/UriType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/atom/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AccessPolicyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiAccessControlType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiAccessControlType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiAccessControlType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiAccessControlType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiSignatureHeaderAuthenticationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiSignatureHeaderAuthenticationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiSignatureHeaderAuthenticationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AkamaiSignatureHeaderAuthenticationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetDeliveryPolicyRestType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetDeliveryPolicyRestType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetDeliveryPolicyRestType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetDeliveryPolicyRestType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetFileType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetFileType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetFileType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetFileType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/AssetType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ChannelType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ChannelType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ChannelType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ChannelType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/Constants.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/Constants.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/Constants.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/Constants.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyOptionType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyOptionType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyOptionType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyOptionType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyRestrictionType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyRestrictionType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyRestrictionType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyRestrictionType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyAuthorizationPolicyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyRestType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyRestType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyRestType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ContentKeyRestType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/CrossSiteAccessPoliciesType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/CrossSiteAccessPoliciesType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/CrossSiteAccessPoliciesType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/CrossSiteAccessPoliciesType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/EncodingReservedUnitRestType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/EncodingReservedUnitRestType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/EncodingReservedUnitRestType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/EncodingReservedUnitRestType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorDetailType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorDetailType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorDetailType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorDetailType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ErrorType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPAccessControlType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPAccessControlType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPAccessControlType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPAccessControlType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPRangeType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPRangeType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPRangeType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/IPRangeType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobNotificationSubscriptionType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobNotificationSubscriptionType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobNotificationSubscriptionType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobNotificationSubscriptionType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/JobType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/LocatorRestType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/LocatorRestType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/LocatorRestType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/LocatorRestType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaProcessorType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaProcessorType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaProcessorType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaProcessorType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaServiceDTO.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaServiceDTO.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaServiceDTO.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaServiceDTO.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaUriType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaUriType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaUriType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/MediaUriType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/NotificationEndPointType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/NotificationEndPointType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/NotificationEndPointType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/NotificationEndPointType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ODataActionType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ODataActionType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ODataActionType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ODataActionType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ObjectFactory.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/OperationType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/OperationType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/OperationType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/OperationType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProgramType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProgramType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProgramType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProgramType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyIdType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyIdType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyIdType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyIdType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyRestType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyRestType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyRestType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/ProtectionKeyRestType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/RebindContentKeyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/RebindContentKeyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/RebindContentKeyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/RebindContentKeyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StorageAccountType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StorageAccountType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StorageAccountType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StorageAccountType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointAccessControlType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointAccessControlType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointAccessControlType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointAccessControlType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointCacheControlType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointCacheControlType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointCacheControlType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointCacheControlType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/StreamingEndpointType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskHistoricalEventType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/TaskType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/content/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/FairPlayConfiguration.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/FairPlayConfiguration.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/FairPlayConfiguration.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/FairPlayConfiguration.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/fairplay/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestriction.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestriction.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestriction.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestriction.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromHeader.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromHeader.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromHeader.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromHeader.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromKeyIdentifier.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromKeyIdentifier.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromKeyIdentifier.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ContentEncryptionKeyFromKeyIdentifier.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ErrorMessages.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ErrorMessages.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ErrorMessages.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ErrorMessages.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestriction.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestriction.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestriction.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestriction.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializer.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializer.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializer.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializer.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseResponseTemplate.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseResponseTemplate.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseResponseTemplate.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseResponseTemplate.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTemplate.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTemplate.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTemplate.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTemplate.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRight.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRight.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRight.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRight.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestriction.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestriction.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestriction.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestriction.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOption.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOption.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOption.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOption.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/AsymmetricTokenVerificationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/AsymmetricTokenVerificationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/AsymmetricTokenVerificationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/AsymmetricTokenVerificationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/ErrorMessages.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/ErrorMessages.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/ErrorMessages.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/ErrorMessages.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/OpenIdConnectDiscoveryDocument.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/OpenIdConnectDiscoveryDocument.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/OpenIdConnectDiscoveryDocument.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/OpenIdConnectDiscoveryDocument.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaim.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaim.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaim.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaim.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplate.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplate.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplate.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplate.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializer.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializer.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializer.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializer.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenVerificationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenVerificationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenVerificationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenVerificationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/AllowedTrackTypes.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/AllowedTrackTypes.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/AllowedTrackTypes.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/AllowedTrackTypes.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/ContentKeySpecs.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/ContentKeySpecs.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/ContentKeySpecs.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/ContentKeySpecs.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/Hdcp.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/Hdcp.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/Hdcp.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/Hdcp.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/RequiredOutputProtection.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/RequiredOutputProtection.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/RequiredOutputProtection.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/RequiredOutputProtection.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessage.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessage.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessage.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessage.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/package-info.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermission.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermission.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermission.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermission.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Asset.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Asset.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Asset.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Asset.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyConfigurationKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyConfigurationKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyConfigurationKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyConfigurationKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryProtocol.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryProtocol.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryProtocol.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryProtocol.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFile.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFile.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFile.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFile.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFileInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFileInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFileInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetFileInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetOption.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetOption.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetOption.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetOption.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/AssetState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/AssetState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOption.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOption.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOption.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOption.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOptionInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOptionInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOptionInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyOptionInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyRestriction.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyRestriction.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyRestriction.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyAuthorizationPolicyRestriction.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyDeliveryType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyDeliveryType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyDeliveryType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyDeliveryType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ContentKeyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnit.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnit.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnit.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnit.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EncodingReservedUnitType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EndPointType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EndPointType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/EndPointType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/EndPointType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ErrorDetail.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ErrorDetail.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ErrorDetail.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ErrorDetail.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Ipv4.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Ipv4.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Ipv4.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Ipv4.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Job.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Job.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Job.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Job.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscription.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscription.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscription.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscription.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscriptionListFactory.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscriptionListFactory.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscriptionListFactory.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobNotificationSubscriptionListFactory.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/JobState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/JobState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LinkInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LinkInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LinkInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LinkInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ListResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ListResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ListResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ListResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Locator.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Locator.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Locator.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Locator.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/LocatorType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessor.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessor.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessor.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessor.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPoint.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPoint.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPoint.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPoint.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Operation.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Operation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Operation.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Operation.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/OperationInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/OperationInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/OperationInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/OperationInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/OperationState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/OperationState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/OperationState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/OperationState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKey.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKey.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKey.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKey.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyType.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyType.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyType.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyType.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccountInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccountInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccountInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccountInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccounts.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccounts.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccounts.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StorageAccounts.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpoint.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpoint.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpoint.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpoint.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/StreamingEndpointState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TargetJobState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TargetJobState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TargetJobState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TargetJobState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Task.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Task.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/Task.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/Task.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskHistoricalEvent.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskInfo.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskOption.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskOption.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskOption.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskOption.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskState.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskState.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/TaskState.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/TaskState.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/models/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/models/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/media/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/media/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/Exports.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/Exports.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/Exports.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/Exports.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueConfiguration.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueContract.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/QueueService.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueExceptionProcessor.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueExceptionProcessor.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueExceptionProcessor.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueExceptionProcessor.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueMessage.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueMessage.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueMessage.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueMessage.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/QueueRestProxy.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyLiteFilter.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyLiteFilter.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyLiteFilter.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/SharedKeyLiteFilter.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/implementation/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/implementation/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateMessageOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/CreateQueueOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/GetQueueMetadataResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/GetServicePropertiesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListMessagesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ListQueuesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/PeekMessagesResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/QueueServiceOptions.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/ServiceProperties.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/UpdateMessageResult.java diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/models/package.html diff --git a/mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/package.html b/sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/package.html old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/java/com/microsoft/windowsazure/services/queue/package.html rename to sdk/mediaservices/microsoft-azure-media/src/main/java/com/microsoft/windowsazure/services/queue/package.html diff --git a/mediaservices/data-plane/src/main/resources/META-INF/services/com.microsoft.windowsazure.core.Builder$Exports b/sdk/mediaservices/microsoft-azure-media/src/main/resources/META-INF/services/com.microsoft.windowsazure.core.Builder$Exports old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/main/resources/META-INF/services/com.microsoft.windowsazure.core.Builder$Exports rename to sdk/mediaservices/microsoft-azure-media/src/main/resources/META-INF/services/com.microsoft.windowsazure.core.Builder$Exports diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/media/authentication/AzureAdTokenProviderTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/media/authentication/AzureAdTokenProviderTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/media/authentication/AzureAdTokenProviderTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/media/authentication/AzureAdTokenProviderTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/media/authentication/package-info.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/media/authentication/package-info.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/media/authentication/package-info.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/media/authentication/package-info.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/blob/BlobServiceIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/blob/BlobServiceIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/blob/BlobServiceIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/blob/BlobServiceIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/blob/IntegrationTestBase.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/blob/IntegrationTestBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/blob/IntegrationTestBase.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/blob/IntegrationTestBase.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AccessPolicyIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AssetFileIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AssetFileIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AssetFileIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AssetFileIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AssetIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AssetIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/AssetIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/AssetIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ContentKeyIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ContentKeyIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ContentKeyIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ContentKeyIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncodingReservedUnitTypeIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncodingReservedUnitTypeIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncodingReservedUnitTypeIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncodingReservedUnitTypeIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncryptionHelper.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncryptionHelper.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncryptionHelper.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncryptionHelper.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EncryptionIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EntityProxyTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EntityProxyTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/EntityProxyTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/EntityProxyTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ExportsTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ExportsTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ExportsTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ExportsTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/IntegrationTestBase.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/JobIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/LocatorIntegrationTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/LocatorIntegrationTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/LocatorIntegrationTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/LocatorIntegrationTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/MediaProcessorIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/NotificationEndPointIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/NotificationEndPointIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/NotificationEndPointIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/NotificationEndPointIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ProtectionKeyIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ProtectionKeyIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ProtectionKeyIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ProtectionKeyIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ServiceExceptionMatcher.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ServiceExceptionMatcher.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/ServiceExceptionMatcher.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/ServiceExceptionMatcher.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/StorageAccountsTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/StorageAccountsTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/StorageAccountsTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/StorageAccountsTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/StreamingEndopointIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/StreamingEndopointIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/StreamingEndopointIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/StreamingEndopointIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/TaskIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/TaskIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/TaskIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/TaskIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/UploadingIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyOptionInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyRestrictionTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyRestrictionTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyRestrictionTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/contentprotection/ContentKeyAuthorizationPolicyRestrictionTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/LinkRetrievalTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/LinkRetrievalTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/LinkRetrievalTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/LinkRetrievalTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperationsTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperationsTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperationsTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/MediaBatchOperationsTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataDateParsingTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataDateParsingTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataDateParsingTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataDateParsingTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationFromJerseyTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ODataSerializationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/RedirectionFilterTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/RedirectionFilterTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/RedirectionFilterTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/RedirectionFilterTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManagerTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManagerTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManagerTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/ResourceLocationManagerTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilterTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilterTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilterTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/SASTokenFilterTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/StatusLineTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/StatusLineTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/StatusLineTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/StatusLineTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestrictionTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestrictionTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestrictionTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/AgcAndColorStripeRestrictionTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestrictionTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestrictionTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestrictionTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ExplicitAnalogTelevisionRestrictionTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializerTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializerTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializerTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/MediaServicesLicenseTemplateSerializerTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKeyTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKeyTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKeyTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyContentKeyTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTypeTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTypeTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTypeTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyLicenseTypeTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRightTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRightTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRightTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/PlayReadyPlayRightTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestrictionTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestrictionTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestrictionTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/ScmsRestrictionTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOptionTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOptionTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOptionTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/playreadylicense/UnknownOutputPassingOptionTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKeyTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKeyTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKeyTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/SymmetricVerificationKeyTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaimTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaimTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaimTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenClaimTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializerTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializerTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializerTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenRestrictionTemplateSerializerTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenTypeTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenTypeTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenTypeTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/TokenTypeTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKeyTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKeyTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKeyTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/tokenrestriction/X509CertTokenVerificationKeyTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessageSerializerTests.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessageSerializerTests.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessageSerializerTests.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/implementation/templates/widevine/WidevineMessageSerializerTests.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermissionTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermissionTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermissionTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AccessPolicyPermissionTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetDeliveryPolicyEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetFileInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/AssetInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/AssetInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ChannelEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ChannelEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ChannelEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ChannelEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ContentKeyInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/GenericListResultTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/GenericListResultTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/GenericListResultTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/GenericListResultTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/JobEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/JobEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/JobEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/JobEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/JobInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/JobInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/JobInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/JobInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/LocatorInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/MediaProcessorInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/NotificationEndPointInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/ProtectionKeyEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/TaskEntityTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/TaskEntityTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/TaskEntityTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/TaskEntityTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/TaskInfoTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/TaskInfoTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/media/models/TaskInfoTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/media/models/TaskInfoTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/queue/IntegrationTestBase.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/queue/IntegrationTestBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/queue/IntegrationTestBase.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/queue/IntegrationTestBase.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/queue/QueueServiceIntegrationTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/queue/QueueServiceIntegrationTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/queue/QueueServiceIntegrationTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/queue/QueueServiceIntegrationTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceScenarioTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceScenarioTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceScenarioTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceScenarioTest.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceValidation.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceValidation.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceValidation.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceValidation.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/MediaServiceWrapper.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/ScenarioTestBase.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/ScenarioTestBase.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/services/scenarios/ScenarioTestBase.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/services/scenarios/ScenarioTestBase.java diff --git a/mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java b/sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java rename to sdk/mediaservices/microsoft-azure-media/src/test/java/com/microsoft/windowsazure/utils/ServiceExceptionFactoryTest.java diff --git a/mediaservices/data-plane/src/test/resources/META-INF/com.microsoft.windowsazure.properties b/sdk/mediaservices/microsoft-azure-media/src/test/resources/META-INF/com.microsoft.windowsazure.properties old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/META-INF/com.microsoft.windowsazure.properties rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/META-INF/com.microsoft.windowsazure.properties diff --git a/mediaservices/data-plane/src/test/resources/certificate/server.crt b/sdk/mediaservices/microsoft-azure-media/src/test/resources/certificate/server.crt old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/certificate/server.crt rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/certificate/server.crt diff --git a/mediaservices/data-plane/src/test/resources/certificate/server.der b/sdk/mediaservices/microsoft-azure-media/src/test/resources/certificate/server.der old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/certificate/server.der rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/certificate/server.der diff --git a/mediaservices/data-plane/src/test/resources/media/MPEG4-H264.mp4 b/sdk/mediaservices/microsoft-azure-media/src/test/resources/media/MPEG4-H264.mp4 old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/media/MPEG4-H264.mp4 rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/media/MPEG4-H264.mp4 diff --git a/mediaservices/data-plane/src/test/resources/schemas/PlayReadyLicenseResponseTemplate.xsd b/sdk/mediaservices/microsoft-azure-media/src/test/resources/schemas/PlayReadyLicenseResponseTemplate.xsd old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/schemas/PlayReadyLicenseResponseTemplate.xsd rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/schemas/PlayReadyLicenseResponseTemplate.xsd diff --git a/mediaservices/data-plane/src/test/resources/schemas/TokenRestrictionTemplate.xsd b/sdk/mediaservices/microsoft-azure-media/src/test/resources/schemas/TokenRestrictionTemplate.xsd old mode 100755 new mode 100644 similarity index 100% rename from mediaservices/data-plane/src/test/resources/schemas/TokenRestrictionTemplate.xsd rename to sdk/mediaservices/microsoft-azure-media/src/test/resources/schemas/TokenRestrictionTemplate.xsd diff --git a/sdk/mediaservices/pom.service.xml b/sdk/mediaservices/pom.service.xml new file mode 100644 index 0000000000000..bd3c7433293a5 --- /dev/null +++ b/sdk/mediaservices/pom.service.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.azure + azure-mediaservices-service + pom + 1.0.0 + + microsoft-azure-media + + diff --git a/sdk/servicebus/pom.xml b/sdk/servicebus/pom.xml index a67dbb9efd79d..bfc3a7f2daed1 100644 --- a/sdk/servicebus/pom.xml +++ b/sdk/servicebus/pom.xml @@ -16,7 +16,7 @@ com.azure azure-data-sdk-parent - 1.0.0 + 1.1.0 ../../pom.data.xml diff --git a/sdk/template/azure-sdk-template/pom.xml b/sdk/template/azure-sdk-template/pom.xml index 576735b26541e..3c5ff41f6fc2a 100644 --- a/sdk/template/azure-sdk-template/pom.xml +++ b/sdk/template/azure-sdk-template/pom.xml @@ -5,7 +5,7 @@ com.azure azure-client-sdk-parent - 1.0.0 + 1.1.0 ../../../pom.client.xml diff --git a/sdk/template/ci.yml b/sdk/template/ci.yml new file mode 100644 index 0000000000000..a02392a0674f8 --- /dev/null +++ b/sdk/template/ci.yml @@ -0,0 +1,23 @@ +# DO NOT EDIT THIS FILE +# This file is generated automatically and any changes will be lost. + +trigger: + branches: + include: + - master + paths: + include: + - sdk/template/ + +pr: + branches: + include: + - master + paths: + include: + - sdk/template/ + +jobs: + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + ServiceDirectory: template \ No newline at end of file diff --git a/sdk/template/pom.service.xml b/sdk/template/pom.service.xml new file mode 100644 index 0000000000000..f8b2c05a9ef67 --- /dev/null +++ b/sdk/template/pom.service.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + com.azure + azure-template-service + pom + 1.0.0 + + azure-sdk-template + + diff --git a/tracing/README.md b/sdk/tracing/README.md similarity index 100% rename from tracing/README.md rename to sdk/tracing/README.md diff --git a/tracing/tracing-opentelemetry/README.md b/sdk/tracing/azure-tracing-opentelemetry/README.md similarity index 100% rename from tracing/tracing-opentelemetry/README.md rename to sdk/tracing/azure-tracing-opentelemetry/README.md diff --git a/tracing/tracing-opentelemetry/pom.xml b/sdk/tracing/azure-tracing-opentelemetry/pom.xml similarity index 100% rename from tracing/tracing-opentelemetry/pom.xml rename to sdk/tracing/azure-tracing-opentelemetry/pom.xml diff --git a/tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/HttpTraceUtil.java b/sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/HttpTraceUtil.java similarity index 100% rename from tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/HttpTraceUtil.java rename to sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/HttpTraceUtil.java diff --git a/tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryHttpPolicy.java b/sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryHttpPolicy.java similarity index 100% rename from tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryHttpPolicy.java rename to sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryHttpPolicy.java diff --git a/tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryTracer.java b/sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryTracer.java similarity index 100% rename from tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryTracer.java rename to sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/OpenTelemetryTracer.java diff --git a/tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/package-info.java b/sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/package-info.java similarity index 100% rename from tracing/tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/package-info.java rename to sdk/tracing/azure-tracing-opentelemetry/src/main/java/com/azure/tracing/opentelemetry/package-info.java diff --git a/tracing/tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.http.policy.spi.AfterRetryPolicyProvider b/sdk/tracing/azure-tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.http.policy.spi.AfterRetryPolicyProvider similarity index 100% rename from tracing/tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.http.policy.spi.AfterRetryPolicyProvider rename to sdk/tracing/azure-tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.http.policy.spi.AfterRetryPolicyProvider diff --git a/tracing/tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.tracing.Tracer b/sdk/tracing/azure-tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.tracing.Tracer similarity index 100% rename from tracing/tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.tracing.Tracer rename to sdk/tracing/azure-tracing-opentelemetry/src/main/resources/META-INF/services/com.azure.core.implementation.tracing.Tracer diff --git a/tracing/pom.xml b/sdk/tracing/pom.xml similarity index 92% rename from tracing/pom.xml rename to sdk/tracing/pom.xml index 822fab5e83b78..2850e2f2a63b6 100644 --- a/tracing/pom.xml +++ b/sdk/tracing/pom.xml @@ -8,8 +8,8 @@ com.azure azure-client-sdk-parent - 1.0.0 - ../pom.client.xml + 1.1.0 + ../../pom.client.xml com.azure @@ -53,6 +53,6 @@
    - tracing-opentelemetry + azure-tracing-opentelemetry diff --git a/search/resource-manager/v2015_02_28/pom.xml b/search/resource-manager/v2015_02_28/pom.xml index c09be0fa76d5a..19f7e0c74beeb 100644 --- a/search/resource-manager/v2015_02_28/pom.xml +++ b/search/resource-manager/v2015_02_28/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/servicebus/resource-manager/v2015_08_01/pom.xml b/servicebus/resource-manager/v2015_08_01/pom.xml index 77d52c2ea066f..6c4421ae3e797 100644 --- a/servicebus/resource-manager/v2015_08_01/pom.xml +++ b/servicebus/resource-manager/v2015_08_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/servicebus/resource-manager/v2018_01_01_preview/pom.xml b/servicebus/resource-manager/v2018_01_01_preview/pom.xml index 5fd8887577830..68c64ab067a81 100644 --- a/servicebus/resource-manager/v2018_01_01_preview/pom.xml +++ b/servicebus/resource-manager/v2018_01_01_preview/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/servicefabric/resource-manager/v2018_02_01/pom.xml b/servicefabric/resource-manager/v2018_02_01/pom.xml index f711362b446c0..a8bbdaaca20e3 100644 --- a/servicefabric/resource-manager/v2018_02_01/pom.xml +++ b/servicefabric/resource-manager/v2018_02_01/pom.xml @@ -71,6 +71,8 @@ azure-arm-client-runtime test-jar test + + 1.6.5 diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/pom.xml b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/pom.xml new file mode 100644 index 0000000000000..b1ca95bfd516b --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/pom.xml @@ -0,0 +1,135 @@ + + + 4.0.0 + com.microsoft.azure.sqlvirtualmachine.v2017_03_01_preview + + com.microsoft.azure + azure-arm-parent + 1.1.0 + ../../../pom.management.xml + + azure-mgmt-sqlvirtualmachine + 1.0.0-beta + jar + Microsoft Azure SDK for SqlVirtualMachine Management + This package contains Microsoft SqlVirtualMachine Management SDK. + https://github.com/Azure/azure-sdk-for-java + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + UTF-8 + + + + + microsoft + Microsoft + + + + + com.microsoft.azure + azure-client-runtime + + + com.microsoft.azure + azure-arm-client-runtime + + + junit + junit + test + + + com.microsoft.azure + azure-client-authentication + test + + + com.microsoft.azure + azure-mgmt-resources + test + + + com.microsoft.azure + azure-arm-client-runtime + test-jar + test + + 1.6.5 + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + 1.7 + 1.7 + + + com.microsoft.azure.management.apigeneration.LangDefinitionProcessor + + + true + true + + true + true + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 + + *.implementation.*;*.utils.*;com.microsoft.schemas._2003._10.serialization;*.blob.core.search + + + /** +
    * Copyright (c) Microsoft Corporation. All rights reserved. +
    * Licensed under the MIT License. See License.txt in the project root for +
    * license information. +
    */ + ]]> +
    +
    +
    +
    +
    +
    diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AdditionalFeaturesServerConfigurations.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AdditionalFeaturesServerConfigurations.java new file mode 100644 index 0000000000000..5bac163dcfe0a --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AdditionalFeaturesServerConfigurations.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Additional SQL Server feature settings. + */ +public class AdditionalFeaturesServerConfigurations { + /** + * Enable or disable R services (SQL 2016 onwards). + */ + @JsonProperty(value = "isRServicesEnabled") + private Boolean isRServicesEnabled; + + /** + * Get enable or disable R services (SQL 2016 onwards). + * + * @return the isRServicesEnabled value + */ + public Boolean isRServicesEnabled() { + return this.isRServicesEnabled; + } + + /** + * Set enable or disable R services (SQL 2016 onwards). + * + * @param isRServicesEnabled the isRServicesEnabled value to set + * @return the AdditionalFeaturesServerConfigurations object itself. + */ + public AdditionalFeaturesServerConfigurations withIsRServicesEnabled(Boolean isRServicesEnabled) { + this.isRServicesEnabled = isRServicesEnabled; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoBackupSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoBackupSettings.java new file mode 100644 index 0000000000000..6789a508fd0ab --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoBackupSettings.java @@ -0,0 +1,332 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Configure backups for databases in your SQL virtual machine. + */ +public class AutoBackupSettings { + /** + * Enable or disable autobackup on SQL virtual machine. + */ + @JsonProperty(value = "enable") + private Boolean enable; + + /** + * Enable or disable encryption for backup on SQL virtual machine. + */ + @JsonProperty(value = "enableEncryption") + private Boolean enableEncryption; + + /** + * Retention period of backup: 1-30 days. + */ + @JsonProperty(value = "retentionPeriod") + private Integer retentionPeriod; + + /** + * Storage account url where backup will be taken to. + */ + @JsonProperty(value = "storageAccountUrl") + private String storageAccountUrl; + + /** + * Storage account key where backup will be taken to. + */ + @JsonProperty(value = "storageAccessKey") + private String storageAccessKey; + + /** + * Password for encryption on backup. + */ + @JsonProperty(value = "password") + private String password; + + /** + * Include or exclude system databases from auto backup. + */ + @JsonProperty(value = "backupSystemDbs") + private Boolean backupSystemDbs; + + /** + * Backup schedule type. Possible values include: 'Manual', 'Automated'. + */ + @JsonProperty(value = "backupScheduleType") + private BackupScheduleType backupScheduleType; + + /** + * Frequency of full backups. In both cases, full backups begin during the + * next scheduled time window. Possible values include: 'Daily', 'Weekly'. + */ + @JsonProperty(value = "fullBackupFrequency") + private FullBackupFrequencyType fullBackupFrequency; + + /** + * Start time of a given day during which full backups can take place. 0-23 + * hours. + */ + @JsonProperty(value = "fullBackupStartTime") + private Integer fullBackupStartTime; + + /** + * Duration of the time window of a given day during which full backups can + * take place. 1-23 hours. + */ + @JsonProperty(value = "fullBackupWindowHours") + private Integer fullBackupWindowHours; + + /** + * Frequency of log backups. 5-60 minutes. + */ + @JsonProperty(value = "logBackupFrequency") + private Integer logBackupFrequency; + + /** + * Get enable or disable autobackup on SQL virtual machine. + * + * @return the enable value + */ + public Boolean enable() { + return this.enable; + } + + /** + * Set enable or disable autobackup on SQL virtual machine. + * + * @param enable the enable value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withEnable(Boolean enable) { + this.enable = enable; + return this; + } + + /** + * Get enable or disable encryption for backup on SQL virtual machine. + * + * @return the enableEncryption value + */ + public Boolean enableEncryption() { + return this.enableEncryption; + } + + /** + * Set enable or disable encryption for backup on SQL virtual machine. + * + * @param enableEncryption the enableEncryption value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withEnableEncryption(Boolean enableEncryption) { + this.enableEncryption = enableEncryption; + return this; + } + + /** + * Get retention period of backup: 1-30 days. + * + * @return the retentionPeriod value + */ + public Integer retentionPeriod() { + return this.retentionPeriod; + } + + /** + * Set retention period of backup: 1-30 days. + * + * @param retentionPeriod the retentionPeriod value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withRetentionPeriod(Integer retentionPeriod) { + this.retentionPeriod = retentionPeriod; + return this; + } + + /** + * Get storage account url where backup will be taken to. + * + * @return the storageAccountUrl value + */ + public String storageAccountUrl() { + return this.storageAccountUrl; + } + + /** + * Set storage account url where backup will be taken to. + * + * @param storageAccountUrl the storageAccountUrl value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withStorageAccountUrl(String storageAccountUrl) { + this.storageAccountUrl = storageAccountUrl; + return this; + } + + /** + * Get storage account key where backup will be taken to. + * + * @return the storageAccessKey value + */ + public String storageAccessKey() { + return this.storageAccessKey; + } + + /** + * Set storage account key where backup will be taken to. + * + * @param storageAccessKey the storageAccessKey value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withStorageAccessKey(String storageAccessKey) { + this.storageAccessKey = storageAccessKey; + return this; + } + + /** + * Get password for encryption on backup. + * + * @return the password value + */ + public String password() { + return this.password; + } + + /** + * Set password for encryption on backup. + * + * @param password the password value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withPassword(String password) { + this.password = password; + return this; + } + + /** + * Get include or exclude system databases from auto backup. + * + * @return the backupSystemDbs value + */ + public Boolean backupSystemDbs() { + return this.backupSystemDbs; + } + + /** + * Set include or exclude system databases from auto backup. + * + * @param backupSystemDbs the backupSystemDbs value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withBackupSystemDbs(Boolean backupSystemDbs) { + this.backupSystemDbs = backupSystemDbs; + return this; + } + + /** + * Get backup schedule type. Possible values include: 'Manual', 'Automated'. + * + * @return the backupScheduleType value + */ + public BackupScheduleType backupScheduleType() { + return this.backupScheduleType; + } + + /** + * Set backup schedule type. Possible values include: 'Manual', 'Automated'. + * + * @param backupScheduleType the backupScheduleType value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withBackupScheduleType(BackupScheduleType backupScheduleType) { + this.backupScheduleType = backupScheduleType; + return this; + } + + /** + * Get frequency of full backups. In both cases, full backups begin during the next scheduled time window. Possible values include: 'Daily', 'Weekly'. + * + * @return the fullBackupFrequency value + */ + public FullBackupFrequencyType fullBackupFrequency() { + return this.fullBackupFrequency; + } + + /** + * Set frequency of full backups. In both cases, full backups begin during the next scheduled time window. Possible values include: 'Daily', 'Weekly'. + * + * @param fullBackupFrequency the fullBackupFrequency value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withFullBackupFrequency(FullBackupFrequencyType fullBackupFrequency) { + this.fullBackupFrequency = fullBackupFrequency; + return this; + } + + /** + * Get start time of a given day during which full backups can take place. 0-23 hours. + * + * @return the fullBackupStartTime value + */ + public Integer fullBackupStartTime() { + return this.fullBackupStartTime; + } + + /** + * Set start time of a given day during which full backups can take place. 0-23 hours. + * + * @param fullBackupStartTime the fullBackupStartTime value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withFullBackupStartTime(Integer fullBackupStartTime) { + this.fullBackupStartTime = fullBackupStartTime; + return this; + } + + /** + * Get duration of the time window of a given day during which full backups can take place. 1-23 hours. + * + * @return the fullBackupWindowHours value + */ + public Integer fullBackupWindowHours() { + return this.fullBackupWindowHours; + } + + /** + * Set duration of the time window of a given day during which full backups can take place. 1-23 hours. + * + * @param fullBackupWindowHours the fullBackupWindowHours value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withFullBackupWindowHours(Integer fullBackupWindowHours) { + this.fullBackupWindowHours = fullBackupWindowHours; + return this; + } + + /** + * Get frequency of log backups. 5-60 minutes. + * + * @return the logBackupFrequency value + */ + public Integer logBackupFrequency() { + return this.logBackupFrequency; + } + + /** + * Set frequency of log backups. 5-60 minutes. + * + * @param logBackupFrequency the logBackupFrequency value to set + * @return the AutoBackupSettings object itself. + */ + public AutoBackupSettings withLogBackupFrequency(Integer logBackupFrequency) { + this.logBackupFrequency = logBackupFrequency; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoPatchingSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoPatchingSettings.java new file mode 100644 index 0000000000000..7192c1ba5f103 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AutoPatchingSettings.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Set a patching window during which Windows and SQL patches will be applied. + */ +public class AutoPatchingSettings { + /** + * Enable or disable autopatching on SQL virtual machine. + */ + @JsonProperty(value = "enable") + private Boolean enable; + + /** + * Day of week to apply the patch on. Possible values include: 'Monday', + * 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'. + */ + @JsonProperty(value = "dayOfWeek") + private DayOfWeek dayOfWeek; + + /** + * Hour of the day when patching is initiated. Local VM time. + */ + @JsonProperty(value = "maintenanceWindowStartingHour") + private Integer maintenanceWindowStartingHour; + + /** + * Duration of patching. + */ + @JsonProperty(value = "maintenanceWindowDuration") + private Integer maintenanceWindowDuration; + + /** + * Get enable or disable autopatching on SQL virtual machine. + * + * @return the enable value + */ + public Boolean enable() { + return this.enable; + } + + /** + * Set enable or disable autopatching on SQL virtual machine. + * + * @param enable the enable value to set + * @return the AutoPatchingSettings object itself. + */ + public AutoPatchingSettings withEnable(Boolean enable) { + this.enable = enable; + return this; + } + + /** + * Get day of week to apply the patch on. Possible values include: 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'. + * + * @return the dayOfWeek value + */ + public DayOfWeek dayOfWeek() { + return this.dayOfWeek; + } + + /** + * Set day of week to apply the patch on. Possible values include: 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'. + * + * @param dayOfWeek the dayOfWeek value to set + * @return the AutoPatchingSettings object itself. + */ + public AutoPatchingSettings withDayOfWeek(DayOfWeek dayOfWeek) { + this.dayOfWeek = dayOfWeek; + return this; + } + + /** + * Get hour of the day when patching is initiated. Local VM time. + * + * @return the maintenanceWindowStartingHour value + */ + public Integer maintenanceWindowStartingHour() { + return this.maintenanceWindowStartingHour; + } + + /** + * Set hour of the day when patching is initiated. Local VM time. + * + * @param maintenanceWindowStartingHour the maintenanceWindowStartingHour value to set + * @return the AutoPatchingSettings object itself. + */ + public AutoPatchingSettings withMaintenanceWindowStartingHour(Integer maintenanceWindowStartingHour) { + this.maintenanceWindowStartingHour = maintenanceWindowStartingHour; + return this; + } + + /** + * Get duration of patching. + * + * @return the maintenanceWindowDuration value + */ + public Integer maintenanceWindowDuration() { + return this.maintenanceWindowDuration; + } + + /** + * Set duration of patching. + * + * @param maintenanceWindowDuration the maintenanceWindowDuration value to set + * @return the AutoPatchingSettings object itself. + */ + public AutoPatchingSettings withMaintenanceWindowDuration(Integer maintenanceWindowDuration) { + this.maintenanceWindowDuration = maintenanceWindowDuration; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListener.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListener.java new file mode 100644 index 0000000000000..ab53efa1e0d77 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListener.java @@ -0,0 +1,210 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.AvailabilityGroupListenerInner; +import com.microsoft.azure.arm.model.Indexable; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineManager; +import java.util.List; + +/** + * Type representing AvailabilityGroupListener. + */ +public interface AvailabilityGroupListener extends HasInner, Indexable, Refreshable, Updatable, HasManager { + /** + * @return the availabilityGroupName value. + */ + String availabilityGroupName(); + + /** + * @return the createDefaultAvailabilityGroupIfNotExist value. + */ + Boolean createDefaultAvailabilityGroupIfNotExist(); + + /** + * @return the id value. + */ + String id(); + + /** + * @return the loadBalancerConfigurations value. + */ + List loadBalancerConfigurations(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the port value. + */ + Integer port(); + + /** + * @return the provisioningState value. + */ + String provisioningState(); + + /** + * @return the type value. + */ + String type(); + + /** + * The entirety of the AvailabilityGroupListener definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithSqlVirtualMachineGroup, DefinitionStages.WithCreate { + } + + /** + * Grouping of AvailabilityGroupListener definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a AvailabilityGroupListener definition. + */ + interface Blank extends WithSqlVirtualMachineGroup { + } + + /** + * The stage of the availabilitygrouplistener definition allowing to specify SqlVirtualMachineGroup. + */ + interface WithSqlVirtualMachineGroup { + /** + * Specifies resourceGroupName, sqlVirtualMachineGroupName. + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group + * @return the next definition stage + */ + WithCreate withExistingSqlVirtualMachineGroup(String resourceGroupName, String sqlVirtualMachineGroupName); + } + + /** + * The stage of the availabilitygrouplistener definition allowing to specify AvailabilityGroupName. + */ + interface WithAvailabilityGroupName { + /** + * Specifies availabilityGroupName. + * @param availabilityGroupName Name of the availability group + * @return the next definition stage + */ + WithCreate withAvailabilityGroupName(String availabilityGroupName); + } + + /** + * The stage of the availabilitygrouplistener definition allowing to specify CreateDefaultAvailabilityGroupIfNotExist. + */ + interface WithCreateDefaultAvailabilityGroupIfNotExist { + /** + * Specifies createDefaultAvailabilityGroupIfNotExist. + * @param createDefaultAvailabilityGroupIfNotExist Create a default availability group if it does not exist + * @return the next definition stage + */ + WithCreate withCreateDefaultAvailabilityGroupIfNotExist(Boolean createDefaultAvailabilityGroupIfNotExist); + } + + /** + * The stage of the availabilitygrouplistener definition allowing to specify LoadBalancerConfigurations. + */ + interface WithLoadBalancerConfigurations { + /** + * Specifies loadBalancerConfigurations. + * @param loadBalancerConfigurations List of load balancer configurations for an availability group listener + * @return the next definition stage + */ + WithCreate withLoadBalancerConfigurations(List loadBalancerConfigurations); + } + + /** + * The stage of the availabilitygrouplistener definition allowing to specify Port. + */ + interface WithPort { + /** + * Specifies port. + * @param port Listener port + * @return the next definition stage + */ + WithCreate withPort(Integer port); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable, DefinitionStages.WithAvailabilityGroupName, DefinitionStages.WithCreateDefaultAvailabilityGroupIfNotExist, DefinitionStages.WithLoadBalancerConfigurations, DefinitionStages.WithPort { + } + } + /** + * The template for a AvailabilityGroupListener update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, UpdateStages.WithAvailabilityGroupName, UpdateStages.WithCreateDefaultAvailabilityGroupIfNotExist, UpdateStages.WithLoadBalancerConfigurations, UpdateStages.WithPort { + } + + /** + * Grouping of AvailabilityGroupListener update stages. + */ + interface UpdateStages { + /** + * The stage of the availabilitygrouplistener update allowing to specify AvailabilityGroupName. + */ + interface WithAvailabilityGroupName { + /** + * Specifies availabilityGroupName. + * @param availabilityGroupName Name of the availability group + * @return the next update stage + */ + Update withAvailabilityGroupName(String availabilityGroupName); + } + + /** + * The stage of the availabilitygrouplistener update allowing to specify CreateDefaultAvailabilityGroupIfNotExist. + */ + interface WithCreateDefaultAvailabilityGroupIfNotExist { + /** + * Specifies createDefaultAvailabilityGroupIfNotExist. + * @param createDefaultAvailabilityGroupIfNotExist Create a default availability group if it does not exist + * @return the next update stage + */ + Update withCreateDefaultAvailabilityGroupIfNotExist(Boolean createDefaultAvailabilityGroupIfNotExist); + } + + /** + * The stage of the availabilitygrouplistener update allowing to specify LoadBalancerConfigurations. + */ + interface WithLoadBalancerConfigurations { + /** + * Specifies loadBalancerConfigurations. + * @param loadBalancerConfigurations List of load balancer configurations for an availability group listener + * @return the next update stage + */ + Update withLoadBalancerConfigurations(List loadBalancerConfigurations); + } + + /** + * The stage of the availabilitygrouplistener update allowing to specify Port. + */ + interface WithPort { + /** + * Specifies port. + * @param port Listener port + * @return the next update stage + */ + Update withPort(Integer port); + } + + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListeners.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListeners.java new file mode 100644 index 0000000000000..f381e4e983125 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/AvailabilityGroupListeners.java @@ -0,0 +1,53 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import rx.Completable; +import rx.Observable; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.AvailabilityGroupListenersInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing AvailabilityGroupListeners. + */ +public interface AvailabilityGroupListeners extends SupportsCreating, HasInner { + /** + * Gets an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable getAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName); + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listByGroupAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName); + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Completable deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName); + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/BackupScheduleType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/BackupScheduleType.java new file mode 100644 index 0000000000000..5b82c5db17fe2 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/BackupScheduleType.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for BackupScheduleType. + */ +public final class BackupScheduleType extends ExpandableStringEnum { + /** Static value Manual for BackupScheduleType. */ + public static final BackupScheduleType MANUAL = fromString("Manual"); + + /** Static value Automated for BackupScheduleType. */ + public static final BackupScheduleType AUTOMATED = fromString("Automated"); + + /** + * Creates or finds a BackupScheduleType from its string representation. + * @param name a name to look for + * @return the corresponding BackupScheduleType + */ + @JsonCreator + public static BackupScheduleType fromString(String name) { + return fromString(name, BackupScheduleType.class); + } + + /** + * @return known BackupScheduleType values + */ + public static Collection values() { + return values(BackupScheduleType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterConfiguration.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterConfiguration.java new file mode 100644 index 0000000000000..4da03ae83b67c --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterConfiguration.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for ClusterConfiguration. + */ +public final class ClusterConfiguration extends ExpandableStringEnum { + /** Static value Domainful for ClusterConfiguration. */ + public static final ClusterConfiguration DOMAINFUL = fromString("Domainful"); + + /** + * Creates or finds a ClusterConfiguration from its string representation. + * @param name a name to look for + * @return the corresponding ClusterConfiguration + */ + @JsonCreator + public static ClusterConfiguration fromString(String name) { + return fromString(name, ClusterConfiguration.class); + } + + /** + * @return known ClusterConfiguration values + */ + public static Collection values() { + return values(ClusterConfiguration.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterManagerType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterManagerType.java new file mode 100644 index 0000000000000..5ff3a8174728c --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ClusterManagerType.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for ClusterManagerType. + */ +public final class ClusterManagerType extends ExpandableStringEnum { + /** Static value WSFC for ClusterManagerType. */ + public static final ClusterManagerType WSFC = fromString("WSFC"); + + /** + * Creates or finds a ClusterManagerType from its string representation. + * @param name a name to look for + * @return the corresponding ClusterManagerType + */ + @JsonCreator + public static ClusterManagerType fromString(String name) { + return fromString(name, ClusterManagerType.class); + } + + /** + * @return known ClusterManagerType values + */ + public static Collection values() { + return values(ClusterManagerType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ConnectivityType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ConnectivityType.java new file mode 100644 index 0000000000000..e3bb4ae04b79b --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ConnectivityType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for ConnectivityType. + */ +public final class ConnectivityType extends ExpandableStringEnum { + /** Static value LOCAL for ConnectivityType. */ + public static final ConnectivityType LOCAL = fromString("LOCAL"); + + /** Static value PRIVATE for ConnectivityType. */ + public static final ConnectivityType PRIVATE = fromString("PRIVATE"); + + /** Static value PUBLIC for ConnectivityType. */ + public static final ConnectivityType PUBLIC = fromString("PUBLIC"); + + /** + * Creates or finds a ConnectivityType from its string representation. + * @param name a name to look for + * @return the corresponding ConnectivityType + */ + @JsonCreator + public static ConnectivityType fromString(String name) { + return fromString(name, ConnectivityType.class); + } + + /** + * @return known ConnectivityType values + */ + public static Collection values() { + return values(ConnectivityType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DayOfWeek.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DayOfWeek.java new file mode 100644 index 0000000000000..38ef71f2d5e54 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DayOfWeek.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for DayOfWeek. + */ +public enum DayOfWeek { + /** Enum value Monday. */ + MONDAY("Monday"), + + /** Enum value Tuesday. */ + TUESDAY("Tuesday"), + + /** Enum value Wednesday. */ + WEDNESDAY("Wednesday"), + + /** Enum value Thursday. */ + THURSDAY("Thursday"), + + /** Enum value Friday. */ + FRIDAY("Friday"), + + /** Enum value Saturday. */ + SATURDAY("Saturday"), + + /** Enum value Sunday. */ + SUNDAY("Sunday"); + + /** The actual serialized value for a DayOfWeek instance. */ + private String value; + + DayOfWeek(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a DayOfWeek instance. + * + * @param value the serialized value to parse. + * @return the parsed DayOfWeek object, or null if unable to parse. + */ + @JsonCreator + public static DayOfWeek fromString(String value) { + DayOfWeek[] items = DayOfWeek.values(); + for (DayOfWeek item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DiskConfigurationType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DiskConfigurationType.java new file mode 100644 index 0000000000000..49e844b68c8dd --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/DiskConfigurationType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for DiskConfigurationType. + */ +public final class DiskConfigurationType extends ExpandableStringEnum { + /** Static value NEW for DiskConfigurationType. */ + public static final DiskConfigurationType NEW = fromString("NEW"); + + /** Static value EXTEND for DiskConfigurationType. */ + public static final DiskConfigurationType EXTEND = fromString("EXTEND"); + + /** Static value ADD for DiskConfigurationType. */ + public static final DiskConfigurationType ADD = fromString("ADD"); + + /** + * Creates or finds a DiskConfigurationType from its string representation. + * @param name a name to look for + * @return the corresponding DiskConfigurationType + */ + @JsonCreator + public static DiskConfigurationType fromString(String name) { + return fromString(name, DiskConfigurationType.class); + } + + /** + * @return known DiskConfigurationType values + */ + public static Collection values() { + return values(DiskConfigurationType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/FullBackupFrequencyType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/FullBackupFrequencyType.java new file mode 100644 index 0000000000000..b6165e6da9ac1 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/FullBackupFrequencyType.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for FullBackupFrequencyType. + */ +public final class FullBackupFrequencyType extends ExpandableStringEnum { + /** Static value Daily for FullBackupFrequencyType. */ + public static final FullBackupFrequencyType DAILY = fromString("Daily"); + + /** Static value Weekly for FullBackupFrequencyType. */ + public static final FullBackupFrequencyType WEEKLY = fromString("Weekly"); + + /** + * Creates or finds a FullBackupFrequencyType from its string representation. + * @param name a name to look for + * @return the corresponding FullBackupFrequencyType + */ + @JsonCreator + public static FullBackupFrequencyType fromString(String name) { + return fromString(name, FullBackupFrequencyType.class); + } + + /** + * @return known FullBackupFrequencyType values + */ + public static Collection values() { + return values(FullBackupFrequencyType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/IdentityType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/IdentityType.java new file mode 100644 index 0000000000000..3fcf662038824 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/IdentityType.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for IdentityType. + */ +public final class IdentityType extends ExpandableStringEnum { + /** Static value SystemAssigned for IdentityType. */ + public static final IdentityType SYSTEM_ASSIGNED = fromString("SystemAssigned"); + + /** + * Creates or finds a IdentityType from its string representation. + * @param name a name to look for + * @return the corresponding IdentityType + */ + @JsonCreator + public static IdentityType fromString(String name) { + return fromString(name, IdentityType.class); + } + + /** + * @return known IdentityType values + */ + public static Collection values() { + return values(IdentityType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/KeyVaultCredentialSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/KeyVaultCredentialSettings.java new file mode 100644 index 0000000000000..b5263dbfcb52e --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/KeyVaultCredentialSettings.java @@ -0,0 +1,148 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Configure your SQL virtual machine to be able to connect to the Azure Key + * Vault service. + */ +public class KeyVaultCredentialSettings { + /** + * Enable or disable key vault credential setting. + */ + @JsonProperty(value = "enable") + private Boolean enable; + + /** + * Credential name. + */ + @JsonProperty(value = "credentialName") + private String credentialName; + + /** + * Azure Key Vault url. + */ + @JsonProperty(value = "azureKeyVaultUrl") + private String azureKeyVaultUrl; + + /** + * Service principal name to access key vault. + */ + @JsonProperty(value = "servicePrincipalName") + private String servicePrincipalName; + + /** + * Service principal name secret to access key vault. + */ + @JsonProperty(value = "servicePrincipalSecret") + private String servicePrincipalSecret; + + /** + * Get enable or disable key vault credential setting. + * + * @return the enable value + */ + public Boolean enable() { + return this.enable; + } + + /** + * Set enable or disable key vault credential setting. + * + * @param enable the enable value to set + * @return the KeyVaultCredentialSettings object itself. + */ + public KeyVaultCredentialSettings withEnable(Boolean enable) { + this.enable = enable; + return this; + } + + /** + * Get credential name. + * + * @return the credentialName value + */ + public String credentialName() { + return this.credentialName; + } + + /** + * Set credential name. + * + * @param credentialName the credentialName value to set + * @return the KeyVaultCredentialSettings object itself. + */ + public KeyVaultCredentialSettings withCredentialName(String credentialName) { + this.credentialName = credentialName; + return this; + } + + /** + * Get azure Key Vault url. + * + * @return the azureKeyVaultUrl value + */ + public String azureKeyVaultUrl() { + return this.azureKeyVaultUrl; + } + + /** + * Set azure Key Vault url. + * + * @param azureKeyVaultUrl the azureKeyVaultUrl value to set + * @return the KeyVaultCredentialSettings object itself. + */ + public KeyVaultCredentialSettings withAzureKeyVaultUrl(String azureKeyVaultUrl) { + this.azureKeyVaultUrl = azureKeyVaultUrl; + return this; + } + + /** + * Get service principal name to access key vault. + * + * @return the servicePrincipalName value + */ + public String servicePrincipalName() { + return this.servicePrincipalName; + } + + /** + * Set service principal name to access key vault. + * + * @param servicePrincipalName the servicePrincipalName value to set + * @return the KeyVaultCredentialSettings object itself. + */ + public KeyVaultCredentialSettings withServicePrincipalName(String servicePrincipalName) { + this.servicePrincipalName = servicePrincipalName; + return this; + } + + /** + * Get service principal name secret to access key vault. + * + * @return the servicePrincipalSecret value + */ + public String servicePrincipalSecret() { + return this.servicePrincipalSecret; + } + + /** + * Set service principal name secret to access key vault. + * + * @param servicePrincipalSecret the servicePrincipalSecret value to set + * @return the KeyVaultCredentialSettings object itself. + */ + public KeyVaultCredentialSettings withServicePrincipalSecret(String servicePrincipalSecret) { + this.servicePrincipalSecret = servicePrincipalSecret; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/LoadBalancerConfiguration.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/LoadBalancerConfiguration.java new file mode 100644 index 0000000000000..cf0aeb67f0639 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/LoadBalancerConfiguration.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.List; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A load balancer configuration for an availability group listener. + */ +public class LoadBalancerConfiguration { + /** + * Private IP address. + */ + @JsonProperty(value = "privateIpAddress") + private PrivateIPAddress privateIpAddress; + + /** + * Resource id of the public IP. + */ + @JsonProperty(value = "publicIpAddressResourceId") + private String publicIpAddressResourceId; + + /** + * Resource id of the load balancer. + */ + @JsonProperty(value = "loadBalancerResourceId") + private String loadBalancerResourceId; + + /** + * Probe port. + */ + @JsonProperty(value = "probePort") + private Integer probePort; + + /** + * List of the SQL virtual machine instance resource id's that are enrolled + * into the availability group listener. + */ + @JsonProperty(value = "sqlVirtualMachineInstances") + private List sqlVirtualMachineInstances; + + /** + * Get private IP address. + * + * @return the privateIpAddress value + */ + public PrivateIPAddress privateIpAddress() { + return this.privateIpAddress; + } + + /** + * Set private IP address. + * + * @param privateIpAddress the privateIpAddress value to set + * @return the LoadBalancerConfiguration object itself. + */ + public LoadBalancerConfiguration withPrivateIpAddress(PrivateIPAddress privateIpAddress) { + this.privateIpAddress = privateIpAddress; + return this; + } + + /** + * Get resource id of the public IP. + * + * @return the publicIpAddressResourceId value + */ + public String publicIpAddressResourceId() { + return this.publicIpAddressResourceId; + } + + /** + * Set resource id of the public IP. + * + * @param publicIpAddressResourceId the publicIpAddressResourceId value to set + * @return the LoadBalancerConfiguration object itself. + */ + public LoadBalancerConfiguration withPublicIpAddressResourceId(String publicIpAddressResourceId) { + this.publicIpAddressResourceId = publicIpAddressResourceId; + return this; + } + + /** + * Get resource id of the load balancer. + * + * @return the loadBalancerResourceId value + */ + public String loadBalancerResourceId() { + return this.loadBalancerResourceId; + } + + /** + * Set resource id of the load balancer. + * + * @param loadBalancerResourceId the loadBalancerResourceId value to set + * @return the LoadBalancerConfiguration object itself. + */ + public LoadBalancerConfiguration withLoadBalancerResourceId(String loadBalancerResourceId) { + this.loadBalancerResourceId = loadBalancerResourceId; + return this; + } + + /** + * Get probe port. + * + * @return the probePort value + */ + public Integer probePort() { + return this.probePort; + } + + /** + * Set probe port. + * + * @param probePort the probePort value to set + * @return the LoadBalancerConfiguration object itself. + */ + public LoadBalancerConfiguration withProbePort(Integer probePort) { + this.probePort = probePort; + return this; + } + + /** + * Get list of the SQL virtual machine instance resource id's that are enrolled into the availability group listener. + * + * @return the sqlVirtualMachineInstances value + */ + public List sqlVirtualMachineInstances() { + return this.sqlVirtualMachineInstances; + } + + /** + * Set list of the SQL virtual machine instance resource id's that are enrolled into the availability group listener. + * + * @param sqlVirtualMachineInstances the sqlVirtualMachineInstances value to set + * @return the LoadBalancerConfiguration object itself. + */ + public LoadBalancerConfiguration withSqlVirtualMachineInstances(List sqlVirtualMachineInstances) { + this.sqlVirtualMachineInstances = sqlVirtualMachineInstances; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operation.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operation.java new file mode 100644 index 0000000000000..e4fce18924da7 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operation.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.OperationInner; +import java.util.Map; + +/** + * Type representing Operation. + */ +public interface Operation extends HasInner, HasManager { + /** + * @return the display value. + */ + OperationDisplay display(); + + /** + * @return the name value. + */ + String name(); + + /** + * @return the origin value. + */ + OperationOrigin origin(); + + /** + * @return the properties value. + */ + Map properties(); + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationDisplay.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationDisplay.java new file mode 100644 index 0000000000000..2b9ad6ddd2efd --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationDisplay.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Display metadata associated with the operation. + */ +public class OperationDisplay { + /** + * The localized friendly form of the resource provider name. + */ + @JsonProperty(value = "provider", access = JsonProperty.Access.WRITE_ONLY) + private String provider; + + /** + * The localized friendly form of the resource type related to this + * action/operation. + */ + @JsonProperty(value = "resource", access = JsonProperty.Access.WRITE_ONLY) + private String resource; + + /** + * The localized friendly name for the operation. + */ + @JsonProperty(value = "operation", access = JsonProperty.Access.WRITE_ONLY) + private String operation; + + /** + * The localized friendly description for the operation. + */ + @JsonProperty(value = "description", access = JsonProperty.Access.WRITE_ONLY) + private String description; + + /** + * Get the localized friendly form of the resource provider name. + * + * @return the provider value + */ + public String provider() { + return this.provider; + } + + /** + * Get the localized friendly form of the resource type related to this action/operation. + * + * @return the resource value + */ + public String resource() { + return this.resource; + } + + /** + * Get the localized friendly name for the operation. + * + * @return the operation value + */ + public String operation() { + return this.operation; + } + + /** + * Get the localized friendly description for the operation. + * + * @return the description value + */ + public String description() { + return this.description; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationOrigin.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationOrigin.java new file mode 100644 index 0000000000000..daefb0e3e9e15 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/OperationOrigin.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for OperationOrigin. + */ +public final class OperationOrigin extends ExpandableStringEnum { + /** Static value user for OperationOrigin. */ + public static final OperationOrigin USER = fromString("user"); + + /** Static value system for OperationOrigin. */ + public static final OperationOrigin SYSTEM = fromString("system"); + + /** + * Creates or finds a OperationOrigin from its string representation. + * @param name a name to look for + * @return the corresponding OperationOrigin + */ + @JsonCreator + public static OperationOrigin fromString(String name) { + return fromString(name, OperationOrigin.class); + } + + /** + * @return known OperationOrigin values + */ + public static Collection values() { + return values(OperationOrigin.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operations.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operations.java new file mode 100644 index 0000000000000..a52610ee0cc67 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/Operations.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import rx.Observable; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.OperationsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing Operations. + */ +public interface Operations extends HasInner { + /** + * Lists all of the available SQL Rest API operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + Observable listAsync(); + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/PrivateIPAddress.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/PrivateIPAddress.java new file mode 100644 index 0000000000000..28139b8869257 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/PrivateIPAddress.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A private IP address bound to the availability group listener. + */ +public class PrivateIPAddress { + /** + * Private IP address bound to the availability group listener. + */ + @JsonProperty(value = "ipAddress") + private String ipAddress; + + /** + * Subnet used to include private IP. + */ + @JsonProperty(value = "subnetResourceId") + private String subnetResourceId; + + /** + * Get private IP address bound to the availability group listener. + * + * @return the ipAddress value + */ + public String ipAddress() { + return this.ipAddress; + } + + /** + * Set private IP address bound to the availability group listener. + * + * @param ipAddress the ipAddress value to set + * @return the PrivateIPAddress object itself. + */ + public PrivateIPAddress withIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + return this; + } + + /** + * Get subnet used to include private IP. + * + * @return the subnetResourceId value + */ + public String subnetResourceId() { + return this.subnetResourceId; + } + + /** + * Set subnet used to include private IP. + * + * @param subnetResourceId the subnetResourceId value to set + * @return the PrivateIPAddress object itself. + */ + public PrivateIPAddress withSubnetResourceId(String subnetResourceId) { + this.subnetResourceId = subnetResourceId; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ResourceIdentity.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ResourceIdentity.java new file mode 100644 index 0000000000000..f36df36d76775 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ResourceIdentity.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.UUID; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Azure Active Directory identity configuration for a resource. + */ +public class ResourceIdentity { + /** + * The Azure Active Directory principal id. + */ + @JsonProperty(value = "principalId", access = JsonProperty.Access.WRITE_ONLY) + private UUID principalId; + + /** + * The identity type. Set this to 'SystemAssigned' in order to + * automatically create and assign an Azure Active Directory principal for + * the resource. Possible values include: 'SystemAssigned'. + */ + @JsonProperty(value = "type") + private IdentityType type; + + /** + * The Azure Active Directory tenant id. + */ + @JsonProperty(value = "tenantId", access = JsonProperty.Access.WRITE_ONLY) + private UUID tenantId; + + /** + * Get the Azure Active Directory principal id. + * + * @return the principalId value + */ + public UUID principalId() { + return this.principalId; + } + + /** + * Get the identity type. Set this to 'SystemAssigned' in order to automatically create and assign an Azure Active Directory principal for the resource. Possible values include: 'SystemAssigned'. + * + * @return the type value + */ + public IdentityType type() { + return this.type; + } + + /** + * Set the identity type. Set this to 'SystemAssigned' in order to automatically create and assign an Azure Active Directory principal for the resource. Possible values include: 'SystemAssigned'. + * + * @param type the type value to set + * @return the ResourceIdentity object itself. + */ + public ResourceIdentity withType(IdentityType type) { + this.type = type; + return this; + } + + /** + * Get the Azure Active Directory tenant id. + * + * @return the tenantId value + */ + public UUID tenantId() { + return this.tenantId; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ScaleType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ScaleType.java new file mode 100644 index 0000000000000..5f6300f9e63d2 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ScaleType.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for ScaleType. + */ +public final class ScaleType extends ExpandableStringEnum { + /** Static value HA for ScaleType. */ + public static final ScaleType HA = fromString("HA"); + + /** + * Creates or finds a ScaleType from its string representation. + * @param name a name to look for + * @return the corresponding ScaleType + */ + @JsonCreator + public static ScaleType fromString(String name) { + return fromString(name, ScaleType.class); + } + + /** + * @return known ScaleType values + */ + public static Collection values() { + return values(ScaleType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ServerConfigurationsManagementSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ServerConfigurationsManagementSettings.java new file mode 100644 index 0000000000000..8cde29e6616d7 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/ServerConfigurationsManagementSettings.java @@ -0,0 +1,121 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Set the connectivity, storage and workload settings. + */ +public class ServerConfigurationsManagementSettings { + /** + * SQL connectivity type settings. + */ + @JsonProperty(value = "sqlConnectivityUpdateSettings") + private SqlConnectivityUpdateSettings sqlConnectivityUpdateSettings; + + /** + * SQL workload type settings. + */ + @JsonProperty(value = "sqlWorkloadTypeUpdateSettings") + private SqlWorkloadTypeUpdateSettings sqlWorkloadTypeUpdateSettings; + + /** + * SQL storage update settings. + */ + @JsonProperty(value = "sqlStorageUpdateSettings") + private SqlStorageUpdateSettings sqlStorageUpdateSettings; + + /** + * Additional SQL feature settings. + */ + @JsonProperty(value = "additionalFeaturesServerConfigurations") + private AdditionalFeaturesServerConfigurations additionalFeaturesServerConfigurations; + + /** + * Get sQL connectivity type settings. + * + * @return the sqlConnectivityUpdateSettings value + */ + public SqlConnectivityUpdateSettings sqlConnectivityUpdateSettings() { + return this.sqlConnectivityUpdateSettings; + } + + /** + * Set sQL connectivity type settings. + * + * @param sqlConnectivityUpdateSettings the sqlConnectivityUpdateSettings value to set + * @return the ServerConfigurationsManagementSettings object itself. + */ + public ServerConfigurationsManagementSettings withSqlConnectivityUpdateSettings(SqlConnectivityUpdateSettings sqlConnectivityUpdateSettings) { + this.sqlConnectivityUpdateSettings = sqlConnectivityUpdateSettings; + return this; + } + + /** + * Get sQL workload type settings. + * + * @return the sqlWorkloadTypeUpdateSettings value + */ + public SqlWorkloadTypeUpdateSettings sqlWorkloadTypeUpdateSettings() { + return this.sqlWorkloadTypeUpdateSettings; + } + + /** + * Set sQL workload type settings. + * + * @param sqlWorkloadTypeUpdateSettings the sqlWorkloadTypeUpdateSettings value to set + * @return the ServerConfigurationsManagementSettings object itself. + */ + public ServerConfigurationsManagementSettings withSqlWorkloadTypeUpdateSettings(SqlWorkloadTypeUpdateSettings sqlWorkloadTypeUpdateSettings) { + this.sqlWorkloadTypeUpdateSettings = sqlWorkloadTypeUpdateSettings; + return this; + } + + /** + * Get sQL storage update settings. + * + * @return the sqlStorageUpdateSettings value + */ + public SqlStorageUpdateSettings sqlStorageUpdateSettings() { + return this.sqlStorageUpdateSettings; + } + + /** + * Set sQL storage update settings. + * + * @param sqlStorageUpdateSettings the sqlStorageUpdateSettings value to set + * @return the ServerConfigurationsManagementSettings object itself. + */ + public ServerConfigurationsManagementSettings withSqlStorageUpdateSettings(SqlStorageUpdateSettings sqlStorageUpdateSettings) { + this.sqlStorageUpdateSettings = sqlStorageUpdateSettings; + return this; + } + + /** + * Get additional SQL feature settings. + * + * @return the additionalFeaturesServerConfigurations value + */ + public AdditionalFeaturesServerConfigurations additionalFeaturesServerConfigurations() { + return this.additionalFeaturesServerConfigurations; + } + + /** + * Set additional SQL feature settings. + * + * @param additionalFeaturesServerConfigurations the additionalFeaturesServerConfigurations value to set + * @return the ServerConfigurationsManagementSettings object itself. + */ + public ServerConfigurationsManagementSettings withAdditionalFeaturesServerConfigurations(AdditionalFeaturesServerConfigurations additionalFeaturesServerConfigurations) { + this.additionalFeaturesServerConfigurations = additionalFeaturesServerConfigurations; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlConnectivityUpdateSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlConnectivityUpdateSettings.java new file mode 100644 index 0000000000000..9b507da62998a --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlConnectivityUpdateSettings.java @@ -0,0 +1,122 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Set the access level and network port settings for SQL Server. + */ +public class SqlConnectivityUpdateSettings { + /** + * SQL Server connectivity option. Possible values include: 'LOCAL', + * 'PRIVATE', 'PUBLIC'. + */ + @JsonProperty(value = "connectivityType") + private ConnectivityType connectivityType; + + /** + * SQL Server port. + */ + @JsonProperty(value = "port") + private Integer port; + + /** + * SQL Server sysadmin login to create. + */ + @JsonProperty(value = "sqlAuthUpdateUserName") + private String sqlAuthUpdateUserName; + + /** + * SQL Server sysadmin login password. + */ + @JsonProperty(value = "sqlAuthUpdatePassword") + private String sqlAuthUpdatePassword; + + /** + * Get sQL Server connectivity option. Possible values include: 'LOCAL', 'PRIVATE', 'PUBLIC'. + * + * @return the connectivityType value + */ + public ConnectivityType connectivityType() { + return this.connectivityType; + } + + /** + * Set sQL Server connectivity option. Possible values include: 'LOCAL', 'PRIVATE', 'PUBLIC'. + * + * @param connectivityType the connectivityType value to set + * @return the SqlConnectivityUpdateSettings object itself. + */ + public SqlConnectivityUpdateSettings withConnectivityType(ConnectivityType connectivityType) { + this.connectivityType = connectivityType; + return this; + } + + /** + * Get sQL Server port. + * + * @return the port value + */ + public Integer port() { + return this.port; + } + + /** + * Set sQL Server port. + * + * @param port the port value to set + * @return the SqlConnectivityUpdateSettings object itself. + */ + public SqlConnectivityUpdateSettings withPort(Integer port) { + this.port = port; + return this; + } + + /** + * Get sQL Server sysadmin login to create. + * + * @return the sqlAuthUpdateUserName value + */ + public String sqlAuthUpdateUserName() { + return this.sqlAuthUpdateUserName; + } + + /** + * Set sQL Server sysadmin login to create. + * + * @param sqlAuthUpdateUserName the sqlAuthUpdateUserName value to set + * @return the SqlConnectivityUpdateSettings object itself. + */ + public SqlConnectivityUpdateSettings withSqlAuthUpdateUserName(String sqlAuthUpdateUserName) { + this.sqlAuthUpdateUserName = sqlAuthUpdateUserName; + return this; + } + + /** + * Get sQL Server sysadmin login password. + * + * @return the sqlAuthUpdatePassword value + */ + public String sqlAuthUpdatePassword() { + return this.sqlAuthUpdatePassword; + } + + /** + * Set sQL Server sysadmin login password. + * + * @param sqlAuthUpdatePassword the sqlAuthUpdatePassword value to set + * @return the SqlConnectivityUpdateSettings object itself. + */ + public SqlConnectivityUpdateSettings withSqlAuthUpdatePassword(String sqlAuthUpdatePassword) { + this.sqlAuthUpdatePassword = sqlAuthUpdatePassword; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlImageSku.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlImageSku.java new file mode 100644 index 0000000000000..0c42bddd3ba24 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlImageSku.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SqlImageSku. + */ +public final class SqlImageSku extends ExpandableStringEnum { + /** Static value Developer for SqlImageSku. */ + public static final SqlImageSku DEVELOPER = fromString("Developer"); + + /** Static value Express for SqlImageSku. */ + public static final SqlImageSku EXPRESS = fromString("Express"); + + /** Static value Standard for SqlImageSku. */ + public static final SqlImageSku STANDARD = fromString("Standard"); + + /** Static value Enterprise for SqlImageSku. */ + public static final SqlImageSku ENTERPRISE = fromString("Enterprise"); + + /** Static value Web for SqlImageSku. */ + public static final SqlImageSku WEB = fromString("Web"); + + /** + * Creates or finds a SqlImageSku from its string representation. + * @param name a name to look for + * @return the corresponding SqlImageSku + */ + @JsonCreator + public static SqlImageSku fromString(String name) { + return fromString(name, SqlImageSku.class); + } + + /** + * @return known SqlImageSku values + */ + public static Collection values() { + return values(SqlImageSku.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlManagementMode.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlManagementMode.java new file mode 100644 index 0000000000000..2832caa2b0b85 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlManagementMode.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SqlManagementMode. + */ +public final class SqlManagementMode extends ExpandableStringEnum { + /** Static value Full for SqlManagementMode. */ + public static final SqlManagementMode FULL = fromString("Full"); + + /** Static value LightWeight for SqlManagementMode. */ + public static final SqlManagementMode LIGHT_WEIGHT = fromString("LightWeight"); + + /** Static value NoAgent for SqlManagementMode. */ + public static final SqlManagementMode NO_AGENT = fromString("NoAgent"); + + /** + * Creates or finds a SqlManagementMode from its string representation. + * @param name a name to look for + * @return the corresponding SqlManagementMode + */ + @JsonCreator + public static SqlManagementMode fromString(String name) { + return fromString(name, SqlManagementMode.class); + } + + /** + * @return known SqlManagementMode values + */ + public static Collection values() { + return values(SqlManagementMode.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlServerLicenseType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlServerLicenseType.java new file mode 100644 index 0000000000000..6825e7a17c2d2 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlServerLicenseType.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SqlServerLicenseType. + */ +public final class SqlServerLicenseType extends ExpandableStringEnum { + /** Static value PAYG for SqlServerLicenseType. */ + public static final SqlServerLicenseType PAYG = fromString("PAYG"); + + /** Static value AHUB for SqlServerLicenseType. */ + public static final SqlServerLicenseType AHUB = fromString("AHUB"); + + /** + * Creates or finds a SqlServerLicenseType from its string representation. + * @param name a name to look for + * @return the corresponding SqlServerLicenseType + */ + @JsonCreator + public static SqlServerLicenseType fromString(String name) { + return fromString(name, SqlServerLicenseType.class); + } + + /** + * @return known SqlServerLicenseType values + */ + public static Collection values() { + return values(SqlServerLicenseType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlStorageUpdateSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlStorageUpdateSettings.java new file mode 100644 index 0000000000000..f6c9015d6e50d --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlStorageUpdateSettings.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Set disk storage settings for SQL Server. + */ +public class SqlStorageUpdateSettings { + /** + * Virtual machine disk count. + */ + @JsonProperty(value = "diskCount") + private Integer diskCount; + + /** + * Device id of the first disk to be updated. + */ + @JsonProperty(value = "startingDeviceId") + private Integer startingDeviceId; + + /** + * Disk configuration to apply to SQL Server. Possible values include: + * 'NEW', 'EXTEND', 'ADD'. + */ + @JsonProperty(value = "diskConfigurationType") + private DiskConfigurationType diskConfigurationType; + + /** + * Get virtual machine disk count. + * + * @return the diskCount value + */ + public Integer diskCount() { + return this.diskCount; + } + + /** + * Set virtual machine disk count. + * + * @param diskCount the diskCount value to set + * @return the SqlStorageUpdateSettings object itself. + */ + public SqlStorageUpdateSettings withDiskCount(Integer diskCount) { + this.diskCount = diskCount; + return this; + } + + /** + * Get device id of the first disk to be updated. + * + * @return the startingDeviceId value + */ + public Integer startingDeviceId() { + return this.startingDeviceId; + } + + /** + * Set device id of the first disk to be updated. + * + * @param startingDeviceId the startingDeviceId value to set + * @return the SqlStorageUpdateSettings object itself. + */ + public SqlStorageUpdateSettings withStartingDeviceId(Integer startingDeviceId) { + this.startingDeviceId = startingDeviceId; + return this; + } + + /** + * Get disk configuration to apply to SQL Server. Possible values include: 'NEW', 'EXTEND', 'ADD'. + * + * @return the diskConfigurationType value + */ + public DiskConfigurationType diskConfigurationType() { + return this.diskConfigurationType; + } + + /** + * Set disk configuration to apply to SQL Server. Possible values include: 'NEW', 'EXTEND', 'ADD'. + * + * @param diskConfigurationType the diskConfigurationType value to set + * @return the SqlStorageUpdateSettings object itself. + */ + public SqlStorageUpdateSettings withDiskConfigurationType(DiskConfigurationType diskConfigurationType) { + this.diskConfigurationType = diskConfigurationType; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachine.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachine.java new file mode 100644 index 0000000000000..6ab9c2f4896c0 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachine.java @@ -0,0 +1,421 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.arm.resources.models.Resource; +import com.microsoft.azure.arm.resources.models.GroupableResourceCore; +import com.microsoft.azure.arm.resources.models.HasResourceGroup; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineInner; + +/** + * Type representing SqlVirtualMachine. + */ +public interface SqlVirtualMachine extends HasInner, Resource, GroupableResourceCore, HasResourceGroup, Refreshable, Updatable, HasManager { + /** + * @return the autoBackupSettings value. + */ + AutoBackupSettings autoBackupSettings(); + + /** + * @return the autoPatchingSettings value. + */ + AutoPatchingSettings autoPatchingSettings(); + + /** + * @return the identity value. + */ + ResourceIdentity identity(); + + /** + * @return the keyVaultCredentialSettings value. + */ + KeyVaultCredentialSettings keyVaultCredentialSettings(); + + /** + * @return the provisioningState value. + */ + String provisioningState(); + + /** + * @return the serverConfigurationsManagementSettings value. + */ + ServerConfigurationsManagementSettings serverConfigurationsManagementSettings(); + + /** + * @return the sqlImageOffer value. + */ + String sqlImageOffer(); + + /** + * @return the sqlImageSku value. + */ + SqlImageSku sqlImageSku(); + + /** + * @return the sqlManagement value. + */ + SqlManagementMode sqlManagement(); + + /** + * @return the sqlServerLicenseType value. + */ + SqlServerLicenseType sqlServerLicenseType(); + + /** + * @return the sqlVirtualMachineGroupResourceId value. + */ + String sqlVirtualMachineGroupResourceId(); + + /** + * @return the virtualMachineResourceId value. + */ + String virtualMachineResourceId(); + + /** + * @return the wsfcDomainCredentials value. + */ + WsfcDomainCredentials wsfcDomainCredentials(); + + /** + * The entirety of the SqlVirtualMachine definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithGroup, DefinitionStages.WithCreate { + } + + /** + * Grouping of SqlVirtualMachine definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a SqlVirtualMachine definition. + */ + interface Blank extends GroupableResourceCore.DefinitionWithRegion { + } + + /** + * The stage of the SqlVirtualMachine definition allowing to specify the resource group. + */ + interface WithGroup extends GroupableResourceCore.DefinitionStages.WithGroup { + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify AutoBackupSettings. + */ + interface WithAutoBackupSettings { + /** + * Specifies autoBackupSettings. + * @param autoBackupSettings Auto backup settings for SQL Server + * @return the next definition stage + */ + WithCreate withAutoBackupSettings(AutoBackupSettings autoBackupSettings); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify AutoPatchingSettings. + */ + interface WithAutoPatchingSettings { + /** + * Specifies autoPatchingSettings. + * @param autoPatchingSettings Auto patching settings for applying critical security updates to SQL virtual machine + * @return the next definition stage + */ + WithCreate withAutoPatchingSettings(AutoPatchingSettings autoPatchingSettings); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify Identity. + */ + interface WithIdentity { + /** + * Specifies identity. + * @param identity Azure Active Directory identity of the server + * @return the next definition stage + */ + WithCreate withIdentity(ResourceIdentity identity); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify KeyVaultCredentialSettings. + */ + interface WithKeyVaultCredentialSettings { + /** + * Specifies keyVaultCredentialSettings. + * @param keyVaultCredentialSettings Key vault credential settings + * @return the next definition stage + */ + WithCreate withKeyVaultCredentialSettings(KeyVaultCredentialSettings keyVaultCredentialSettings); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify ServerConfigurationsManagementSettings. + */ + interface WithServerConfigurationsManagementSettings { + /** + * Specifies serverConfigurationsManagementSettings. + * @param serverConfigurationsManagementSettings SQL Server configuration management settings + * @return the next definition stage + */ + WithCreate withServerConfigurationsManagementSettings(ServerConfigurationsManagementSettings serverConfigurationsManagementSettings); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify SqlImageOffer. + */ + interface WithSqlImageOffer { + /** + * Specifies sqlImageOffer. + * @param sqlImageOffer SQL image offer. Examples include SQL2016-WS2016, SQL2017-WS2016 + * @return the next definition stage + */ + WithCreate withSqlImageOffer(String sqlImageOffer); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify SqlImageSku. + */ + interface WithSqlImageSku { + /** + * Specifies sqlImageSku. + * @param sqlImageSku SQL Server edition type. Possible values include: 'Developer', 'Express', 'Standard', 'Enterprise', 'Web' + * @return the next definition stage + */ + WithCreate withSqlImageSku(SqlImageSku sqlImageSku); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify SqlManagement. + */ + interface WithSqlManagement { + /** + * Specifies sqlManagement. + * @param sqlManagement SQL Server Management type. Possible values include: 'Full', 'LightWeight', 'NoAgent' + * @return the next definition stage + */ + WithCreate withSqlManagement(SqlManagementMode sqlManagement); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify SqlServerLicenseType. + */ + interface WithSqlServerLicenseType { + /** + * Specifies sqlServerLicenseType. + * @param sqlServerLicenseType SQL Server license type. Possible values include: 'PAYG', 'AHUB' + * @return the next definition stage + */ + WithCreate withSqlServerLicenseType(SqlServerLicenseType sqlServerLicenseType); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify SqlVirtualMachineGroupResourceId. + */ + interface WithSqlVirtualMachineGroupResourceId { + /** + * Specifies sqlVirtualMachineGroupResourceId. + * @param sqlVirtualMachineGroupResourceId ARM resource id of the SQL virtual machine group this SQL virtual machine is or will be part of + * @return the next definition stage + */ + WithCreate withSqlVirtualMachineGroupResourceId(String sqlVirtualMachineGroupResourceId); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify VirtualMachineResourceId. + */ + interface WithVirtualMachineResourceId { + /** + * Specifies virtualMachineResourceId. + * @param virtualMachineResourceId ARM Resource id of underlying virtual machine created from SQL marketplace image + * @return the next definition stage + */ + WithCreate withVirtualMachineResourceId(String virtualMachineResourceId); + } + + /** + * The stage of the sqlvirtualmachine definition allowing to specify WsfcDomainCredentials. + */ + interface WithWsfcDomainCredentials { + /** + * Specifies wsfcDomainCredentials. + * @param wsfcDomainCredentials Domain credentials for setting up Windows Server Failover Cluster for SQL availability group + * @return the next definition stage + */ + WithCreate withWsfcDomainCredentials(WsfcDomainCredentials wsfcDomainCredentials); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable, Resource.DefinitionWithTags, DefinitionStages.WithAutoBackupSettings, DefinitionStages.WithAutoPatchingSettings, DefinitionStages.WithIdentity, DefinitionStages.WithKeyVaultCredentialSettings, DefinitionStages.WithServerConfigurationsManagementSettings, DefinitionStages.WithSqlImageOffer, DefinitionStages.WithSqlImageSku, DefinitionStages.WithSqlManagement, DefinitionStages.WithSqlServerLicenseType, DefinitionStages.WithSqlVirtualMachineGroupResourceId, DefinitionStages.WithVirtualMachineResourceId, DefinitionStages.WithWsfcDomainCredentials { + } + } + /** + * The template for a SqlVirtualMachine update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, Resource.UpdateWithTags, UpdateStages.WithAutoBackupSettings, UpdateStages.WithAutoPatchingSettings, UpdateStages.WithIdentity, UpdateStages.WithKeyVaultCredentialSettings, UpdateStages.WithServerConfigurationsManagementSettings, UpdateStages.WithSqlImageOffer, UpdateStages.WithSqlImageSku, UpdateStages.WithSqlManagement, UpdateStages.WithSqlServerLicenseType, UpdateStages.WithSqlVirtualMachineGroupResourceId, UpdateStages.WithVirtualMachineResourceId, UpdateStages.WithWsfcDomainCredentials { + } + + /** + * Grouping of SqlVirtualMachine update stages. + */ + interface UpdateStages { + /** + * The stage of the sqlvirtualmachine update allowing to specify AutoBackupSettings. + */ + interface WithAutoBackupSettings { + /** + * Specifies autoBackupSettings. + * @param autoBackupSettings Auto backup settings for SQL Server + * @return the next update stage + */ + Update withAutoBackupSettings(AutoBackupSettings autoBackupSettings); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify AutoPatchingSettings. + */ + interface WithAutoPatchingSettings { + /** + * Specifies autoPatchingSettings. + * @param autoPatchingSettings Auto patching settings for applying critical security updates to SQL virtual machine + * @return the next update stage + */ + Update withAutoPatchingSettings(AutoPatchingSettings autoPatchingSettings); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify Identity. + */ + interface WithIdentity { + /** + * Specifies identity. + * @param identity Azure Active Directory identity of the server + * @return the next update stage + */ + Update withIdentity(ResourceIdentity identity); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify KeyVaultCredentialSettings. + */ + interface WithKeyVaultCredentialSettings { + /** + * Specifies keyVaultCredentialSettings. + * @param keyVaultCredentialSettings Key vault credential settings + * @return the next update stage + */ + Update withKeyVaultCredentialSettings(KeyVaultCredentialSettings keyVaultCredentialSettings); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify ServerConfigurationsManagementSettings. + */ + interface WithServerConfigurationsManagementSettings { + /** + * Specifies serverConfigurationsManagementSettings. + * @param serverConfigurationsManagementSettings SQL Server configuration management settings + * @return the next update stage + */ + Update withServerConfigurationsManagementSettings(ServerConfigurationsManagementSettings serverConfigurationsManagementSettings); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify SqlImageOffer. + */ + interface WithSqlImageOffer { + /** + * Specifies sqlImageOffer. + * @param sqlImageOffer SQL image offer. Examples include SQL2016-WS2016, SQL2017-WS2016 + * @return the next update stage + */ + Update withSqlImageOffer(String sqlImageOffer); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify SqlImageSku. + */ + interface WithSqlImageSku { + /** + * Specifies sqlImageSku. + * @param sqlImageSku SQL Server edition type. Possible values include: 'Developer', 'Express', 'Standard', 'Enterprise', 'Web' + * @return the next update stage + */ + Update withSqlImageSku(SqlImageSku sqlImageSku); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify SqlManagement. + */ + interface WithSqlManagement { + /** + * Specifies sqlManagement. + * @param sqlManagement SQL Server Management type. Possible values include: 'Full', 'LightWeight', 'NoAgent' + * @return the next update stage + */ + Update withSqlManagement(SqlManagementMode sqlManagement); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify SqlServerLicenseType. + */ + interface WithSqlServerLicenseType { + /** + * Specifies sqlServerLicenseType. + * @param sqlServerLicenseType SQL Server license type. Possible values include: 'PAYG', 'AHUB' + * @return the next update stage + */ + Update withSqlServerLicenseType(SqlServerLicenseType sqlServerLicenseType); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify SqlVirtualMachineGroupResourceId. + */ + interface WithSqlVirtualMachineGroupResourceId { + /** + * Specifies sqlVirtualMachineGroupResourceId. + * @param sqlVirtualMachineGroupResourceId ARM resource id of the SQL virtual machine group this SQL virtual machine is or will be part of + * @return the next update stage + */ + Update withSqlVirtualMachineGroupResourceId(String sqlVirtualMachineGroupResourceId); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify VirtualMachineResourceId. + */ + interface WithVirtualMachineResourceId { + /** + * Specifies virtualMachineResourceId. + * @param virtualMachineResourceId ARM Resource id of underlying virtual machine created from SQL marketplace image + * @return the next update stage + */ + Update withVirtualMachineResourceId(String virtualMachineResourceId); + } + + /** + * The stage of the sqlvirtualmachine update allowing to specify WsfcDomainCredentials. + */ + interface WithWsfcDomainCredentials { + /** + * Specifies wsfcDomainCredentials. + * @param wsfcDomainCredentials Domain credentials for setting up Windows Server Failover Cluster for SQL availability group + * @return the next update stage + */ + Update withWsfcDomainCredentials(WsfcDomainCredentials wsfcDomainCredentials); + } + + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroup.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroup.java new file mode 100644 index 0000000000000..e8697e906bc56 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroup.java @@ -0,0 +1,175 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.model.HasInner; +import com.microsoft.azure.arm.resources.models.Resource; +import com.microsoft.azure.arm.resources.models.GroupableResourceCore; +import com.microsoft.azure.arm.resources.models.HasResourceGroup; +import com.microsoft.azure.arm.model.Refreshable; +import com.microsoft.azure.arm.model.Updatable; +import com.microsoft.azure.arm.model.Appliable; +import com.microsoft.azure.arm.model.Creatable; +import com.microsoft.azure.arm.resources.models.HasManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineManager; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineGroupInner; + +/** + * Type representing SqlVirtualMachineGroup. + */ +public interface SqlVirtualMachineGroup extends HasInner, Resource, GroupableResourceCore, HasResourceGroup, Refreshable, Updatable, HasManager { + /** + * @return the clusterConfiguration value. + */ + ClusterConfiguration clusterConfiguration(); + + /** + * @return the clusterManagerType value. + */ + ClusterManagerType clusterManagerType(); + + /** + * @return the provisioningState value. + */ + String provisioningState(); + + /** + * @return the scaleType value. + */ + ScaleType scaleType(); + + /** + * @return the sqlImageOffer value. + */ + String sqlImageOffer(); + + /** + * @return the sqlImageSku value. + */ + SqlVmGroupImageSku sqlImageSku(); + + /** + * @return the wsfcDomainProfile value. + */ + WsfcDomainProfile wsfcDomainProfile(); + + /** + * The entirety of the SqlVirtualMachineGroup definition. + */ + interface Definition extends DefinitionStages.Blank, DefinitionStages.WithGroup, DefinitionStages.WithCreate { + } + + /** + * Grouping of SqlVirtualMachineGroup definition stages. + */ + interface DefinitionStages { + /** + * The first stage of a SqlVirtualMachineGroup definition. + */ + interface Blank extends GroupableResourceCore.DefinitionWithRegion { + } + + /** + * The stage of the SqlVirtualMachineGroup definition allowing to specify the resource group. + */ + interface WithGroup extends GroupableResourceCore.DefinitionStages.WithGroup { + } + + /** + * The stage of the sqlvirtualmachinegroup definition allowing to specify SqlImageOffer. + */ + interface WithSqlImageOffer { + /** + * Specifies sqlImageOffer. + * @param sqlImageOffer SQL image offer. Examples may include SQL2016-WS2016, SQL2017-WS2016 + * @return the next definition stage + */ + WithCreate withSqlImageOffer(String sqlImageOffer); + } + + /** + * The stage of the sqlvirtualmachinegroup definition allowing to specify SqlImageSku. + */ + interface WithSqlImageSku { + /** + * Specifies sqlImageSku. + * @param sqlImageSku SQL image sku. Possible values include: 'Developer', 'Enterprise' + * @return the next definition stage + */ + WithCreate withSqlImageSku(SqlVmGroupImageSku sqlImageSku); + } + + /** + * The stage of the sqlvirtualmachinegroup definition allowing to specify WsfcDomainProfile. + */ + interface WithWsfcDomainProfile { + /** + * Specifies wsfcDomainProfile. + * @param wsfcDomainProfile Cluster Active Directory domain profile + * @return the next definition stage + */ + WithCreate withWsfcDomainProfile(WsfcDomainProfile wsfcDomainProfile); + } + + /** + * The stage of the definition which contains all the minimum required inputs for + * the resource to be created (via {@link WithCreate#create()}), but also allows + * for any other optional settings to be specified. + */ + interface WithCreate extends Creatable, Resource.DefinitionWithTags, DefinitionStages.WithSqlImageOffer, DefinitionStages.WithSqlImageSku, DefinitionStages.WithWsfcDomainProfile { + } + } + /** + * The template for a SqlVirtualMachineGroup update operation, containing all the settings that can be modified. + */ + interface Update extends Appliable, Resource.UpdateWithTags, UpdateStages.WithSqlImageOffer, UpdateStages.WithSqlImageSku, UpdateStages.WithWsfcDomainProfile { + } + + /** + * Grouping of SqlVirtualMachineGroup update stages. + */ + interface UpdateStages { + /** + * The stage of the sqlvirtualmachinegroup update allowing to specify SqlImageOffer. + */ + interface WithSqlImageOffer { + /** + * Specifies sqlImageOffer. + * @param sqlImageOffer SQL image offer. Examples may include SQL2016-WS2016, SQL2017-WS2016 + * @return the next update stage + */ + Update withSqlImageOffer(String sqlImageOffer); + } + + /** + * The stage of the sqlvirtualmachinegroup update allowing to specify SqlImageSku. + */ + interface WithSqlImageSku { + /** + * Specifies sqlImageSku. + * @param sqlImageSku SQL image sku. Possible values include: 'Developer', 'Enterprise' + * @return the next update stage + */ + Update withSqlImageSku(SqlVmGroupImageSku sqlImageSku); + } + + /** + * The stage of the sqlvirtualmachinegroup update allowing to specify WsfcDomainProfile. + */ + interface WithWsfcDomainProfile { + /** + * Specifies wsfcDomainProfile. + * @param wsfcDomainProfile Cluster Active Directory domain profile + * @return the next update stage + */ + Update withWsfcDomainProfile(WsfcDomainProfile wsfcDomainProfile); + } + + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroupUpdate.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroupUpdate.java new file mode 100644 index 0000000000000..edfee48280a1d --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroupUpdate.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * An update to a SQL virtual machine group. + */ +public class SqlVirtualMachineGroupUpdate { + /** + * Resource tags. + */ + @JsonProperty(value = "tags") + private Map tags; + + /** + * Get resource tags. + * + * @return the tags value + */ + public Map tags() { + return this.tags; + } + + /** + * Set resource tags. + * + * @param tags the tags value to set + * @return the SqlVirtualMachineGroupUpdate object itself. + */ + public SqlVirtualMachineGroupUpdate withTags(Map tags) { + this.tags = tags; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroups.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroups.java new file mode 100644 index 0000000000000..b92d0cfc035a6 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineGroups.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import com.microsoft.azure.arm.resources.collection.SupportsDeletingByResourceGroup; +import com.microsoft.azure.arm.resources.collection.SupportsBatchDeletion; +import com.microsoft.azure.arm.resources.collection.SupportsGettingByResourceGroup; +import rx.Observable; +import com.microsoft.azure.arm.resources.collection.SupportsListingByResourceGroup; +import com.microsoft.azure.arm.collection.SupportsListing; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachineGroupsInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing SqlVirtualMachineGroups. + */ +public interface SqlVirtualMachineGroups extends SupportsCreating, SupportsDeletingByResourceGroup, SupportsBatchDeletion, SupportsGettingByResourceGroup, SupportsListingByResourceGroup, SupportsListing, HasInner { +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineUpdate.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineUpdate.java new file mode 100644 index 0000000000000..30a83cd8013ed --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachineUpdate.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * An update to a SQL virtual machine. + */ +public class SqlVirtualMachineUpdate { + /** + * Resource tags. + */ + @JsonProperty(value = "tags") + private Map tags; + + /** + * Get resource tags. + * + * @return the tags value + */ + public Map tags() { + return this.tags; + } + + /** + * Set resource tags. + * + * @param tags the tags value to set + * @return the SqlVirtualMachineUpdate object itself. + */ + public SqlVirtualMachineUpdate withTags(Map tags) { + this.tags = tags; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachines.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachines.java new file mode 100644 index 0000000000000..359f32a3574a4 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVirtualMachines.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.microsoft.azure.arm.collection.SupportsCreating; +import com.microsoft.azure.arm.resources.collection.SupportsDeletingByResourceGroup; +import com.microsoft.azure.arm.resources.collection.SupportsBatchDeletion; +import com.microsoft.azure.arm.resources.collection.SupportsGettingByResourceGroup; +import rx.Observable; +import com.microsoft.azure.arm.resources.collection.SupportsListingByResourceGroup; +import com.microsoft.azure.arm.collection.SupportsListing; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation.SqlVirtualMachinesInner; +import com.microsoft.azure.arm.model.HasInner; + +/** + * Type representing SqlVirtualMachines. + */ +public interface SqlVirtualMachines extends SupportsCreating, SupportsDeletingByResourceGroup, SupportsBatchDeletion, SupportsGettingByResourceGroup, SupportsListingByResourceGroup, SupportsListing, HasInner { +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVmGroupImageSku.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVmGroupImageSku.java new file mode 100644 index 0000000000000..c17a48c02975d --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlVmGroupImageSku.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SqlVmGroupImageSku. + */ +public final class SqlVmGroupImageSku extends ExpandableStringEnum { + /** Static value Developer for SqlVmGroupImageSku. */ + public static final SqlVmGroupImageSku DEVELOPER = fromString("Developer"); + + /** Static value Enterprise for SqlVmGroupImageSku. */ + public static final SqlVmGroupImageSku ENTERPRISE = fromString("Enterprise"); + + /** + * Creates or finds a SqlVmGroupImageSku from its string representation. + * @param name a name to look for + * @return the corresponding SqlVmGroupImageSku + */ + @JsonCreator + public static SqlVmGroupImageSku fromString(String name) { + return fromString(name, SqlVmGroupImageSku.class); + } + + /** + * @return known SqlVmGroupImageSku values + */ + public static Collection values() { + return values(SqlVmGroupImageSku.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadType.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadType.java new file mode 100644 index 0000000000000..398f969f661ee --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadType.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.microsoft.rest.ExpandableStringEnum; + +/** + * Defines values for SqlWorkloadType. + */ +public final class SqlWorkloadType extends ExpandableStringEnum { + /** Static value GENERAL for SqlWorkloadType. */ + public static final SqlWorkloadType GENERAL = fromString("GENERAL"); + + /** Static value OLTP for SqlWorkloadType. */ + public static final SqlWorkloadType OLTP = fromString("OLTP"); + + /** Static value DW for SqlWorkloadType. */ + public static final SqlWorkloadType DW = fromString("DW"); + + /** + * Creates or finds a SqlWorkloadType from its string representation. + * @param name a name to look for + * @return the corresponding SqlWorkloadType + */ + @JsonCreator + public static SqlWorkloadType fromString(String name) { + return fromString(name, SqlWorkloadType.class); + } + + /** + * @return known SqlWorkloadType values + */ + public static Collection values() { + return values(SqlWorkloadType.class); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadTypeUpdateSettings.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadTypeUpdateSettings.java new file mode 100644 index 0000000000000..0d276338a161a --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/SqlWorkloadTypeUpdateSettings.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Set workload type to optimize storage for SQL Server. + */ +public class SqlWorkloadTypeUpdateSettings { + /** + * SQL Server workload type. Possible values include: 'GENERAL', 'OLTP', + * 'DW'. + */ + @JsonProperty(value = "sqlWorkloadType") + private SqlWorkloadType sqlWorkloadType; + + /** + * Get sQL Server workload type. Possible values include: 'GENERAL', 'OLTP', 'DW'. + * + * @return the sqlWorkloadType value + */ + public SqlWorkloadType sqlWorkloadType() { + return this.sqlWorkloadType; + } + + /** + * Set sQL Server workload type. Possible values include: 'GENERAL', 'OLTP', 'DW'. + * + * @param sqlWorkloadType the sqlWorkloadType value to set + * @return the SqlWorkloadTypeUpdateSettings object itself. + */ + public SqlWorkloadTypeUpdateSettings withSqlWorkloadType(SqlWorkloadType sqlWorkloadType) { + this.sqlWorkloadType = sqlWorkloadType; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainCredentials.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainCredentials.java new file mode 100644 index 0000000000000..09e86863fc77c --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainCredentials.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Domain credentials for setting up Windows Server Failover Cluster for SQL + * availability group. + */ +public class WsfcDomainCredentials { + /** + * Cluster bootstrap account password. + */ + @JsonProperty(value = "clusterBootstrapAccountPassword") + private String clusterBootstrapAccountPassword; + + /** + * Cluster operator account password. + */ + @JsonProperty(value = "clusterOperatorAccountPassword") + private String clusterOperatorAccountPassword; + + /** + * SQL service account password. + */ + @JsonProperty(value = "sqlServiceAccountPassword") + private String sqlServiceAccountPassword; + + /** + * Get cluster bootstrap account password. + * + * @return the clusterBootstrapAccountPassword value + */ + public String clusterBootstrapAccountPassword() { + return this.clusterBootstrapAccountPassword; + } + + /** + * Set cluster bootstrap account password. + * + * @param clusterBootstrapAccountPassword the clusterBootstrapAccountPassword value to set + * @return the WsfcDomainCredentials object itself. + */ + public WsfcDomainCredentials withClusterBootstrapAccountPassword(String clusterBootstrapAccountPassword) { + this.clusterBootstrapAccountPassword = clusterBootstrapAccountPassword; + return this; + } + + /** + * Get cluster operator account password. + * + * @return the clusterOperatorAccountPassword value + */ + public String clusterOperatorAccountPassword() { + return this.clusterOperatorAccountPassword; + } + + /** + * Set cluster operator account password. + * + * @param clusterOperatorAccountPassword the clusterOperatorAccountPassword value to set + * @return the WsfcDomainCredentials object itself. + */ + public WsfcDomainCredentials withClusterOperatorAccountPassword(String clusterOperatorAccountPassword) { + this.clusterOperatorAccountPassword = clusterOperatorAccountPassword; + return this; + } + + /** + * Get sQL service account password. + * + * @return the sqlServiceAccountPassword value + */ + public String sqlServiceAccountPassword() { + return this.sqlServiceAccountPassword; + } + + /** + * Set sQL service account password. + * + * @param sqlServiceAccountPassword the sqlServiceAccountPassword value to set + * @return the WsfcDomainCredentials object itself. + */ + public WsfcDomainCredentials withSqlServiceAccountPassword(String sqlServiceAccountPassword) { + this.sqlServiceAccountPassword = sqlServiceAccountPassword; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainProfile.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainProfile.java new file mode 100644 index 0000000000000..a5a5adf5cda15 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/WsfcDomainProfile.java @@ -0,0 +1,229 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Active Directory account details to operate Windows Server Failover Cluster. + */ +public class WsfcDomainProfile { + /** + * Fully qualified name of the domain. + */ + @JsonProperty(value = "domainFqdn") + private String domainFqdn; + + /** + * Organizational Unit path in which the nodes and cluster will be present. + */ + @JsonProperty(value = "ouPath") + private String ouPath; + + /** + * Account name used for creating cluster (at minimum needs permissions to + * 'Create Computer Objects' in domain). + */ + @JsonProperty(value = "clusterBootstrapAccount") + private String clusterBootstrapAccount; + + /** + * Account name used for operating cluster i.e. will be part of + * administrators group on all the participating virtual machines in the + * cluster. + */ + @JsonProperty(value = "clusterOperatorAccount") + private String clusterOperatorAccount; + + /** + * Account name under which SQL service will run on all participating SQL + * virtual machines in the cluster. + */ + @JsonProperty(value = "sqlServiceAccount") + private String sqlServiceAccount; + + /** + * Optional path for fileshare witness. + */ + @JsonProperty(value = "fileShareWitnessPath") + private String fileShareWitnessPath; + + /** + * Fully qualified ARM resource id of the witness storage account. + */ + @JsonProperty(value = "storageAccountUrl") + private String storageAccountUrl; + + /** + * Primary key of the witness storage account. + */ + @JsonProperty(value = "storageAccountPrimaryKey") + private String storageAccountPrimaryKey; + + /** + * Get fully qualified name of the domain. + * + * @return the domainFqdn value + */ + public String domainFqdn() { + return this.domainFqdn; + } + + /** + * Set fully qualified name of the domain. + * + * @param domainFqdn the domainFqdn value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withDomainFqdn(String domainFqdn) { + this.domainFqdn = domainFqdn; + return this; + } + + /** + * Get organizational Unit path in which the nodes and cluster will be present. + * + * @return the ouPath value + */ + public String ouPath() { + return this.ouPath; + } + + /** + * Set organizational Unit path in which the nodes and cluster will be present. + * + * @param ouPath the ouPath value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withOuPath(String ouPath) { + this.ouPath = ouPath; + return this; + } + + /** + * Get account name used for creating cluster (at minimum needs permissions to 'Create Computer Objects' in domain). + * + * @return the clusterBootstrapAccount value + */ + public String clusterBootstrapAccount() { + return this.clusterBootstrapAccount; + } + + /** + * Set account name used for creating cluster (at minimum needs permissions to 'Create Computer Objects' in domain). + * + * @param clusterBootstrapAccount the clusterBootstrapAccount value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withClusterBootstrapAccount(String clusterBootstrapAccount) { + this.clusterBootstrapAccount = clusterBootstrapAccount; + return this; + } + + /** + * Get account name used for operating cluster i.e. will be part of administrators group on all the participating virtual machines in the cluster. + * + * @return the clusterOperatorAccount value + */ + public String clusterOperatorAccount() { + return this.clusterOperatorAccount; + } + + /** + * Set account name used for operating cluster i.e. will be part of administrators group on all the participating virtual machines in the cluster. + * + * @param clusterOperatorAccount the clusterOperatorAccount value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withClusterOperatorAccount(String clusterOperatorAccount) { + this.clusterOperatorAccount = clusterOperatorAccount; + return this; + } + + /** + * Get account name under which SQL service will run on all participating SQL virtual machines in the cluster. + * + * @return the sqlServiceAccount value + */ + public String sqlServiceAccount() { + return this.sqlServiceAccount; + } + + /** + * Set account name under which SQL service will run on all participating SQL virtual machines in the cluster. + * + * @param sqlServiceAccount the sqlServiceAccount value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withSqlServiceAccount(String sqlServiceAccount) { + this.sqlServiceAccount = sqlServiceAccount; + return this; + } + + /** + * Get optional path for fileshare witness. + * + * @return the fileShareWitnessPath value + */ + public String fileShareWitnessPath() { + return this.fileShareWitnessPath; + } + + /** + * Set optional path for fileshare witness. + * + * @param fileShareWitnessPath the fileShareWitnessPath value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withFileShareWitnessPath(String fileShareWitnessPath) { + this.fileShareWitnessPath = fileShareWitnessPath; + return this; + } + + /** + * Get fully qualified ARM resource id of the witness storage account. + * + * @return the storageAccountUrl value + */ + public String storageAccountUrl() { + return this.storageAccountUrl; + } + + /** + * Set fully qualified ARM resource id of the witness storage account. + * + * @param storageAccountUrl the storageAccountUrl value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withStorageAccountUrl(String storageAccountUrl) { + this.storageAccountUrl = storageAccountUrl; + return this; + } + + /** + * Get primary key of the witness storage account. + * + * @return the storageAccountPrimaryKey value + */ + public String storageAccountPrimaryKey() { + return this.storageAccountPrimaryKey; + } + + /** + * Set primary key of the witness storage account. + * + * @param storageAccountPrimaryKey the storageAccountPrimaryKey value to set + * @return the WsfcDomainProfile object itself. + */ + public WsfcDomainProfile withStorageAccountPrimaryKey(String storageAccountPrimaryKey) { + this.storageAccountPrimaryKey = storageAccountPrimaryKey; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerImpl.java new file mode 100644 index 0000000000000..82c1128a13be3 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerImpl.java @@ -0,0 +1,145 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListener; +import com.microsoft.azure.arm.model.implementation.CreatableUpdatableImpl; +import rx.Observable; +import java.util.List; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.LoadBalancerConfiguration; + +class AvailabilityGroupListenerImpl extends CreatableUpdatableImpl implements AvailabilityGroupListener, AvailabilityGroupListener.Definition, AvailabilityGroupListener.Update { + private final SqlVirtualMachineManager manager; + private String resourceGroupName; + private String sqlVirtualMachineGroupName; + private String availabilityGroupListenerName; + + AvailabilityGroupListenerImpl(String name, SqlVirtualMachineManager manager) { + super(name, new AvailabilityGroupListenerInner()); + this.manager = manager; + // Set resource name + this.availabilityGroupListenerName = name; + // + } + + AvailabilityGroupListenerImpl(AvailabilityGroupListenerInner inner, SqlVirtualMachineManager manager) { + super(inner.name(), inner); + this.manager = manager; + // Set resource name + this.availabilityGroupListenerName = inner.name(); + // set resource ancestor and positional variables + this.resourceGroupName = IdParsingUtils.getValueFromIdByName(inner.id(), "resourceGroups"); + this.sqlVirtualMachineGroupName = IdParsingUtils.getValueFromIdByName(inner.id(), "sqlVirtualMachineGroups"); + this.availabilityGroupListenerName = IdParsingUtils.getValueFromIdByName(inner.id(), "availabilityGroupListeners"); + // + } + + @Override + public SqlVirtualMachineManager manager() { + return this.manager; + } + + @Override + public Observable createResourceAsync() { + AvailabilityGroupListenersInner client = this.manager().inner().availabilityGroupListeners(); + return client.createOrUpdateAsync(this.resourceGroupName, this.sqlVirtualMachineGroupName, this.availabilityGroupListenerName, this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + AvailabilityGroupListenersInner client = this.manager().inner().availabilityGroupListeners(); + return client.createOrUpdateAsync(this.resourceGroupName, this.sqlVirtualMachineGroupName, this.availabilityGroupListenerName, this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + AvailabilityGroupListenersInner client = this.manager().inner().availabilityGroupListeners(); + return client.getAsync(this.resourceGroupName, this.sqlVirtualMachineGroupName, this.availabilityGroupListenerName); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + + @Override + public String availabilityGroupName() { + return this.inner().availabilityGroupName(); + } + + @Override + public Boolean createDefaultAvailabilityGroupIfNotExist() { + return this.inner().createDefaultAvailabilityGroupIfNotExist(); + } + + @Override + public String id() { + return this.inner().id(); + } + + @Override + public List loadBalancerConfigurations() { + return this.inner().loadBalancerConfigurations(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public Integer port() { + return this.inner().port(); + } + + @Override + public String provisioningState() { + return this.inner().provisioningState(); + } + + @Override + public String type() { + return this.inner().type(); + } + + @Override + public AvailabilityGroupListenerImpl withExistingSqlVirtualMachineGroup(String resourceGroupName, String sqlVirtualMachineGroupName) { + this.resourceGroupName = resourceGroupName; + this.sqlVirtualMachineGroupName = sqlVirtualMachineGroupName; + return this; + } + + @Override + public AvailabilityGroupListenerImpl withAvailabilityGroupName(String availabilityGroupName) { + this.inner().withAvailabilityGroupName(availabilityGroupName); + return this; + } + + @Override + public AvailabilityGroupListenerImpl withCreateDefaultAvailabilityGroupIfNotExist(Boolean createDefaultAvailabilityGroupIfNotExist) { + this.inner().withCreateDefaultAvailabilityGroupIfNotExist(createDefaultAvailabilityGroupIfNotExist); + return this; + } + + @Override + public AvailabilityGroupListenerImpl withLoadBalancerConfigurations(List loadBalancerConfigurations) { + this.inner().withLoadBalancerConfigurations(loadBalancerConfigurations); + return this; + } + + @Override + public AvailabilityGroupListenerImpl withPort(Integer port) { + this.inner().withPort(port); + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerInner.java new file mode 100644 index 0000000000000..d792e8f6bf632 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenerInner.java @@ -0,0 +1,141 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import java.util.List; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.LoadBalancerConfiguration; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.rest.serializer.JsonFlatten; +import com.microsoft.azure.ProxyResource; + +/** + * A SQL Server availability group listener. + */ +@JsonFlatten +public class AvailabilityGroupListenerInner extends ProxyResource { + /** + * Provisioning state to track the async operation status. + */ + @JsonProperty(value = "properties.provisioningState", access = JsonProperty.Access.WRITE_ONLY) + private String provisioningState; + + /** + * Name of the availability group. + */ + @JsonProperty(value = "properties.availabilityGroupName") + private String availabilityGroupName; + + /** + * List of load balancer configurations for an availability group listener. + */ + @JsonProperty(value = "properties.loadBalancerConfigurations") + private List loadBalancerConfigurations; + + /** + * Create a default availability group if it does not exist. + */ + @JsonProperty(value = "properties.createDefaultAvailabilityGroupIfNotExist") + private Boolean createDefaultAvailabilityGroupIfNotExist; + + /** + * Listener port. + */ + @JsonProperty(value = "properties.port") + private Integer port; + + /** + * Get provisioning state to track the async operation status. + * + * @return the provisioningState value + */ + public String provisioningState() { + return this.provisioningState; + } + + /** + * Get name of the availability group. + * + * @return the availabilityGroupName value + */ + public String availabilityGroupName() { + return this.availabilityGroupName; + } + + /** + * Set name of the availability group. + * + * @param availabilityGroupName the availabilityGroupName value to set + * @return the AvailabilityGroupListenerInner object itself. + */ + public AvailabilityGroupListenerInner withAvailabilityGroupName(String availabilityGroupName) { + this.availabilityGroupName = availabilityGroupName; + return this; + } + + /** + * Get list of load balancer configurations for an availability group listener. + * + * @return the loadBalancerConfigurations value + */ + public List loadBalancerConfigurations() { + return this.loadBalancerConfigurations; + } + + /** + * Set list of load balancer configurations for an availability group listener. + * + * @param loadBalancerConfigurations the loadBalancerConfigurations value to set + * @return the AvailabilityGroupListenerInner object itself. + */ + public AvailabilityGroupListenerInner withLoadBalancerConfigurations(List loadBalancerConfigurations) { + this.loadBalancerConfigurations = loadBalancerConfigurations; + return this; + } + + /** + * Get create a default availability group if it does not exist. + * + * @return the createDefaultAvailabilityGroupIfNotExist value + */ + public Boolean createDefaultAvailabilityGroupIfNotExist() { + return this.createDefaultAvailabilityGroupIfNotExist; + } + + /** + * Set create a default availability group if it does not exist. + * + * @param createDefaultAvailabilityGroupIfNotExist the createDefaultAvailabilityGroupIfNotExist value to set + * @return the AvailabilityGroupListenerInner object itself. + */ + public AvailabilityGroupListenerInner withCreateDefaultAvailabilityGroupIfNotExist(Boolean createDefaultAvailabilityGroupIfNotExist) { + this.createDefaultAvailabilityGroupIfNotExist = createDefaultAvailabilityGroupIfNotExist; + return this; + } + + /** + * Get listener port. + * + * @return the port value + */ + public Integer port() { + return this.port; + } + + /** + * Set listener port. + * + * @param port the port value to set + * @return the AvailabilityGroupListenerInner object itself. + */ + public AvailabilityGroupListenerInner withPort(Integer port) { + this.port = port; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersImpl.java new file mode 100644 index 0000000000000..c0b696454bcbe --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersImpl.java @@ -0,0 +1,85 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners; +import rx.Completable; +import rx.Observable; +import rx.functions.Func1; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListener; + +class AvailabilityGroupListenersImpl extends WrapperImpl implements AvailabilityGroupListeners { + private final SqlVirtualMachineManager manager; + + AvailabilityGroupListenersImpl(SqlVirtualMachineManager manager) { + super(manager.inner().availabilityGroupListeners()); + this.manager = manager; + } + + public SqlVirtualMachineManager manager() { + return this.manager; + } + + @Override + public AvailabilityGroupListenerImpl define(String name) { + return wrapModel(name); + } + + private AvailabilityGroupListenerImpl wrapModel(AvailabilityGroupListenerInner inner) { + return new AvailabilityGroupListenerImpl(inner, manager()); + } + + private AvailabilityGroupListenerImpl wrapModel(String name) { + return new AvailabilityGroupListenerImpl(name, this.manager()); + } + + @Override + public Observable listByGroupAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName) { + AvailabilityGroupListenersInner client = this.inner(); + return client.listByGroupAsync(resourceGroupName, sqlVirtualMachineGroupName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public AvailabilityGroupListener call(AvailabilityGroupListenerInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public Observable getAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + AvailabilityGroupListenersInner client = this.inner(); + return client.getAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName) + .flatMap(new Func1>() { + @Override + public Observable call(AvailabilityGroupListenerInner inner) { + if (inner == null) { + return Observable.empty(); + } else { + return Observable.just((AvailabilityGroupListener)wrapModel(inner)); + } + } + }); + } + + @Override + public Completable deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + AvailabilityGroupListenersInner client = this.inner(); + return client.deleteAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).toCompletable(); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersInner.java new file mode 100644 index 0000000000000..a2c200244257e --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/AvailabilityGroupListenersInner.java @@ -0,0 +1,776 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in AvailabilityGroupListeners. + */ +public class AvailabilityGroupListenersInner { + /** The Retrofit service to perform REST calls. */ + private AvailabilityGroupListenersService service; + /** The service client containing this operation class. */ + private SqlVirtualMachineManagementClientImpl client; + + /** + * Initializes an instance of AvailabilityGroupListenersInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public AvailabilityGroupListenersInner(Retrofit retrofit, SqlVirtualMachineManagementClientImpl client) { + this.service = retrofit.create(AvailabilityGroupListenersService.class); + this.client = client; + } + + /** + * The interface defining all the services for AvailabilityGroupListeners to be + * used by Retrofit to perform actually REST calls. + */ + interface AvailabilityGroupListenersService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners get" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners/{availabilityGroupListenerName}") + Observable> get(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("availabilityGroupListenerName") String availabilityGroupListenerName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners createOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners/{availabilityGroupListenerName}") + Observable> createOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("availabilityGroupListenerName") String availabilityGroupListenerName, @Path("subscriptionId") String subscriptionId, @Body AvailabilityGroupListenerInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners beginCreateOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners/{availabilityGroupListenerName}") + Observable> beginCreateOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("availabilityGroupListenerName") String availabilityGroupListenerName, @Path("subscriptionId") String subscriptionId, @Body AvailabilityGroupListenerInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners delete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners/{availabilityGroupListenerName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("availabilityGroupListenerName") String availabilityGroupListenerName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners beginDelete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners/{availabilityGroupListenerName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("availabilityGroupListenerName") String availabilityGroupListenerName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners listByGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}/availabilityGroupListeners") + Observable> listByGroup(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners listByGroupNext" }) + @GET + Observable> listByGroupNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AvailabilityGroupListenerInner object if successful. + */ + public AvailabilityGroupListenerInner get(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + return getWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).toBlocking().single().body(); + } + + /** + * Gets an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName), serviceCallback); + } + + /** + * Gets an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AvailabilityGroupListenerInner object + */ + public Observable getAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + return getWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).map(new Func1, AvailabilityGroupListenerInner>() { + @Override + public AvailabilityGroupListenerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AvailabilityGroupListenerInner object + */ + public Observable> getWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (availabilityGroupListenerName == null) { + throw new IllegalArgumentException("Parameter availabilityGroupListenerName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.get(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AvailabilityGroupListenerInner object if successful. + */ + public AvailabilityGroupListenerInner createOrUpdate(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters).toBlocking().last().body(); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters), serviceCallback); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters).map(new Func1, AvailabilityGroupListenerInner>() { + @Override + public AvailabilityGroupListenerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (availabilityGroupListenerName == null) { + throw new IllegalArgumentException("Parameter availabilityGroupListenerName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + Observable> observable = service.createOrUpdate(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the AvailabilityGroupListenerInner object if successful. + */ + public AvailabilityGroupListenerInner beginCreateOrUpdate(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters).toBlocking().single().body(); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters), serviceCallback); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AvailabilityGroupListenerInner object + */ + public Observable beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, parameters).map(new Func1, AvailabilityGroupListenerInner>() { + @Override + public AvailabilityGroupListenerInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param parameters The availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the AvailabilityGroupListenerInner object + */ + public Observable> beginCreateOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, AvailabilityGroupListenerInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (availabilityGroupListenerName == null) { + throw new IllegalArgumentException("Parameter availabilityGroupListenerName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + return service.beginCreateOrUpdate(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateOrUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateOrUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).toBlocking().last().body(); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName), serviceCallback); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + return deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (availabilityGroupListenerName == null) { + throw new IllegalArgumentException("Parameter availabilityGroupListenerName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).toBlocking().single().body(); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName), serviceCallback); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + return beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes an availability group listener. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param availabilityGroupListenerName Name of the availability group listener. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, String availabilityGroupListenerName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (availabilityGroupListenerName == null) { + throw new IllegalArgumentException("Parameter availabilityGroupListenerName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(resourceGroupName, sqlVirtualMachineGroupName, availabilityGroupListenerName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<AvailabilityGroupListenerInner> object if successful. + */ + public PagedList listByGroup(final String resourceGroupName, final String sqlVirtualMachineGroupName) { + ServiceResponse> response = listByGroupSinglePageAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByGroupAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByGroupSinglePageAsync(resourceGroupName, sqlVirtualMachineGroupName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AvailabilityGroupListenerInner> object + */ + public Observable> listByGroupAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName) { + return listByGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AvailabilityGroupListenerInner> object + */ + public Observable>> listByGroupWithServiceResponseAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName) { + return listByGroupSinglePageAsync(resourceGroupName, sqlVirtualMachineGroupName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + ServiceResponse> * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + ServiceResponse> * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<AvailabilityGroupListenerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByGroupSinglePageAsync(final String resourceGroupName, final String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByGroup(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByGroupDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<AvailabilityGroupListenerInner> object if successful. + */ + public PagedList listByGroupNext(final String nextPageLink) { + ServiceResponse> response = listByGroupNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByGroupNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByGroupNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AvailabilityGroupListenerInner> object + */ + public Observable> listByGroupNextAsync(final String nextPageLink) { + return listByGroupNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<AvailabilityGroupListenerInner> object + */ + public Observable>> listByGroupNextWithServiceResponseAsync(final String nextPageLink) { + return listByGroupNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Lists all availability group listeners in a SQL virtual machine group. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<AvailabilityGroupListenerInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByGroupNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByGroupNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByGroupNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByGroupNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/IdParsingUtils.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/IdParsingUtils.java new file mode 100644 index 0000000000000..9c9b8833f90c8 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/IdParsingUtils.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; +import java.util.Arrays; +import java.util.Iterator; + +class IdParsingUtils { + public static String getValueFromIdByName(String id, String name) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (part.equalsIgnoreCase(name)) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + } + return null; + } + + public static String getValueFromIdByPosition(String id, int pos) { + if (id == null) { + return null; + } + Iterable iterable = Arrays.asList(id.split("/")); + Iterator itr = iterable.iterator(); + int index = 0; + while (itr.hasNext()) { + String part = itr.next(); + if (part != null && part.trim() != "") { + if (index == pos) { + if (itr.hasNext()) { + return itr.next(); + } else { + return null; + } + } + } + index++; + } + return null; + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationImpl.java new file mode 100644 index 0000000000000..794374f8194fd --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationImpl.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operation; +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.OperationDisplay; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.OperationOrigin; +import java.util.Map; + +class OperationImpl extends WrapperImpl implements Operation { + private final SqlVirtualMachineManager manager; + OperationImpl(OperationInner inner, SqlVirtualMachineManager manager) { + super(inner); + this.manager = manager; + } + + @Override + public SqlVirtualMachineManager manager() { + return this.manager; + } + + @Override + public OperationDisplay display() { + return this.inner().display(); + } + + @Override + public String name() { + return this.inner().name(); + } + + @Override + public OperationOrigin origin() { + return this.inner().origin(); + } + + @Override + public Map properties() { + return this.inner().properties(); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationInner.java new file mode 100644 index 0000000000000..607ed9dd61848 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationInner.java @@ -0,0 +1,82 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.OperationDisplay; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.OperationOrigin; +import java.util.Map; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * SQL REST API operation definition. + */ +public class OperationInner { + /** + * The name of the operation being performed on this particular object. + */ + @JsonProperty(value = "name", access = JsonProperty.Access.WRITE_ONLY) + private String name; + + /** + * The localized display information for this particular operation / + * action. + */ + @JsonProperty(value = "display", access = JsonProperty.Access.WRITE_ONLY) + private OperationDisplay display; + + /** + * The intended executor of the operation. Possible values include: 'user', + * 'system'. + */ + @JsonProperty(value = "origin", access = JsonProperty.Access.WRITE_ONLY) + private OperationOrigin origin; + + /** + * Additional descriptions for the operation. + */ + @JsonProperty(value = "properties", access = JsonProperty.Access.WRITE_ONLY) + private Map properties; + + /** + * Get the name of the operation being performed on this particular object. + * + * @return the name value + */ + public String name() { + return this.name; + } + + /** + * Get the localized display information for this particular operation / action. + * + * @return the display value + */ + public OperationDisplay display() { + return this.display; + } + + /** + * Get the intended executor of the operation. Possible values include: 'user', 'system'. + * + * @return the origin value + */ + public OperationOrigin origin() { + return this.origin; + } + + /** + * Get additional descriptions for the operation. + * + * @return the properties value + */ + public Map properties() { + return this.properties; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsImpl.java new file mode 100644 index 0000000000000..79d67315bea7c --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsImpl.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * abc + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.model.implementation.WrapperImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operations; +import rx.functions.Func1; +import rx.Observable; +import com.microsoft.azure.Page; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operation; + +class OperationsImpl extends WrapperImpl implements Operations { + private final SqlVirtualMachineManager manager; + + OperationsImpl(SqlVirtualMachineManager manager) { + super(manager.inner().operations()); + this.manager = manager; + } + + public SqlVirtualMachineManager manager() { + return this.manager; + } + + @Override + public Observable listAsync() { + OperationsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public Operation call(OperationInner inner) { + return new OperationImpl(inner, manager()); + } + }); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsInner.java new file mode 100644 index 0000000000000..b6c8ff825ff37 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/OperationsInner.java @@ -0,0 +1,283 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import java.io.IOException; +import java.util.List; +import okhttp3.ResponseBody; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in Operations. + */ +public class OperationsInner { + /** The Retrofit service to perform REST calls. */ + private OperationsService service; + /** The service client containing this operation class. */ + private SqlVirtualMachineManagementClientImpl client; + + /** + * Initializes an instance of OperationsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public OperationsInner(Retrofit retrofit, SqlVirtualMachineManagementClientImpl client) { + this.service = retrofit.create(OperationsService.class); + this.client = client; + } + + /** + * The interface defining all the services for Operations to be + * used by Retrofit to perform actually REST calls. + */ + interface OperationsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operations list" }) + @GET("providers/Microsoft.SqlVirtualMachine/operations") + Observable> list(@Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operations listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<OperationInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<OperationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<OperationInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Lists all of the available SQL Rest API operations. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<OperationInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Lists all of the available SQL Rest API operations. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<OperationInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/PageImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/PageImpl.java new file mode 100644 index 0000000000000..45180da2843b9 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/PageImpl.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.azure.Page; +import java.util.List; + +/** + * An instance of this class defines a page of Azure resources and a link to + * get the next page of resources, if any. + * + * @param type of Azure resource + */ +public class PageImpl implements Page { + /** + * The link to the next page. + */ + @JsonProperty("nextLink") + private String nextPageLink; + + /** + * The list of items. + */ + @JsonProperty("value") + private List items; + + /** + * Gets the link to the next page. + * + * @return the link to the next page. + */ + @Override + public String nextPageLink() { + return this.nextPageLink; + } + + /** + * Gets the list of items. + * + * @return the list of items in {@link List}. + */ + @Override + public List items() { + return items; + } + + /** + * Sets the link to the next page. + * + * @param nextPageLink the link to the next page. + * @return this Page object itself. + */ + public PageImpl setNextPageLink(String nextPageLink) { + this.nextPageLink = nextPageLink; + return this; + } + + /** + * Sets the list of items. + * + * @param items the list of items in {@link List}. + * @return this Page object itself. + */ + public PageImpl setItems(List items) { + this.items = items; + return this; + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupImpl.java new file mode 100644 index 0000000000000..65b92d76f1754 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupImpl.java @@ -0,0 +1,104 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.resources.models.implementation.GroupableResourceCoreImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroup; +import rx.Observable; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVmGroupImageSku; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ScaleType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ClusterManagerType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ClusterConfiguration; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.WsfcDomainProfile; + +class SqlVirtualMachineGroupImpl extends GroupableResourceCoreImpl implements SqlVirtualMachineGroup, SqlVirtualMachineGroup.Definition, SqlVirtualMachineGroup.Update { + SqlVirtualMachineGroupImpl(String name, SqlVirtualMachineGroupInner inner, SqlVirtualMachineManager manager) { + super(name, inner, manager); + } + + @Override + public Observable createResourceAsync() { + SqlVirtualMachineGroupsInner client = this.manager().inner().sqlVirtualMachineGroups(); + return client.createOrUpdateAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + SqlVirtualMachineGroupsInner client = this.manager().inner().sqlVirtualMachineGroups(); + return client.createOrUpdateAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + SqlVirtualMachineGroupsInner client = this.manager().inner().sqlVirtualMachineGroups(); + return client.getByResourceGroupAsync(this.resourceGroupName(), this.name()); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + + @Override + public ClusterConfiguration clusterConfiguration() { + return this.inner().clusterConfiguration(); + } + + @Override + public ClusterManagerType clusterManagerType() { + return this.inner().clusterManagerType(); + } + + @Override + public String provisioningState() { + return this.inner().provisioningState(); + } + + @Override + public ScaleType scaleType() { + return this.inner().scaleType(); + } + + @Override + public String sqlImageOffer() { + return this.inner().sqlImageOffer(); + } + + @Override + public SqlVmGroupImageSku sqlImageSku() { + return this.inner().sqlImageSku(); + } + + @Override + public WsfcDomainProfile wsfcDomainProfile() { + return this.inner().wsfcDomainProfile(); + } + + @Override + public SqlVirtualMachineGroupImpl withSqlImageOffer(String sqlImageOffer) { + this.inner().withSqlImageOffer(sqlImageOffer); + return this; + } + + @Override + public SqlVirtualMachineGroupImpl withSqlImageSku(SqlVmGroupImageSku sqlImageSku) { + this.inner().withSqlImageSku(sqlImageSku); + return this; + } + + @Override + public SqlVirtualMachineGroupImpl withWsfcDomainProfile(WsfcDomainProfile wsfcDomainProfile) { + this.inner().withWsfcDomainProfile(wsfcDomainProfile); + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupInner.java new file mode 100644 index 0000000000000..0732ac1d959ec --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupInner.java @@ -0,0 +1,165 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVmGroupImageSku; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ScaleType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ClusterManagerType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ClusterConfiguration; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.WsfcDomainProfile; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.rest.serializer.JsonFlatten; +import com.microsoft.azure.Resource; + +/** + * A SQL virtual machine group. + */ +@JsonFlatten +public class SqlVirtualMachineGroupInner extends Resource { + /** + * Provisioning state to track the async operation status. + */ + @JsonProperty(value = "properties.provisioningState", access = JsonProperty.Access.WRITE_ONLY) + private String provisioningState; + + /** + * SQL image offer. Examples may include SQL2016-WS2016, SQL2017-WS2016. + */ + @JsonProperty(value = "properties.sqlImageOffer") + private String sqlImageOffer; + + /** + * SQL image sku. Possible values include: 'Developer', 'Enterprise'. + */ + @JsonProperty(value = "properties.sqlImageSku") + private SqlVmGroupImageSku sqlImageSku; + + /** + * Scale type. Possible values include: 'HA'. + */ + @JsonProperty(value = "properties.scaleType", access = JsonProperty.Access.WRITE_ONLY) + private ScaleType scaleType; + + /** + * Type of cluster manager: Windows Server Failover Cluster (WSFC), implied + * by the scale type of the group and the OS type. Possible values include: + * 'WSFC'. + */ + @JsonProperty(value = "properties.clusterManagerType", access = JsonProperty.Access.WRITE_ONLY) + private ClusterManagerType clusterManagerType; + + /** + * Cluster type. Possible values include: 'Domainful'. + */ + @JsonProperty(value = "properties.clusterConfiguration", access = JsonProperty.Access.WRITE_ONLY) + private ClusterConfiguration clusterConfiguration; + + /** + * Cluster Active Directory domain profile. + */ + @JsonProperty(value = "properties.wsfcDomainProfile") + private WsfcDomainProfile wsfcDomainProfile; + + /** + * Get provisioning state to track the async operation status. + * + * @return the provisioningState value + */ + public String provisioningState() { + return this.provisioningState; + } + + /** + * Get sQL image offer. Examples may include SQL2016-WS2016, SQL2017-WS2016. + * + * @return the sqlImageOffer value + */ + public String sqlImageOffer() { + return this.sqlImageOffer; + } + + /** + * Set sQL image offer. Examples may include SQL2016-WS2016, SQL2017-WS2016. + * + * @param sqlImageOffer the sqlImageOffer value to set + * @return the SqlVirtualMachineGroupInner object itself. + */ + public SqlVirtualMachineGroupInner withSqlImageOffer(String sqlImageOffer) { + this.sqlImageOffer = sqlImageOffer; + return this; + } + + /** + * Get sQL image sku. Possible values include: 'Developer', 'Enterprise'. + * + * @return the sqlImageSku value + */ + public SqlVmGroupImageSku sqlImageSku() { + return this.sqlImageSku; + } + + /** + * Set sQL image sku. Possible values include: 'Developer', 'Enterprise'. + * + * @param sqlImageSku the sqlImageSku value to set + * @return the SqlVirtualMachineGroupInner object itself. + */ + public SqlVirtualMachineGroupInner withSqlImageSku(SqlVmGroupImageSku sqlImageSku) { + this.sqlImageSku = sqlImageSku; + return this; + } + + /** + * Get scale type. Possible values include: 'HA'. + * + * @return the scaleType value + */ + public ScaleType scaleType() { + return this.scaleType; + } + + /** + * Get type of cluster manager: Windows Server Failover Cluster (WSFC), implied by the scale type of the group and the OS type. Possible values include: 'WSFC'. + * + * @return the clusterManagerType value + */ + public ClusterManagerType clusterManagerType() { + return this.clusterManagerType; + } + + /** + * Get cluster type. Possible values include: 'Domainful'. + * + * @return the clusterConfiguration value + */ + public ClusterConfiguration clusterConfiguration() { + return this.clusterConfiguration; + } + + /** + * Get cluster Active Directory domain profile. + * + * @return the wsfcDomainProfile value + */ + public WsfcDomainProfile wsfcDomainProfile() { + return this.wsfcDomainProfile; + } + + /** + * Set cluster Active Directory domain profile. + * + * @param wsfcDomainProfile the wsfcDomainProfile value to set + * @return the SqlVirtualMachineGroupInner object itself. + */ + public SqlVirtualMachineGroupInner withWsfcDomainProfile(WsfcDomainProfile wsfcDomainProfile) { + this.wsfcDomainProfile = wsfcDomainProfile; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsImpl.java new file mode 100644 index 0000000000000..f3e502ef1b960 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsImpl.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * def + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.resources.collection.implementation.GroupableResourcesCoreImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroup; +import rx.Observable; +import rx.Completable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import com.microsoft.azure.arm.resources.ResourceUtilsCore; +import com.microsoft.azure.arm.utils.RXMapper; +import rx.functions.Func1; +import com.microsoft.azure.PagedList; +import com.microsoft.azure.Page; + +class SqlVirtualMachineGroupsImpl extends GroupableResourcesCoreImpl implements SqlVirtualMachineGroups { + protected SqlVirtualMachineGroupsImpl(SqlVirtualMachineManager manager) { + super(manager.inner().sqlVirtualMachineGroups(), manager); + } + + @Override + protected Observable getInnerAsync(String resourceGroupName, String name) { + SqlVirtualMachineGroupsInner client = this.inner(); + return client.getByResourceGroupAsync(resourceGroupName, name); + } + + @Override + protected Completable deleteInnerAsync(String resourceGroupName, String name) { + SqlVirtualMachineGroupsInner client = this.inner(); + return client.deleteAsync(resourceGroupName, name).toCompletable(); + } + + @Override + public Observable deleteByIdsAsync(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Observable.empty(); + } + Collection> observables = new ArrayList<>(); + for (String id : ids) { + final String resourceGroupName = ResourceUtilsCore.groupFromResourceId(id); + final String name = ResourceUtilsCore.nameFromResourceId(id); + Observable o = RXMapper.map(this.inner().deleteAsync(resourceGroupName, name), id); + observables.add(o); + } + return Observable.mergeDelayError(observables); + } + + @Override + public Observable deleteByIdsAsync(String...ids) { + return this.deleteByIdsAsync(new ArrayList(Arrays.asList(ids))); + } + + @Override + public void deleteByIds(Collection ids) { + if (ids != null && !ids.isEmpty()) { + this.deleteByIdsAsync(ids).toBlocking().last(); + } + } + + @Override + public void deleteByIds(String...ids) { + this.deleteByIds(new ArrayList(Arrays.asList(ids))); + } + + @Override + public PagedList listByResourceGroup(String resourceGroupName) { + SqlVirtualMachineGroupsInner client = this.inner(); + return this.wrapList(client.listByResourceGroup(resourceGroupName)); + } + + @Override + public Observable listByResourceGroupAsync(String resourceGroupName) { + SqlVirtualMachineGroupsInner client = this.inner(); + return client.listByResourceGroupAsync(resourceGroupName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public SqlVirtualMachineGroup call(SqlVirtualMachineGroupInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public PagedList list() { + SqlVirtualMachineGroupsInner client = this.inner(); + return this.wrapList(client.list()); + } + + @Override + public Observable listAsync() { + SqlVirtualMachineGroupsInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public SqlVirtualMachineGroup call(SqlVirtualMachineGroupInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public SqlVirtualMachineGroupImpl define(String name) { + return wrapModel(name); + } + + @Override + protected SqlVirtualMachineGroupImpl wrapModel(SqlVirtualMachineGroupInner inner) { + return new SqlVirtualMachineGroupImpl(inner.name(), inner, manager()); + } + + @Override + protected SqlVirtualMachineGroupImpl wrapModel(String name) { + return new SqlVirtualMachineGroupImpl(name, new SqlVirtualMachineGroupInner(), this.manager()); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsInner.java new file mode 100644 index 0000000000000..8978c000569da --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineGroupsInner.java @@ -0,0 +1,1295 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsGet; +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import com.microsoft.azure.arm.collection.InnerSupportsListing; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroupUpdate; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in SqlVirtualMachineGroups. + */ +public class SqlVirtualMachineGroupsInner implements InnerSupportsGet, InnerSupportsDelete, InnerSupportsListing { + /** The Retrofit service to perform REST calls. */ + private SqlVirtualMachineGroupsService service; + /** The service client containing this operation class. */ + private SqlVirtualMachineManagementClientImpl client; + + /** + * Initializes an instance of SqlVirtualMachineGroupsInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public SqlVirtualMachineGroupsInner(Retrofit retrofit, SqlVirtualMachineManagementClientImpl client) { + this.service = retrofit.create(SqlVirtualMachineGroupsService.class); + this.client = client; + } + + /** + * The interface defining all the services for SqlVirtualMachineGroups to be + * used by Retrofit to perform actually REST calls. + */ + interface SqlVirtualMachineGroupsService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups getByResourceGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}") + Observable> getByResourceGroup(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups createOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}") + Observable> createOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Body SqlVirtualMachineGroupInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups beginCreateOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}") + Observable> beginCreateOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Body SqlVirtualMachineGroupInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups delete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups beginDelete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups update" }) + @PATCH("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}") + Observable> update(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SqlVirtualMachineGroupUpdate parameters, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups beginUpdate" }) + @PATCH("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups/{sqlVirtualMachineGroupName}") + Observable> beginUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineGroupName") String sqlVirtualMachineGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SqlVirtualMachineGroupUpdate parameters, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups listByResourceGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups") + Observable> listByResourceGroup(@Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups list" }) + @GET("subscriptions/{subscriptionId}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachineGroups") + Observable> list(@Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups listByResourceGroupNext" }) + @GET + Observable> listByResourceGroupNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner getByResourceGroup(String resourceGroupName, String sqlVirtualMachineGroupName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().single().body(); + } + + /** + * Gets a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineGroupName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName), serviceCallback); + } + + /** + * Gets a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable> getByResourceGroupWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.getByResourceGroup(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getByResourceGroupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getByResourceGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner createOrUpdate(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters).toBlocking().last().body(); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters), serviceCallback); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + Observable> observable = service.createOrUpdate(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner beginCreateOrUpdate(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters).toBlocking().single().body(); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters), serviceCallback); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, parameters).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param parameters The SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable> beginCreateOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, SqlVirtualMachineGroupInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + return service.beginCreateOrUpdate(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateOrUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateOrUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String resourceGroupName, String sqlVirtualMachineGroupName) { + deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().last().body(); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName), serviceCallback); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + return deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String resourceGroupName, String sqlVirtualMachineGroupName) { + beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().single().body(); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName), serviceCallback); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + return beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SQL virtual machine group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner update(String resourceGroupName, String sqlVirtualMachineGroupName) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().last().body(); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName), serviceCallback); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final Map tags = null; + SqlVirtualMachineGroupUpdate parameters = new SqlVirtualMachineGroupUpdate(); + parameters.withTags(null); + Observable> observable = service.update(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner update(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags).toBlocking().last().body(); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags), serviceCallback); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(tags); + SqlVirtualMachineGroupUpdate parameters = new SqlVirtualMachineGroupUpdate(); + parameters.withTags(tags); + Observable> observable = service.update(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner beginUpdate(String resourceGroupName, String sqlVirtualMachineGroupName) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).toBlocking().single().body(); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName), serviceCallback); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final Map tags = null; + SqlVirtualMachineGroupUpdate parameters = new SqlVirtualMachineGroupUpdate(); + parameters.withTags(null); + return service.beginUpdate(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineGroupInner object if successful. + */ + public SqlVirtualMachineGroupInner beginUpdate(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags).toBlocking().single().body(); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags), serviceCallback); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineGroupName, tags).map(new Func1, SqlVirtualMachineGroupInner>() { + @Override + public SqlVirtualMachineGroupInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates SQL virtual machine group tags. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineGroupName Name of the SQL virtual machine group. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineGroupInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineGroupName, Map tags) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineGroupName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(tags); + SqlVirtualMachineGroupUpdate parameters = new SqlVirtualMachineGroupUpdate(); + parameters.withTags(tags); + return service.beginUpdate(resourceGroupName, sqlVirtualMachineGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineGroupInner> object if successful. + */ + public PagedList listByResourceGroup(final String resourceGroupName) { + ServiceResponse> response = listByResourceGroupSinglePageAsync(resourceGroupName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupAsync(final String resourceGroupName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupSinglePageAsync(resourceGroupName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable> listByResourceGroupAsync(final String resourceGroupName) { + return listByResourceGroupWithServiceResponseAsync(resourceGroupName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable>> listByResourceGroupWithServiceResponseAsync(final String resourceGroupName) { + return listByResourceGroupSinglePageAsync(resourceGroupName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + ServiceResponse> * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineGroupInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupSinglePageAsync(final String resourceGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByResourceGroup(resourceGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineGroupInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineGroupInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineGroupInner> object if successful. + */ + public PagedList listByResourceGroupNext(final String nextPageLink) { + ServiceResponse> response = listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable> listByResourceGroupNextAsync(final String nextPageLink) { + return listByResourceGroupNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable>> listByResourceGroupNextWithServiceResponseAsync(final String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a resource group. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineGroupInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByResourceGroupNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineGroupInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineGroupInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machine groups in a subscription. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineGroupInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineImpl.java new file mode 100644 index 0000000000000..6cbd713dff1b3 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineImpl.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.resources.models.implementation.GroupableResourceCoreImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachine; +import rx.Observable; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ResourceIdentity; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlServerLicenseType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlManagementMode; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlImageSku; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.WsfcDomainCredentials; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AutoPatchingSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AutoBackupSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.KeyVaultCredentialSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ServerConfigurationsManagementSettings; + +class SqlVirtualMachineImpl extends GroupableResourceCoreImpl implements SqlVirtualMachine, SqlVirtualMachine.Definition, SqlVirtualMachine.Update { + SqlVirtualMachineImpl(String name, SqlVirtualMachineInner inner, SqlVirtualMachineManager manager) { + super(name, inner, manager); + } + + @Override + public Observable createResourceAsync() { + SqlVirtualMachinesInner client = this.manager().inner().sqlVirtualMachines(); + return client.createOrUpdateAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + public Observable updateResourceAsync() { + SqlVirtualMachinesInner client = this.manager().inner().sqlVirtualMachines(); + return client.createOrUpdateAsync(this.resourceGroupName(), this.name(), this.inner()) + .map(innerToFluentMap(this)); + } + + @Override + protected Observable getInnerAsync() { + SqlVirtualMachinesInner client = this.manager().inner().sqlVirtualMachines(); + return client.getByResourceGroupAsync(this.resourceGroupName(), this.name()); + } + + @Override + public boolean isInCreateMode() { + return this.inner().id() == null; + } + + + @Override + public AutoBackupSettings autoBackupSettings() { + return this.inner().autoBackupSettings(); + } + + @Override + public AutoPatchingSettings autoPatchingSettings() { + return this.inner().autoPatchingSettings(); + } + + @Override + public ResourceIdentity identity() { + return this.inner().identity(); + } + + @Override + public KeyVaultCredentialSettings keyVaultCredentialSettings() { + return this.inner().keyVaultCredentialSettings(); + } + + @Override + public String provisioningState() { + return this.inner().provisioningState(); + } + + @Override + public ServerConfigurationsManagementSettings serverConfigurationsManagementSettings() { + return this.inner().serverConfigurationsManagementSettings(); + } + + @Override + public String sqlImageOffer() { + return this.inner().sqlImageOffer(); + } + + @Override + public SqlImageSku sqlImageSku() { + return this.inner().sqlImageSku(); + } + + @Override + public SqlManagementMode sqlManagement() { + return this.inner().sqlManagement(); + } + + @Override + public SqlServerLicenseType sqlServerLicenseType() { + return this.inner().sqlServerLicenseType(); + } + + @Override + public String sqlVirtualMachineGroupResourceId() { + return this.inner().sqlVirtualMachineGroupResourceId(); + } + + @Override + public String virtualMachineResourceId() { + return this.inner().virtualMachineResourceId(); + } + + @Override + public WsfcDomainCredentials wsfcDomainCredentials() { + return this.inner().wsfcDomainCredentials(); + } + + @Override + public SqlVirtualMachineImpl withAutoBackupSettings(AutoBackupSettings autoBackupSettings) { + this.inner().withAutoBackupSettings(autoBackupSettings); + return this; + } + + @Override + public SqlVirtualMachineImpl withAutoPatchingSettings(AutoPatchingSettings autoPatchingSettings) { + this.inner().withAutoPatchingSettings(autoPatchingSettings); + return this; + } + + @Override + public SqlVirtualMachineImpl withIdentity(ResourceIdentity identity) { + this.inner().withIdentity(identity); + return this; + } + + @Override + public SqlVirtualMachineImpl withKeyVaultCredentialSettings(KeyVaultCredentialSettings keyVaultCredentialSettings) { + this.inner().withKeyVaultCredentialSettings(keyVaultCredentialSettings); + return this; + } + + @Override + public SqlVirtualMachineImpl withServerConfigurationsManagementSettings(ServerConfigurationsManagementSettings serverConfigurationsManagementSettings) { + this.inner().withServerConfigurationsManagementSettings(serverConfigurationsManagementSettings); + return this; + } + + @Override + public SqlVirtualMachineImpl withSqlImageOffer(String sqlImageOffer) { + this.inner().withSqlImageOffer(sqlImageOffer); + return this; + } + + @Override + public SqlVirtualMachineImpl withSqlImageSku(SqlImageSku sqlImageSku) { + this.inner().withSqlImageSku(sqlImageSku); + return this; + } + + @Override + public SqlVirtualMachineImpl withSqlManagement(SqlManagementMode sqlManagement) { + this.inner().withSqlManagement(sqlManagement); + return this; + } + + @Override + public SqlVirtualMachineImpl withSqlServerLicenseType(SqlServerLicenseType sqlServerLicenseType) { + this.inner().withSqlServerLicenseType(sqlServerLicenseType); + return this; + } + + @Override + public SqlVirtualMachineImpl withSqlVirtualMachineGroupResourceId(String sqlVirtualMachineGroupResourceId) { + this.inner().withSqlVirtualMachineGroupResourceId(sqlVirtualMachineGroupResourceId); + return this; + } + + @Override + public SqlVirtualMachineImpl withVirtualMachineResourceId(String virtualMachineResourceId) { + this.inner().withVirtualMachineResourceId(virtualMachineResourceId); + return this; + } + + @Override + public SqlVirtualMachineImpl withWsfcDomainCredentials(WsfcDomainCredentials wsfcDomainCredentials) { + this.inner().withWsfcDomainCredentials(wsfcDomainCredentials); + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineInner.java new file mode 100644 index 0000000000000..7448ec5c2ab64 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineInner.java @@ -0,0 +1,362 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ResourceIdentity; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlServerLicenseType; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlManagementMode; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlImageSku; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.WsfcDomainCredentials; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AutoPatchingSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AutoBackupSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.KeyVaultCredentialSettings; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.ServerConfigurationsManagementSettings; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.microsoft.rest.serializer.JsonFlatten; +import com.microsoft.azure.Resource; + +/** + * A SQL virtual machine. + */ +@JsonFlatten +public class SqlVirtualMachineInner extends Resource { + /** + * Azure Active Directory identity of the server. + */ + @JsonProperty(value = "identity") + private ResourceIdentity identity; + + /** + * ARM Resource id of underlying virtual machine created from SQL + * marketplace image. + */ + @JsonProperty(value = "properties.virtualMachineResourceId") + private String virtualMachineResourceId; + + /** + * Provisioning state to track the async operation status. + */ + @JsonProperty(value = "properties.provisioningState", access = JsonProperty.Access.WRITE_ONLY) + private String provisioningState; + + /** + * SQL image offer. Examples include SQL2016-WS2016, SQL2017-WS2016. + */ + @JsonProperty(value = "properties.sqlImageOffer") + private String sqlImageOffer; + + /** + * SQL Server license type. Possible values include: 'PAYG', 'AHUB'. + */ + @JsonProperty(value = "properties.sqlServerLicenseType") + private SqlServerLicenseType sqlServerLicenseType; + + /** + * SQL Server Management type. Possible values include: 'Full', + * 'LightWeight', 'NoAgent'. + */ + @JsonProperty(value = "properties.sqlManagement") + private SqlManagementMode sqlManagement; + + /** + * SQL Server edition type. Possible values include: 'Developer', + * 'Express', 'Standard', 'Enterprise', 'Web'. + */ + @JsonProperty(value = "properties.sqlImageSku") + private SqlImageSku sqlImageSku; + + /** + * ARM resource id of the SQL virtual machine group this SQL virtual + * machine is or will be part of. + */ + @JsonProperty(value = "properties.sqlVirtualMachineGroupResourceId") + private String sqlVirtualMachineGroupResourceId; + + /** + * Domain credentials for setting up Windows Server Failover Cluster for + * SQL availability group. + */ + @JsonProperty(value = "properties.wsfcDomainCredentials") + private WsfcDomainCredentials wsfcDomainCredentials; + + /** + * Auto patching settings for applying critical security updates to SQL + * virtual machine. + */ + @JsonProperty(value = "properties.autoPatchingSettings") + private AutoPatchingSettings autoPatchingSettings; + + /** + * Auto backup settings for SQL Server. + */ + @JsonProperty(value = "properties.autoBackupSettings") + private AutoBackupSettings autoBackupSettings; + + /** + * Key vault credential settings. + */ + @JsonProperty(value = "properties.keyVaultCredentialSettings") + private KeyVaultCredentialSettings keyVaultCredentialSettings; + + /** + * SQL Server configuration management settings. + */ + @JsonProperty(value = "properties.serverConfigurationsManagementSettings") + private ServerConfigurationsManagementSettings serverConfigurationsManagementSettings; + + /** + * Get azure Active Directory identity of the server. + * + * @return the identity value + */ + public ResourceIdentity identity() { + return this.identity; + } + + /** + * Set azure Active Directory identity of the server. + * + * @param identity the identity value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withIdentity(ResourceIdentity identity) { + this.identity = identity; + return this; + } + + /** + * Get aRM Resource id of underlying virtual machine created from SQL marketplace image. + * + * @return the virtualMachineResourceId value + */ + public String virtualMachineResourceId() { + return this.virtualMachineResourceId; + } + + /** + * Set aRM Resource id of underlying virtual machine created from SQL marketplace image. + * + * @param virtualMachineResourceId the virtualMachineResourceId value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withVirtualMachineResourceId(String virtualMachineResourceId) { + this.virtualMachineResourceId = virtualMachineResourceId; + return this; + } + + /** + * Get provisioning state to track the async operation status. + * + * @return the provisioningState value + */ + public String provisioningState() { + return this.provisioningState; + } + + /** + * Get sQL image offer. Examples include SQL2016-WS2016, SQL2017-WS2016. + * + * @return the sqlImageOffer value + */ + public String sqlImageOffer() { + return this.sqlImageOffer; + } + + /** + * Set sQL image offer. Examples include SQL2016-WS2016, SQL2017-WS2016. + * + * @param sqlImageOffer the sqlImageOffer value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withSqlImageOffer(String sqlImageOffer) { + this.sqlImageOffer = sqlImageOffer; + return this; + } + + /** + * Get sQL Server license type. Possible values include: 'PAYG', 'AHUB'. + * + * @return the sqlServerLicenseType value + */ + public SqlServerLicenseType sqlServerLicenseType() { + return this.sqlServerLicenseType; + } + + /** + * Set sQL Server license type. Possible values include: 'PAYG', 'AHUB'. + * + * @param sqlServerLicenseType the sqlServerLicenseType value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withSqlServerLicenseType(SqlServerLicenseType sqlServerLicenseType) { + this.sqlServerLicenseType = sqlServerLicenseType; + return this; + } + + /** + * Get sQL Server Management type. Possible values include: 'Full', 'LightWeight', 'NoAgent'. + * + * @return the sqlManagement value + */ + public SqlManagementMode sqlManagement() { + return this.sqlManagement; + } + + /** + * Set sQL Server Management type. Possible values include: 'Full', 'LightWeight', 'NoAgent'. + * + * @param sqlManagement the sqlManagement value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withSqlManagement(SqlManagementMode sqlManagement) { + this.sqlManagement = sqlManagement; + return this; + } + + /** + * Get sQL Server edition type. Possible values include: 'Developer', 'Express', 'Standard', 'Enterprise', 'Web'. + * + * @return the sqlImageSku value + */ + public SqlImageSku sqlImageSku() { + return this.sqlImageSku; + } + + /** + * Set sQL Server edition type. Possible values include: 'Developer', 'Express', 'Standard', 'Enterprise', 'Web'. + * + * @param sqlImageSku the sqlImageSku value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withSqlImageSku(SqlImageSku sqlImageSku) { + this.sqlImageSku = sqlImageSku; + return this; + } + + /** + * Get aRM resource id of the SQL virtual machine group this SQL virtual machine is or will be part of. + * + * @return the sqlVirtualMachineGroupResourceId value + */ + public String sqlVirtualMachineGroupResourceId() { + return this.sqlVirtualMachineGroupResourceId; + } + + /** + * Set aRM resource id of the SQL virtual machine group this SQL virtual machine is or will be part of. + * + * @param sqlVirtualMachineGroupResourceId the sqlVirtualMachineGroupResourceId value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withSqlVirtualMachineGroupResourceId(String sqlVirtualMachineGroupResourceId) { + this.sqlVirtualMachineGroupResourceId = sqlVirtualMachineGroupResourceId; + return this; + } + + /** + * Get domain credentials for setting up Windows Server Failover Cluster for SQL availability group. + * + * @return the wsfcDomainCredentials value + */ + public WsfcDomainCredentials wsfcDomainCredentials() { + return this.wsfcDomainCredentials; + } + + /** + * Set domain credentials for setting up Windows Server Failover Cluster for SQL availability group. + * + * @param wsfcDomainCredentials the wsfcDomainCredentials value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withWsfcDomainCredentials(WsfcDomainCredentials wsfcDomainCredentials) { + this.wsfcDomainCredentials = wsfcDomainCredentials; + return this; + } + + /** + * Get auto patching settings for applying critical security updates to SQL virtual machine. + * + * @return the autoPatchingSettings value + */ + public AutoPatchingSettings autoPatchingSettings() { + return this.autoPatchingSettings; + } + + /** + * Set auto patching settings for applying critical security updates to SQL virtual machine. + * + * @param autoPatchingSettings the autoPatchingSettings value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withAutoPatchingSettings(AutoPatchingSettings autoPatchingSettings) { + this.autoPatchingSettings = autoPatchingSettings; + return this; + } + + /** + * Get auto backup settings for SQL Server. + * + * @return the autoBackupSettings value + */ + public AutoBackupSettings autoBackupSettings() { + return this.autoBackupSettings; + } + + /** + * Set auto backup settings for SQL Server. + * + * @param autoBackupSettings the autoBackupSettings value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withAutoBackupSettings(AutoBackupSettings autoBackupSettings) { + this.autoBackupSettings = autoBackupSettings; + return this; + } + + /** + * Get key vault credential settings. + * + * @return the keyVaultCredentialSettings value + */ + public KeyVaultCredentialSettings keyVaultCredentialSettings() { + return this.keyVaultCredentialSettings; + } + + /** + * Set key vault credential settings. + * + * @param keyVaultCredentialSettings the keyVaultCredentialSettings value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withKeyVaultCredentialSettings(KeyVaultCredentialSettings keyVaultCredentialSettings) { + this.keyVaultCredentialSettings = keyVaultCredentialSettings; + return this; + } + + /** + * Get sQL Server configuration management settings. + * + * @return the serverConfigurationsManagementSettings value + */ + public ServerConfigurationsManagementSettings serverConfigurationsManagementSettings() { + return this.serverConfigurationsManagementSettings; + } + + /** + * Set sQL Server configuration management settings. + * + * @param serverConfigurationsManagementSettings the serverConfigurationsManagementSettings value to set + * @return the SqlVirtualMachineInner object itself. + */ + public SqlVirtualMachineInner withServerConfigurationsManagementSettings(ServerConfigurationsManagementSettings serverConfigurationsManagementSettings) { + this.serverConfigurationsManagementSettings = serverConfigurationsManagementSettings; + return this; + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManagementClientImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManagementClientImpl.java new file mode 100644 index 0000000000000..529c508c8c780 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManagementClientImpl.java @@ -0,0 +1,238 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.AzureClient; +import com.microsoft.azure.AzureServiceClient; +import com.microsoft.rest.credentials.ServiceClientCredentials; +import com.microsoft.rest.RestClient; + +/** + * Initializes a new instance of the SqlVirtualMachineManagementClientImpl class. + */ +public class SqlVirtualMachineManagementClientImpl extends AzureServiceClient { + /** the {@link AzureClient} used for long running operations. */ + private AzureClient azureClient; + + /** + * Gets the {@link AzureClient} used for long running operations. + * @return the azure client; + */ + public AzureClient getAzureClient() { + return this.azureClient; + } + + /** Subscription ID that identifies an Azure subscription. */ + private String subscriptionId; + + /** + * Gets Subscription ID that identifies an Azure subscription. + * + * @return the subscriptionId value. + */ + public String subscriptionId() { + return this.subscriptionId; + } + + /** + * Sets Subscription ID that identifies an Azure subscription. + * + * @param subscriptionId the subscriptionId value. + * @return the service client itself + */ + public SqlVirtualMachineManagementClientImpl withSubscriptionId(String subscriptionId) { + this.subscriptionId = subscriptionId; + return this; + } + + /** API version to use for the request. */ + private String apiVersion; + + /** + * Gets API version to use for the request. + * + * @return the apiVersion value. + */ + public String apiVersion() { + return this.apiVersion; + } + + /** The preferred language for the response. */ + private String acceptLanguage; + + /** + * Gets The preferred language for the response. + * + * @return the acceptLanguage value. + */ + public String acceptLanguage() { + return this.acceptLanguage; + } + + /** + * Sets The preferred language for the response. + * + * @param acceptLanguage the acceptLanguage value. + * @return the service client itself + */ + public SqlVirtualMachineManagementClientImpl withAcceptLanguage(String acceptLanguage) { + this.acceptLanguage = acceptLanguage; + return this; + } + + /** The retry timeout in seconds for Long Running Operations. Default value is 30. */ + private int longRunningOperationRetryTimeout; + + /** + * Gets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @return the longRunningOperationRetryTimeout value. + */ + public int longRunningOperationRetryTimeout() { + return this.longRunningOperationRetryTimeout; + } + + /** + * Sets The retry timeout in seconds for Long Running Operations. Default value is 30. + * + * @param longRunningOperationRetryTimeout the longRunningOperationRetryTimeout value. + * @return the service client itself + */ + public SqlVirtualMachineManagementClientImpl withLongRunningOperationRetryTimeout(int longRunningOperationRetryTimeout) { + this.longRunningOperationRetryTimeout = longRunningOperationRetryTimeout; + return this; + } + + /** Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. */ + private boolean generateClientRequestId; + + /** + * Gets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @return the generateClientRequestId value. + */ + public boolean generateClientRequestId() { + return this.generateClientRequestId; + } + + /** + * Sets Whether a unique x-ms-client-request-id should be generated. When set to true a unique x-ms-client-request-id value is generated and included in each request. Default is true. + * + * @param generateClientRequestId the generateClientRequestId value. + * @return the service client itself + */ + public SqlVirtualMachineManagementClientImpl withGenerateClientRequestId(boolean generateClientRequestId) { + this.generateClientRequestId = generateClientRequestId; + return this; + } + + /** + * The AvailabilityGroupListenersInner object to access its operations. + */ + private AvailabilityGroupListenersInner availabilityGroupListeners; + + /** + * Gets the AvailabilityGroupListenersInner object to access its operations. + * @return the AvailabilityGroupListenersInner object. + */ + public AvailabilityGroupListenersInner availabilityGroupListeners() { + return this.availabilityGroupListeners; + } + + /** + * The OperationsInner object to access its operations. + */ + private OperationsInner operations; + + /** + * Gets the OperationsInner object to access its operations. + * @return the OperationsInner object. + */ + public OperationsInner operations() { + return this.operations; + } + + /** + * The SqlVirtualMachineGroupsInner object to access its operations. + */ + private SqlVirtualMachineGroupsInner sqlVirtualMachineGroups; + + /** + * Gets the SqlVirtualMachineGroupsInner object to access its operations. + * @return the SqlVirtualMachineGroupsInner object. + */ + public SqlVirtualMachineGroupsInner sqlVirtualMachineGroups() { + return this.sqlVirtualMachineGroups; + } + + /** + * The SqlVirtualMachinesInner object to access its operations. + */ + private SqlVirtualMachinesInner sqlVirtualMachines; + + /** + * Gets the SqlVirtualMachinesInner object to access its operations. + * @return the SqlVirtualMachinesInner object. + */ + public SqlVirtualMachinesInner sqlVirtualMachines() { + return this.sqlVirtualMachines; + } + + /** + * Initializes an instance of SqlVirtualMachineManagementClient client. + * + * @param credentials the management credentials for Azure + */ + public SqlVirtualMachineManagementClientImpl(ServiceClientCredentials credentials) { + this("https://management.azure.com", credentials); + } + + /** + * Initializes an instance of SqlVirtualMachineManagementClient client. + * + * @param baseUrl the base URL of the host + * @param credentials the management credentials for Azure + */ + public SqlVirtualMachineManagementClientImpl(String baseUrl, ServiceClientCredentials credentials) { + super(baseUrl, credentials); + initialize(); + } + + /** + * Initializes an instance of SqlVirtualMachineManagementClient client. + * + * @param restClient the REST client to connect to Azure. + */ + public SqlVirtualMachineManagementClientImpl(RestClient restClient) { + super(restClient); + initialize(); + } + + protected void initialize() { + this.apiVersion = "2017-03-01-preview"; + this.acceptLanguage = "en-US"; + this.longRunningOperationRetryTimeout = 30; + this.generateClientRequestId = true; + this.availabilityGroupListeners = new AvailabilityGroupListenersInner(restClient().retrofit(), this); + this.operations = new OperationsInner(restClient().retrofit(), this); + this.sqlVirtualMachineGroups = new SqlVirtualMachineGroupsInner(restClient().retrofit(), this); + this.sqlVirtualMachines = new SqlVirtualMachinesInner(restClient().retrofit(), this); + this.azureClient = new AzureClient(this); + } + + /** + * Gets the User-Agent header for the client. + * + * @return the user agent string. + */ + @Override + public String userAgent() { + return String.format("%s (%s, %s, auto-generated)", super.userAgent(), "SqlVirtualMachineManagementClient", "2017-03-01-preview"); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManager.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManager.java new file mode 100644 index 0000000000000..3acb87b6ac5e9 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachineManager.java @@ -0,0 +1,135 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.AzureEnvironment; +import com.microsoft.azure.AzureResponseBuilder; +import com.microsoft.azure.credentials.AzureTokenCredentials; +import com.microsoft.azure.management.apigeneration.Beta; +import com.microsoft.azure.management.apigeneration.Beta.SinceVersion; +import com.microsoft.azure.arm.resources.AzureConfigurable; +import com.microsoft.azure.serializer.AzureJacksonAdapter; +import com.microsoft.rest.RestClient; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.AvailabilityGroupListeners; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.Operations; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineGroups; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines; +import com.microsoft.azure.arm.resources.implementation.AzureConfigurableCoreImpl; +import com.microsoft.azure.arm.resources.implementation.ManagerCore; + +/** + * Entry point to Azure SqlVirtualMachine resource management. + */ +public final class SqlVirtualMachineManager extends ManagerCore { + private AvailabilityGroupListeners availabilityGroupListeners; + private Operations operations; + private SqlVirtualMachineGroups sqlVirtualMachineGroups; + private SqlVirtualMachines sqlVirtualMachines; + /** + * Get a Configurable instance that can be used to create SqlVirtualMachineManager with optional configuration. + * + * @return the instance allowing configurations + */ + public static Configurable configure() { + return new SqlVirtualMachineManager.ConfigurableImpl(); + } + /** + * Creates an instance of SqlVirtualMachineManager that exposes SqlVirtualMachine resource management API entry points. + * + * @param credentials the credentials to use + * @param subscriptionId the subscription UUID + * @return the SqlVirtualMachineManager + */ + public static SqlVirtualMachineManager authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return new SqlVirtualMachineManager(new RestClient.Builder() + .withBaseUrl(credentials.environment(), AzureEnvironment.Endpoint.RESOURCE_MANAGER) + .withCredentials(credentials) + .withSerializerAdapter(new AzureJacksonAdapter()) + .withResponseBuilderFactory(new AzureResponseBuilder.Factory()) + .build(), subscriptionId); + } + /** + * Creates an instance of SqlVirtualMachineManager that exposes SqlVirtualMachine resource management API entry points. + * + * @param restClient the RestClient to be used for API calls. + * @param subscriptionId the subscription UUID + * @return the SqlVirtualMachineManager + */ + public static SqlVirtualMachineManager authenticate(RestClient restClient, String subscriptionId) { + return new SqlVirtualMachineManager(restClient, subscriptionId); + } + /** + * The interface allowing configurations to be set. + */ + public interface Configurable extends AzureConfigurable { + /** + * Creates an instance of SqlVirtualMachineManager that exposes SqlVirtualMachine management API entry points. + * + * @param credentials the credentials to use + * @param subscriptionId the subscription UUID + * @return the interface exposing SqlVirtualMachine management API entry points that work across subscriptions + */ + SqlVirtualMachineManager authenticate(AzureTokenCredentials credentials, String subscriptionId); + } + + /** + * @return Entry point to manage AvailabilityGroupListeners. + */ + public AvailabilityGroupListeners availabilityGroupListeners() { + if (this.availabilityGroupListeners == null) { + this.availabilityGroupListeners = new AvailabilityGroupListenersImpl(this); + } + return this.availabilityGroupListeners; + } + + /** + * @return Entry point to manage Operations. + */ + public Operations operations() { + if (this.operations == null) { + this.operations = new OperationsImpl(this); + } + return this.operations; + } + + /** + * @return Entry point to manage SqlVirtualMachineGroups. + */ + public SqlVirtualMachineGroups sqlVirtualMachineGroups() { + if (this.sqlVirtualMachineGroups == null) { + this.sqlVirtualMachineGroups = new SqlVirtualMachineGroupsImpl(this); + } + return this.sqlVirtualMachineGroups; + } + + /** + * @return Entry point to manage SqlVirtualMachines. + */ + public SqlVirtualMachines sqlVirtualMachines() { + if (this.sqlVirtualMachines == null) { + this.sqlVirtualMachines = new SqlVirtualMachinesImpl(this); + } + return this.sqlVirtualMachines; + } + + /** + * The implementation for Configurable interface. + */ + private static final class ConfigurableImpl extends AzureConfigurableCoreImpl implements Configurable { + public SqlVirtualMachineManager authenticate(AzureTokenCredentials credentials, String subscriptionId) { + return SqlVirtualMachineManager.authenticate(buildRestClient(credentials), subscriptionId); + } + } + private SqlVirtualMachineManager(RestClient restClient, String subscriptionId) { + super( + restClient, + subscriptionId, + new SqlVirtualMachineManagementClientImpl(restClient).withSubscriptionId(subscriptionId)); + } +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesImpl.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesImpl.java new file mode 100644 index 0000000000000..626f62da62535 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesImpl.java @@ -0,0 +1,138 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * def + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.resources.collection.implementation.GroupableResourcesCoreImpl; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachine; +import rx.Observable; +import rx.Completable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import com.microsoft.azure.arm.resources.ResourceUtilsCore; +import com.microsoft.azure.arm.utils.RXMapper; +import rx.functions.Func1; +import com.microsoft.azure.PagedList; +import com.microsoft.azure.Page; + +class SqlVirtualMachinesImpl extends GroupableResourcesCoreImpl implements SqlVirtualMachines { + protected SqlVirtualMachinesImpl(SqlVirtualMachineManager manager) { + super(manager.inner().sqlVirtualMachines(), manager); + } + + @Override + protected Observable getInnerAsync(String resourceGroupName, String name) { + SqlVirtualMachinesInner client = this.inner(); + return client.getByResourceGroupAsync(resourceGroupName, name); + } + + @Override + protected Completable deleteInnerAsync(String resourceGroupName, String name) { + SqlVirtualMachinesInner client = this.inner(); + return client.deleteAsync(resourceGroupName, name).toCompletable(); + } + + @Override + public Observable deleteByIdsAsync(Collection ids) { + if (ids == null || ids.isEmpty()) { + return Observable.empty(); + } + Collection> observables = new ArrayList<>(); + for (String id : ids) { + final String resourceGroupName = ResourceUtilsCore.groupFromResourceId(id); + final String name = ResourceUtilsCore.nameFromResourceId(id); + Observable o = RXMapper.map(this.inner().deleteAsync(resourceGroupName, name), id); + observables.add(o); + } + return Observable.mergeDelayError(observables); + } + + @Override + public Observable deleteByIdsAsync(String...ids) { + return this.deleteByIdsAsync(new ArrayList(Arrays.asList(ids))); + } + + @Override + public void deleteByIds(Collection ids) { + if (ids != null && !ids.isEmpty()) { + this.deleteByIdsAsync(ids).toBlocking().last(); + } + } + + @Override + public void deleteByIds(String...ids) { + this.deleteByIds(new ArrayList(Arrays.asList(ids))); + } + + @Override + public PagedList listByResourceGroup(String resourceGroupName) { + SqlVirtualMachinesInner client = this.inner(); + return this.wrapList(client.listByResourceGroup(resourceGroupName)); + } + + @Override + public Observable listByResourceGroupAsync(String resourceGroupName) { + SqlVirtualMachinesInner client = this.inner(); + return client.listByResourceGroupAsync(resourceGroupName) + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public SqlVirtualMachine call(SqlVirtualMachineInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public PagedList list() { + SqlVirtualMachinesInner client = this.inner(); + return this.wrapList(client.list()); + } + + @Override + public Observable listAsync() { + SqlVirtualMachinesInner client = this.inner(); + return client.listAsync() + .flatMapIterable(new Func1, Iterable>() { + @Override + public Iterable call(Page page) { + return page.items(); + } + }) + .map(new Func1() { + @Override + public SqlVirtualMachine call(SqlVirtualMachineInner inner) { + return wrapModel(inner); + } + }); + } + + @Override + public SqlVirtualMachineImpl define(String name) { + return wrapModel(name); + } + + @Override + protected SqlVirtualMachineImpl wrapModel(SqlVirtualMachineInner inner) { + return new SqlVirtualMachineImpl(inner.name(), inner, manager()); + } + + @Override + protected SqlVirtualMachineImpl wrapModel(String name) { + return new SqlVirtualMachineImpl(name, new SqlVirtualMachineInner(), this.manager()); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesInner.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesInner.java new file mode 100644 index 0000000000000..3cac074ce5941 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/SqlVirtualMachinesInner.java @@ -0,0 +1,1379 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + */ + +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; + +import com.microsoft.azure.arm.collection.InnerSupportsGet; +import com.microsoft.azure.arm.collection.InnerSupportsDelete; +import com.microsoft.azure.arm.collection.InnerSupportsListing; +import retrofit2.Retrofit; +import com.google.common.reflect.TypeToken; +import com.microsoft.azure.AzureServiceFuture; +import com.microsoft.azure.CloudException; +import com.microsoft.azure.ListOperationCallback; +import com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachineUpdate; +import com.microsoft.azure.Page; +import com.microsoft.azure.PagedList; +import com.microsoft.rest.ServiceCallback; +import com.microsoft.rest.ServiceFuture; +import com.microsoft.rest.ServiceResponse; +import com.microsoft.rest.Validator; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import okhttp3.ResponseBody; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.Header; +import retrofit2.http.Headers; +import retrofit2.http.HTTP; +import retrofit2.http.PATCH; +import retrofit2.http.Path; +import retrofit2.http.PUT; +import retrofit2.http.Query; +import retrofit2.http.Url; +import retrofit2.Response; +import rx.functions.Func1; +import rx.Observable; + +/** + * An instance of this class provides access to all the operations defined + * in SqlVirtualMachines. + */ +public class SqlVirtualMachinesInner implements InnerSupportsGet, InnerSupportsDelete, InnerSupportsListing { + /** The Retrofit service to perform REST calls. */ + private SqlVirtualMachinesService service; + /** The service client containing this operation class. */ + private SqlVirtualMachineManagementClientImpl client; + + /** + * Initializes an instance of SqlVirtualMachinesInner. + * + * @param retrofit the Retrofit instance built from a Retrofit Builder. + * @param client the instance of the service client containing this operation class. + */ + public SqlVirtualMachinesInner(Retrofit retrofit, SqlVirtualMachineManagementClientImpl client) { + this.service = retrofit.create(SqlVirtualMachinesService.class); + this.client = client; + } + + /** + * The interface defining all the services for SqlVirtualMachines to be + * used by Retrofit to perform actually REST calls. + */ + interface SqlVirtualMachinesService { + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines list" }) + @GET("subscriptions/{subscriptionId}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines") + Observable> list(@Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines getByResourceGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}") + Observable> getByResourceGroup(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Query("$expand") String expand, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines createOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}") + Observable> createOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Body SqlVirtualMachineInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines beginCreateOrUpdate" }) + @PUT("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}") + Observable> beginCreateOrUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Body SqlVirtualMachineInner parameters, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines delete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}", method = "DELETE", hasBody = true) + Observable> delete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines beginDelete" }) + @HTTP(path = "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}", method = "DELETE", hasBody = true) + Observable> beginDelete(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines update" }) + @PATCH("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}") + Observable> update(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SqlVirtualMachineUpdate parameters, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines beginUpdate" }) + @PATCH("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines/{sqlVirtualMachineName}") + Observable> beginUpdate(@Path("resourceGroupName") String resourceGroupName, @Path("sqlVirtualMachineName") String sqlVirtualMachineName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Body SqlVirtualMachineUpdate parameters, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines listByResourceGroup" }) + @GET("subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.SqlVirtualMachine/sqlVirtualMachines") + Observable> listByResourceGroup(@Path("resourceGroupName") String resourceGroupName, @Path("subscriptionId") String subscriptionId, @Query("api-version") String apiVersion, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines listNext" }) + @GET + Observable> listNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + @Headers({ "Content-Type: application/json; charset=utf-8", "x-ms-logging-context: com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.SqlVirtualMachines listByResourceGroupNext" }) + @GET + Observable> listByResourceGroupNext(@Url String nextUrl, @Header("accept-language") String acceptLanguage, @Header("User-Agent") String userAgent); + + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineInner> object if successful. + */ + public PagedList list() { + ServiceResponse> response = listSinglePageAsync().toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listAsync(final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listSinglePageAsync(), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable> listAsync() { + return listWithServiceResponseAsync() + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable>> listWithServiceResponseAsync() { + return listSinglePageAsync() + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listSinglePageAsync() { + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.list(this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner getByResourceGroup(String resourceGroupName, String sqlVirtualMachineName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).toBlocking().single().body(); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName), serviceCallback); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineName) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable> getByResourceGroupWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final String expand = null; + return service.getByResourceGroup(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), expand, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getByResourceGroupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param expand The child resources to include in the response. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner getByResourceGroup(String resourceGroupName, String sqlVirtualMachineName, String expand) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, expand).toBlocking().single().body(); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param expand The child resources to include in the response. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineName, String expand, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, expand), serviceCallback); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param expand The child resources to include in the response. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable getByResourceGroupAsync(String resourceGroupName, String sqlVirtualMachineName, String expand) { + return getByResourceGroupWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, expand).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Gets a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param expand The child resources to include in the response. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable> getByResourceGroupWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName, String expand) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.getByResourceGroup(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), expand, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = getByResourceGroupDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse getByResourceGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner createOrUpdate(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters).toBlocking().last().body(); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters), serviceCallback); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable createOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + return createOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> createOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + Observable> observable = service.createOrUpdate(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner beginCreateOrUpdate(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters).toBlocking().single().body(); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters), serviceCallback); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable beginCreateOrUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + return beginCreateOrUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, parameters).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Creates or updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param parameters The SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable> beginCreateOrUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName, SqlVirtualMachineInner parameters) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (parameters == null) { + throw new IllegalArgumentException("Parameter parameters is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(parameters); + return service.beginCreateOrUpdate(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), parameters, this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginCreateOrUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginCreateOrUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(201, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void delete(String resourceGroupName, String sqlVirtualMachineName) { + deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).toBlocking().last().body(); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture deleteAsync(String resourceGroupName, String sqlVirtualMachineName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName), serviceCallback); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable deleteAsync(String resourceGroupName, String sqlVirtualMachineName) { + return deleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> deleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Observable> observable = service.delete(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()); + return client.getAzureClient().getPostOrDeleteResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + */ + public void beginDelete(String resourceGroupName, String sqlVirtualMachineName) { + beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).toBlocking().single().body(); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName), serviceCallback); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable beginDeleteAsync(String resourceGroupName, String sqlVirtualMachineName) { + return beginDeleteWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).map(new Func1, Void>() { + @Override + public Void call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Deletes a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceResponse} object if successful. + */ + public Observable> beginDeleteWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.beginDelete(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginDeleteDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginDeleteDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .register(202, new TypeToken() { }.getType()) + .register(204, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner update(String resourceGroupName, String sqlVirtualMachineName) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).toBlocking().last().body(); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sqlVirtualMachineName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName), serviceCallback); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String resourceGroupName, String sqlVirtualMachineName) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final Map tags = null; + SqlVirtualMachineUpdate parameters = new SqlVirtualMachineUpdate(); + parameters.withTags(null); + Observable> observable = service.update(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner update(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags).toBlocking().last().body(); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture updateAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags), serviceCallback); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable updateAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + return updateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable for the request + */ + public Observable> updateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(tags); + SqlVirtualMachineUpdate parameters = new SqlVirtualMachineUpdate(); + parameters.withTags(tags); + Observable> observable = service.update(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()); + return client.getAzureClient().getPutOrPatchResultAsync(observable, new TypeToken() { }.getType()); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner beginUpdate(String resourceGroupName, String sqlVirtualMachineName) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).toBlocking().single().body(); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName), serviceCallback); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineName) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + final Map tags = null; + SqlVirtualMachineUpdate parameters = new SqlVirtualMachineUpdate(); + parameters.withTags(null); + return service.beginUpdate(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the SqlVirtualMachineInner object if successful. + */ + public SqlVirtualMachineInner beginUpdate(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags).toBlocking().single().body(); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags, final ServiceCallback serviceCallback) { + return ServiceFuture.fromResponse(beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags), serviceCallback); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable beginUpdateAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + return beginUpdateWithServiceResponseAsync(resourceGroupName, sqlVirtualMachineName, tags).map(new Func1, SqlVirtualMachineInner>() { + @Override + public SqlVirtualMachineInner call(ServiceResponse response) { + return response.body(); + } + }); + } + + /** + * Updates a SQL virtual machine. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param sqlVirtualMachineName Name of the SQL virtual machine. + * @param tags Resource tags. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the SqlVirtualMachineInner object + */ + public Observable> beginUpdateWithServiceResponseAsync(String resourceGroupName, String sqlVirtualMachineName, Map tags) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (sqlVirtualMachineName == null) { + throw new IllegalArgumentException("Parameter sqlVirtualMachineName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + Validator.validate(tags); + SqlVirtualMachineUpdate parameters = new SqlVirtualMachineUpdate(); + parameters.withTags(tags); + return service.beginUpdate(resourceGroupName, sqlVirtualMachineName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), parameters, this.client.userAgent()) + .flatMap(new Func1, Observable>>() { + @Override + public Observable> call(Response response) { + try { + ServiceResponse clientResponse = beginUpdateDelegate(response); + return Observable.just(clientResponse); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse beginUpdateDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory().newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineInner> object if successful. + */ + public PagedList listByResourceGroup(final String resourceGroupName) { + ServiceResponse> response = listByResourceGroupSinglePageAsync(resourceGroupName).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupAsync(final String resourceGroupName, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupSinglePageAsync(resourceGroupName), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable> listByResourceGroupAsync(final String resourceGroupName) { + return listByResourceGroupWithServiceResponseAsync(resourceGroupName) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable>> listByResourceGroupWithServiceResponseAsync(final String resourceGroupName) { + return listByResourceGroupSinglePageAsync(resourceGroupName) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + ServiceResponse> * @param resourceGroupName Name of the resource group that contains the resource. You can obtain this value from the Azure Resource Manager API or the portal. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupSinglePageAsync(final String resourceGroupName) { + if (resourceGroupName == null) { + throw new IllegalArgumentException("Parameter resourceGroupName is required and cannot be null."); + } + if (this.client.subscriptionId() == null) { + throw new IllegalArgumentException("Parameter this.client.subscriptionId() is required and cannot be null."); + } + if (this.client.apiVersion() == null) { + throw new IllegalArgumentException("Parameter this.client.apiVersion() is required and cannot be null."); + } + return service.listByResourceGroup(resourceGroupName, this.client.subscriptionId(), this.client.apiVersion(), this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineInner> object if successful. + */ + public PagedList listNext(final String nextPageLink) { + ServiceResponse> response = listNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable> listNextAsync(final String nextPageLink) { + return listNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable>> listNextWithServiceResponseAsync(final String nextPageLink) { + return listNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machines in a subscription. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @throws CloudException thrown if the request is rejected by server + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent + * @return the PagedList<SqlVirtualMachineInner> object if successful. + */ + public PagedList listByResourceGroupNext(final String nextPageLink) { + ServiceResponse> response = listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single(); + return new PagedList(response.body()) { + @Override + public Page nextPage(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink).toBlocking().single().body(); + } + }; + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param serviceFuture the ServiceFuture object tracking the Retrofit calls + * @param serviceCallback the async ServiceCallback to handle successful and failed responses. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the {@link ServiceFuture} object + */ + public ServiceFuture> listByResourceGroupNextAsync(final String nextPageLink, final ServiceFuture> serviceFuture, final ListOperationCallback serviceCallback) { + return AzureServiceFuture.fromPageResponse( + listByResourceGroupNextSinglePageAsync(nextPageLink), + new Func1>>>() { + @Override + public Observable>> call(String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink); + } + }, + serviceCallback); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable> listByResourceGroupNextAsync(final String nextPageLink) { + return listByResourceGroupNextWithServiceResponseAsync(nextPageLink) + .map(new Func1>, Page>() { + @Override + public Page call(ServiceResponse> response) { + return response.body(); + } + }); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the observable to the PagedList<SqlVirtualMachineInner> object + */ + public Observable>> listByResourceGroupNextWithServiceResponseAsync(final String nextPageLink) { + return listByResourceGroupNextSinglePageAsync(nextPageLink) + .concatMap(new Func1>, Observable>>>() { + @Override + public Observable>> call(ServiceResponse> page) { + String nextPageLink = page.body().nextPageLink(); + if (nextPageLink == null) { + return Observable.just(page); + } + return Observable.just(page).concatWith(listByResourceGroupNextWithServiceResponseAsync(nextPageLink)); + } + }); + } + + /** + * Gets all SQL virtual machines in a resource group. + * + ServiceResponse> * @param nextPageLink The NextLink from the previous successful call to List operation. + * @throws IllegalArgumentException thrown if parameters fail the validation + * @return the PagedList<SqlVirtualMachineInner> object wrapped in {@link ServiceResponse} if successful. + */ + public Observable>> listByResourceGroupNextSinglePageAsync(final String nextPageLink) { + if (nextPageLink == null) { + throw new IllegalArgumentException("Parameter nextPageLink is required and cannot be null."); + } + String nextUrl = String.format("%s", nextPageLink); + return service.listByResourceGroupNext(nextUrl, this.client.acceptLanguage(), this.client.userAgent()) + .flatMap(new Func1, Observable>>>() { + @Override + public Observable>> call(Response response) { + try { + ServiceResponse> result = listByResourceGroupNextDelegate(response); + return Observable.just(new ServiceResponse>(result.body(), result.response())); + } catch (Throwable t) { + return Observable.error(t); + } + } + }); + } + + private ServiceResponse> listByResourceGroupNextDelegate(Response response) throws CloudException, IOException, IllegalArgumentException { + return this.client.restClient().responseBuilderFactory()., CloudException>newInstance(this.client.serializerAdapter()) + .register(200, new TypeToken>() { }.getType()) + .registerError(CloudException.class) + .build(response); + } + +} diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/package-info.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/package-info.java new file mode 100644 index 0000000000000..ce603ddbbe0c9 --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/implementation/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementation classes for SqlVirtualMachineManagementClient. + * The SQL virtual machine management API provides a RESTful set of web APIs that interact with Azure Compute, Network & Storage services to manage your SQL Server virtual machine. The API enables users to create, delete and retrieve a SQL virtual machine, SQL virtual machine group or availability group listener. + */ +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview.implementation; diff --git a/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/package-info.java b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/package-info.java new file mode 100644 index 0000000000000..4ab74de7b64eb --- /dev/null +++ b/sqlvirtualmachine/resource-manager/v2017_03_01_preview/src/main/java/com/microsoft/azure/management/sqlvirtualmachine/v2017_03_01_preview/package-info.java @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. +// +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the classes for SqlVirtualMachineManagementClient. + * The SQL virtual machine management API provides a RESTful set of web APIs that interact with Azure Compute, Network & Storage services to manage your SQL Server virtual machine. The API enables users to create, delete and retrieve a SQL virtual machine, SQL virtual machine group or availability group listener. + */ +package com.microsoft.azure.management.sqlvirtualmachine.v2017_03_01_preview; diff --git a/storage/client/blob/CHANGELOG.md b/storage/client/blob/CHANGELOG.md new file mode 100644 index 0000000000000..bd8725613be08 --- /dev/null +++ b/storage/client/blob/CHANGELOG.md @@ -0,0 +1,115 @@ +# Change Log azure-storage-blob + +## Version 12.0.0-preview.1: + +Version 12.0.0-preview.1 is the first preview of our efforts to create a user-friendly and Java client library for Azure Storage Blobs. For more information about this, and preview releases of other Azure SDK libraries, please visit +https://aka.ms/azure-sdk-preview1-java. + +**Breaking changes: New API design** +- Operations are now scoped to a particular client: + - `StorageClient`: This client handles account-level operations. This includes managing service properties and listing the containers within an account. + - `ContainerClient`: The client handles operations for a particular container. This includes creating or deleting that container, as well as listing the blobs within that container and managing properties and metadata. + - `BlobClient`: The client handles operations for a particular blob. This includes creating or deleting that blob, as well as upload and download data and managing properties. + This BlobClient handles all blob types (block, page and append). Where operations can behave differently according to type (i.e. `upload`) the default behaviour will be block blobs unless otherwise specified. + + These clients can be accessed by navigating down the client hierarchy, or instantiated directly using builder to the resource (account, container or blob). +- New module level operations for simple upload and download using a block or page blob client. +- Download operations can download data in multiple ways: + - `download_to_stream`: Download the entire content to an open stream handle (e.g. an open file). Supports multi-threaded download. +- New underlying REST pipeline implementation, based on the new `azure-core` library. +- Client and pipeline configuration is now available via keyword arguments at both the client level. +- Authentication using `azure-identity` credentials. + +## 2019.04.30 Version 11.1.1 +- Upgraded to version 2.1.1 of the autorest-clientime which upgrades to a more secure version of jackson and fixes a NPE on unkown host errors. + +## 2019.03.22 Version 11.0.0 +- Upgraded to version 2.1.0 of the autorest-clientruntime which includes several important fixes to mitigate a commonly-seen "Connection reset by peer" error and other similar bugs. +- Support for 2018-11-09 REST version. Please see our REST API documentation and blogs for information about the related added features. +- Added appendBlockFromURL method. A block may be created with another blob as its source. +- Added uploadPagesFromURL method. Pages may be written to with another blob as their source. +- Fixed a bug that would set an invalid range header when downloading an empty blob. +- Modified the LoggingFactory to redact SAS signatures on outgoing requests. +- HTTPGetterInfo was made an internal type as it is an internal implementation detail. +- Removed DEFAULT and NONE static variables. Empty constructors should be used instead. DEFAULT static values were error prone and unsafe to use because although the field was final, the objects were mutable, so it was possible the value could be changed accidentally and alter the behavior of the program. +- Optimized the TransferManager download to file method to skip the initial HEAD request. +- Added an option to configure that maximum size data that will be uploaded in a single shot via the TransferManager. +- Added request Http Method, URL, and headers to logging messages. +- Changed *ListingDetails to *ListDetails. These name changes are to mitigate conflicts with v8, allowing for side-by-side loading of different versions, which may help with upgrading. +- Removed the extra quotes around etags in some responses so they are consistently now consistently formatted. +- Moved the Generated*** types into the blob package to avoid conflicts with generated types from other services (i.e. queues and files) +- Changed the logger name to be the name of class that uses it, which is a more conventional practice +- Support added for SAS tokens to scope to blob snapshot. +- Added getUserDelegationKey to ServiceURL, the result of which can be used to generate a user-delegation SAS. +- Made the max results field on listing responses Integer instead of int as it is an optional field only returned when specified in the request. + +## 2019.02.15 Version 10.5.0 +- Added uploadFromNonReplayableFlowable to support uploading arbitrary data sources (like network streams) to a block blob. + +## 2019.01.11 Version 10.4.0 +- Fixed a bug that caused errors when java.io.tempdir has no trailing separator. +- Upgrade autorest-clientruntime dependency to include some bug fixes. + +## 2018.11.19 Version 10.3.0 +- Added support for SLF4J. +- Included default logging to log warnings and errors to the temp directory by default. +- Fixed a bug in hierarchical listings that would sometimes return incomplete results. +- Included the whole HTTP Request in log statements (except for sensitive authorization information, which is redacted). +- Fixed a bug that made the request property on the response object always null. + +## 2018.10.29 Version 10.2.0 +- Added overloads which only accept the required parameters. +- Added CopyFromURL, which will do a synchronous server-side copy, meaning the service will not return an HTTP response until it has completed the copy. +- Added support for IProgressReceiver in TransferManager operations. This parameter was previously ignored but is now supported. +- Removed internal dependency on javafx to be compatible with openjdk. +- Fixed a bug that would cause downloading large files with the TransferManager to fail. +- Fixed a bug in BlobURL.download() logic for setting up reliable download. This had the potential to download the wrong range when a download stream was retried. + +## 2018.09.11 Version 10.1.0 +- Interfaces for helper types updated to be more consistent throughout the library. All types, with the exception of the options for pipeline factories, use a fluent pattern. +- Removed RetryReader type as it's functionality was moved to be built into the DownloadResponse. RetryReaderOptions are now named ReliableDownloadOptions. +- Restructured the access conditions to be more logically adhere to their respective functions. +- Added support for context parameter on each api to allow communication with the pipeline from the application level + +## 2018.08.22 Version 10.0.4-rc +- Support for the 2017-11-09 REST version. Please see our REST api documentation and blogs for information about the related added features. +- Support for 2018-03-28 REST version. Please see our REST api documentation and blogs for information about the related added features. +- Support for the getAccountInfo api on ServiceURL, ContainerURL, and BlobURL. +- Added support for setting service properties related to static websites. +- Changed BlobURL.startCopy sourceAccessConditions parameter to be HTTPAccessConditions as lease is not actually supported. +- Added methods to TransferManager for conveniently downloading a blob to a file. +- UploadFromFile now takes an AsynchronousFileChannel. +- UploadByteBuffersToBlockBlob, UploadByteBufferToBlockBlob, and DownloadToBuffer have been removed. +- IPRange fields are now strings. +- Fixed retry policy. +- Fixed logging policy. + +## 2018.08.08 Version 10.0.3-Preview +- Resolved dependency issues + +## 2018.08.07 Version 10.0.2-Preview +- Support for 2017-07-29 REST version. Please see our REST api documentation and blogs for information about the related added features. +- Support for setting a block blob's tier. +- Added support for soft delete feature. If a delete retention policy is enabled through the set service properties API, then blobs or snapshots can be deleted softly and retained for a specified number of days, before being permanently removed by garbage collection. +- Changed BlobListingDetails constructor to take a flag to include deleted blobs. +- Restructured the blob and container listing responses. +- BlockBlobURL.MAX_PUT_BLOCK_BYTES renamed to BlockBlobURL.MAX_STAGE_BLOCK_BYTES. +- Changed the accessConditions parameter to be HTTPAccessConditions instead of BlobAccessConditions, since only http access conditions are supported. + +## 2018.07.03 Version 10.0.1-Preview +- Added the RetryReader class to allow for more reliable streaming on large downloads. This is now the return type of blobURL.download +- Fixed a bug that caused generation of signatures to fail at high levels of parallelism. +- Created the StorageException type to give easy access to the ErrorCode, StatusCode, and Message as available for unsuccessful responses. +- Added the StorageErrorCode type for checking against error codes returned by the service. +- Changed the AppendBlobAccessConditions field types to be Long instead of Int. +- Upgraded Netty dependency to allow uploading memory mapped files with https. +- Upgraded the autorest runtime dependency to fix a dependency bug in their package. +- Changed RequestRetryOptions maxTries and tryTimeout fields to be Integer instead of int. 0 is no longer allowed. +- Changed CommonRestResponse.lastModifiedTime to be lastModified. +- Added statusCode property to CommonRestResponse. +- Change dateProperty to be date on all generated types. +- Fixed a bug that prevented proper reset of body stream upon retry. +- Updated the defaults for RequestRetryOptions. + +## 2018.04.27 Version 10.0.0-preview +- Initial Release. Please see the README and wiki for information on the new design. diff --git a/storage/client/blob/README.md b/storage/client/blob/README.md new file mode 100644 index 0000000000000..0b3f28e20fb52 --- /dev/null +++ b/storage/client/blob/README.md @@ -0,0 +1,276 @@ +# Azure Storage Blobs client library for Java + +> Server Version: 2018-11-09 + +Azure Blob storage is Microsoft's object storage solution for the cloud. Blob +storage is optimized for storing massive amounts of unstructured data. +Unstructured data is data that does not adhere to a particular data model or +definition, such as text or binary data. + +[Source code][source] | [Package (Maven)][package] | [API reference documentation][docs] | [REST API documentation][rest_docs] | [Product documentation][product_docs] + +## Getting started + +### Prerequisites + +- Java Development Kit (JDK) with version 8 or above +- [Azure Subscription][azure_subscription] +- [Create Strorage Account][storage_account] + +### Adding the package to your product + +```xml + + com.azure + azure-storage-blob + 12.0.0-preview.1 + +``` + +### Create a Storage Account +To create a Storage Account you can use the Azure Portal or [Azure CLI][storage_account_create_cli]. + +```Powershell +az group create \ + --name storage-resource-group \ + --location westus +``` + +### Authenticate the client + +In order to interact with the Storage service (Blob, Queue, Message, MessageId, File) you'll need to create an instance of the Service Client class. +To make this possible you'll need the Account SAS (shared access signature) string of Storage account. Learn more at [SAS Token][sas_token] + +#### Get Credentials + +- **SAS Token** + +a. Use the [Azure CLI][azure_cli] snippet below to get the SAS token from the Storage account. + +```Powershell +az storage blob generate-sas + --name {queue name} + --expiry {date/time to expire SAS token} + --permission {permission to grant} + --connection-string {connection string of the storage account} +``` + +```Powershell +CONNECTION_STRING= + +az storage blob generate-sas + --name javasdksas + --expiry 2019-06-05 + --permission rpau + --connection-string $CONNECTION_STRING +``` +b. Alternatively, get the Account SAS Token from the Azure Portal. +``` +Go to your storage account -> Shared access signature -> Click on Generate SAS and connection string (after setup) +``` + +- **Shared Key Credential** + +a. Use account name and account key. Account name is your storage account name. +``` +// Here is where we get the key +Go to your storage account -> Access keys -> Key 1/ Key 2 -> Key +``` +b. Use the connection string +``` +// Here is where we get the key +Go to your storage account -> Access Keys -> Keys 1/ Key 2 -> Connection string +``` + +## Key concepts + +Blob storage is designed for: + +- Serving images or documents directly to a browser. +- Storing files for distributed access. +- Streaming video and audio. +- Writing to log files. +- Storing data for backup and restore, disaster recovery, and archiving. +- Storing data for analysis by an on-premises or Azure-hosted service. + +## Examples +The following sections provide several code snippets covering some of the most common Azure Storage Blob tasks, including: +- [Create storage client](#create-storage-client) +- [Create container client](#create-container-client) +- [Create blob client](#create-blob-client) +- [Create a container](#create-a-container) +- [Upload a blob from InputStream](#upload-a-blob-from-inputstream) +- [Upload a blob from File](#upload-a-blob-from-file) +- [Download a blob to OutputStream](#download-a-blob-to-outputstream) +- [Download a blob to File](#download-a-blob-to-file) +- [Enumerating blobs](#enumerating-blobs) +- [Authenticate with Azure.Identity](#authenticate-with-azure-identity) + +### Create Storage Client + +Create a storage client using the [`sasToken`](#get-credentials) generated above. +```java +StorageClient storageClient = StorageClient.builder() + .endpoiont() + .credentail(sasToken) + .build(); +``` + +### Create Container Client + +Create a container client if storage client exists. +```java +ContainerClient containerClient = storageClient.getContainerClient("mycontainer"); +``` + +or + +Create the container client from the builder [`sasToken`](#get-credentials) generated above. +```java +ContainerClient containerClient = ContainerClient.builder() + .endpoiont() + .credentail(sasToken) + .containerName("mycontainer") + .build(); +``` + +### Create Blob Client + +Create a blob client if container client exists. +```java +BlobClient blobClient = containerClient.getBlobClient("myblob"); +``` + +or + +Create the blob client from the builder [`sasToken`](#get-credentials) generated above. +```java +BlobClient blobClient = BlobClient.builder() + .endpoiont() + .credentail(sasToken) + .containerName("mycontainer") + .blobName("myblob") + .build(); +``` + +### Create a container + +Create a container from storage client. +```java +storageClient.createContainer("mycontainer"); +``` + +or + +Create a container using container client. +```java +conatinerClient.create(); +``` + +### Uploading a blob from InputStream + +Upload data stream to a blob using blockBlobClient generated from containerClient. + +```java +BlockBlobClient blockBlobClient = containerClient.getBlockBlobClient("myblockblob"); +String dataSample = "samples"; +try (ByteArrayInputStream dataStream = new ByteArrayInputStream(dataSample.getBytes())) { + blockBlobClient.upload(dataStream, dataSample.length()); +} +``` + +### Uploading a blob from File + +Upload a file to a blob using blockBlobClient generated from containerClient. + +```java +BlockBlobClient blockBlobClient = containerClient.getBlockBlobClient("myblockblob"); +blobClient.uploadFromFile("local-file.jpg"); +``` + +### Downloading a blob to output stream + +Download blob to output stream using blobClient. + +```java +try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream("downloaded-file.jpg")) { + blobClient.download(outputStream); +} +``` + +### Downloading a blob to local path + +Download blob to local file using blobClient. +```java +blobClient.downloadToFile("downloaded-file.jpg"); +``` + +### Enumerating blobs + +Enuerating all blobs using containerClient +```java +containerClient.listBlobsFlat() + .forEach( + blobItem -> System.out.println("This is the blob name: " + blobItem.name()) + ); +``` + +### Authenticate with Azure.Identity + +The [Azure Identity library](identity) provides Azure Active Directory support for authenticating with Azure Storage. +```java +StorageClient storageClient = StorageClient.storageClientBuilder() + .endpoint(endpoint) + .credential(new DefaultAzureCredential()) + .buildClient(); +``` + +## Troubleshooting + +When interacts with blobs using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][error_codes] requests. +For example, if you try to retrieve a container or blob that doesn't exist in your Storage Account, a `404` error is returned, indicating `Not Found`. + +## Next steps + +Get started with our [Blob samples][samples]: + +1. [Basic Examples](src/samples/java/blob/BasicExample.java): Create storage, container, blob clients, Upload, download, and list blobs. +1. [File Transfer Examples](src/samples/java/blob/FileTranferExample.java): Upload and download a large file through blobs. +1. [Storage Error Examples](src/samples/java/blob/StorageErrorHandlingExample.java): Handle the exceptions from storage blob service side. +1. [List Container Examples](src/samples/java/blob/ListContainersExample.java): Create, list and delete containers. +1. [Set metadata and HTTPHeaders Examples](src/samples/java/blob/SetMetadataAndHTTPHeadersExample.java): Set metadata for container and blob, and set HTTPHeaders for blob. +1. [Azure Identity Examples](src/samples/java/blob/AzureIdentityExample.java): Use DefaultAzureCredential to do the authentication. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. + +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-java%2Fsdk%2Fstorage%2FAzure.Storage.Blobs%2FREADME.png) + + +[source]: https://github.com/Azure/azure-sdk-for-java/tree/master/storage/client/blob/src +[package]: https://repo1.maven.org/maven2/com/azure/azure-storage-blob/12.0.0-preview.1/ +[docs]: http://azure.github.io/azure-sdk-for-java/ +[rest_docs]: https://docs.microsoft.com/en-us/rest/api/storageservices/blob-service-rest-api +[product_docs]: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-overview +[sas_token]: https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 +[jdk]: https://docs.microsoft.com/en-us/java/azure/java-supported-jdk-runtime?view=azure-java-stable +[maven]: https://maven.apache.org/ +[azure_subscription]: https://azure.microsoft.com/en-us/free/ +[storage_account]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal +[storage_account_create_ps]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-powershell +[storage_account_create_cli]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-cli +[storage_account_create_portal]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[identity]: https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/identity/azure-identity/README.md +[error_codes]: https://docs.microsoft.com/en-us/rest/api/storageservices/blob-service-error-codes +[samples]: samples/ +[cla]: https://cla.microsoft.com +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[coc_contact]: mailto:opencode@microsoft.com diff --git a/storage/client/blob/pom.xml b/storage/client/blob/pom.xml new file mode 100644 index 0000000000000..b661ff0ad7e2d --- /dev/null +++ b/storage/client/blob/pom.xml @@ -0,0 +1,151 @@ + + + + com.azure + azure-client-sdk-parent + 1.1.0 + ../../../pom.client.xml + + + 4.0.0 + + com.azure + azure-storage-blob + 12.0.0-preview.1 + + azure-storage-blob + https://github.com/Azure/azure-sdk-for-java + + + + azure-java-build-docs + ${site.url}/site/${project.artifactId} + + + + + scm:git:https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + + bintray + Groovy Bintray + https://dl.bintray.com/groovy/maven + + never + + + false + + + + + + + com.azure + azure-core + 1.0.0-preview.2 + + + org.slf4j + slf4j-api + + + + + com.google.code.findbugs + jsr305 + 3.0.2 + provided + + + + com.azure + azure-core-test + 1.0.0-preview.2 + test + + + com.azure + azure-identity + 1.0.0-preview.1 + test + + + junit + junit + test + + + org.slf4j + slf4j-simple + test + + + io.projectreactor + reactor-test + test + + + com.microsoft.azure + adal4j + test + + + org.spockframework + spock-core + test + + + cglib + cglib-nodep + test + + + uk.org.lidalia + slf4j-test + test + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-compiler-plugin + + groovy-eclipse-compiler + -Xlint:unchecked + 1.8 + 1.8 + true + + + + org.codehaus.groovy + groovy-eclipse-compiler + ${groovy-eclipse-compiler.version} + + + org.codehaus.groovy + groovy-eclipse-batch + ${groovy-eclipse-batch.version} + + + + + + + diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASPermission.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASPermission.java new file mode 100644 index 0000000000000..11369aabed0d7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASPermission.java @@ -0,0 +1,253 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.util.Locale; + +/** + * This is a helper class to construct a string representing the permissions granted by an AccountSAS. Setting a value + * to true means that any SAS which uses these permissions will grant permissions for that operation. Once all the + * values are set, this should be serialized with toString and set as the permissions field on an + * {@link AccountSASSignatureValues} object. It is possible to construct the permissions string without this class, but + * the order of the permissions is particular and this class guarantees correctness. + */ +final class AccountSASPermission { + + private boolean read; + + private boolean add; + + private boolean create; + + private boolean write; + + private boolean delete; + + private boolean list; + + private boolean update; + + private boolean processMessages; + + /** + * Initializes an {@code AccountSASPermission} object with all fields set to false. + */ + private AccountSASPermission() { + } + + /** + * Creates an {@code AccountSASPermission} from the specified permissions string. This method will throw an + * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid permission. + * + * @param permString + * A {@code String} which represents the {@code SharedAccessAccountPermissions}. + * + * @return An {@code AccountSASPermission} object generated from the given {@code String}. + * @throws IllegalArgumentException If {@code permString} contains a character other than r, w, d, l, a, c, u, or p. + */ + public static AccountSASPermission parse(String permString) { + AccountSASPermission permissions = new AccountSASPermission(); + + for (int i = 0; i < permString.length(); i++) { + char c = permString.charAt(i); + switch (c) { + case 'r': + permissions.read = true; + break; + case 'w': + permissions.write = true; + break; + case 'd': + permissions.delete = true; + break; + case 'l': + permissions.list = true; + break; + case 'a': + permissions.add = true; + break; + case 'c': + permissions.create = true; + break; + case 'u': + permissions.update = true; + break; + case 'p': + permissions.processMessages = true; + break; + default: + throw new IllegalArgumentException( + String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permString, c)); + } + } + return permissions; + } + + /** + * Permission to read resources and list queues and tables granted. + */ + public boolean read() { + return read; + } + + /** + * Permission to read resources and list queues and tables granted. + */ + public AccountSASPermission read(boolean read) { + this.read = read; + return this; + } + + /** + * Permission to add messages, table entities, and append to blobs granted. + */ + public boolean add() { + return add; + } + + /** + * Permission to add messages, table entities, and append to blobs granted. + */ + public AccountSASPermission add(boolean add) { + this.add = add; + return this; + } + + /** + * Permission to create blobs and files granted. + */ + public boolean create() { + return create; + } + + /** + * Permission to create blobs and files granted. + */ + public AccountSASPermission create(boolean create) { + this.create = create; + return this; + } + + /** + * Permission to write resources granted. + */ + public boolean write() { + return write; + } + + /** + * Permission to write resources granted. + */ + public AccountSASPermission write(boolean write) { + this.write = write; + return this; + } + + /** + * Permission to delete resources granted. + */ + public boolean delete() { + return delete; + } + + /** + * Permission to delete resources granted. + */ + public AccountSASPermission delete(boolean delete) { + this.delete = delete; + return this; + } + + /** + * Permission to list blob containers, blobs, shares, directories, and files granted. + */ + public boolean list() { + return list; + } + + /** + * Permission to list blob containers, blobs, shares, directories, and files granted. + */ + public AccountSASPermission list(boolean list) { + this.list = list; + return this; + } + + /** + * Permissions to update messages and table entities granted. + */ + public boolean update() { + return update; + } + + /** + * Permissions to update messages and table entities granted. + */ + public AccountSASPermission update(boolean update) { + this.update = update; + return this; + } + + /** + * Permission to get and delete messages granted. + */ + public boolean processMessages() { + return processMessages; + } + + /** + * Permission to get and delete messages granted. + */ + public AccountSASPermission processMessages(boolean processMessages) { + this.processMessages = processMessages; + return this; + } + + /** + * Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an + * order accepted by the service. + * + * @return A {@code String} which represents the {@code AccountSASPermissions}. + */ + @Override + public String toString() { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + final StringBuilder builder = new StringBuilder(); + + if (this.read) { + builder.append('r'); + } + + if (this.write) { + builder.append('w'); + } + + if (this.delete) { + builder.append('d'); + } + + if (this.list) { + builder.append('l'); + } + + if (this.add) { + builder.append('a'); + } + + if (this.create) { + builder.append('c'); + } + + if (this.update) { + builder.append('u'); + } + + if (this.processMessages) { + builder.append('p'); + } + + return builder.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASResourceType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASResourceType.java new file mode 100644 index 0000000000000..6fc53c1902937 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASResourceType.java @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.util.Locale; + +/** + * This is a helper class to construct a string representing the resources accessible by an AccountSAS. Setting a value + * to true means that any SAS which uses these permissions will grant access to that resource type. Once all the + * values are set, this should be serialized with toString and set as the resources field on an + * {@link AccountSASSignatureValues} object. It is possible to construct the resources string without this class, but + * the order of the resources is particular and this class guarantees correctness. + */ +final class AccountSASResourceType { + + private boolean service; + + private boolean container; + + private boolean object; + + /** + * Initializes an {@code AccountSASResourceType} object with all fields set to false. + */ + private AccountSASResourceType() { + } + + /** + * Creates an {@code AccountSASResourceType} from the specified resource types string. This method will throw an + * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid resource type. + * + * @param resourceTypesString + * A {@code String} which represents the {@code AccountSASResourceTypes}. + * + * @return A {@code AccountSASResourceType} generated from the given {@code String}. + * @throws IllegalArgumentException If {@code resourceTypesString} contains a character other than s, c, or o. + */ + public static AccountSASResourceType parse(String resourceTypesString) { + AccountSASResourceType resourceType = new AccountSASResourceType(); + + for (int i = 0; i < resourceTypesString.length(); i++) { + char c = resourceTypesString.charAt(i); + switch (c) { + case 's': + resourceType.service = true; + break; + case 'c': + resourceType.container = true; + break; + case 'o': + resourceType.object = true; + break; + default: + throw new IllegalArgumentException( + String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, + "Resource Types", resourceTypesString, c)); + } + } + return resourceType; + } + + /** + * Permission to access service level APIs granted. + */ + public boolean service() { + return service; + } + + /** + * Permission to access service level APIs granted. + */ + public AccountSASResourceType service(boolean service) { + this.service = service; + return this; + } + + /** + * Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted. + */ + public boolean container() { + return container; + } + + /** + * Permission to access container level APIs (Blob Containers, Tables, Queues, File Shares) granted. + */ + public AccountSASResourceType container(boolean container) { + this.container = container; + return this; + } + + /** + * Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted. + */ + public boolean object() { + return object; + } + + /** + * Permission to access object level APIs (Blobs, Table Entities, Queue Messages, Files) granted. + */ + public AccountSASResourceType object(boolean object) { + this.object = object; + return this; + } + + /** + * Converts the given resource types to a {@code String}. Using this method will guarantee the resource types are in + * an order accepted by the service. + * + * @return A {@code String} which represents the {@code AccountSASResourceTypes}. + */ + @Override + public String toString() { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + StringBuilder builder = new StringBuilder(); + + if (this.service) { + builder.append('s'); + } + + if (this.container) { + builder.append('c'); + } + + if (this.object) { + builder.append('o'); + } + + return builder.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASService.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASService.java new file mode 100644 index 0000000000000..0f88ccb2203a9 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASService.java @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.util.Locale; + +/** + * This is a helper class to construct a string representing the services accessible by an AccountSAS. Setting a value + * to true means that any SAS which uses these permissions will grant access to that service. Once all the + * values are set, this should be serialized with toString and set as the services field on an + * {@link AccountSASSignatureValues} object. It is possible to construct the services string without this class, but + * the order of the services is particular and this class guarantees correctness. + */ +final class AccountSASService { + + private boolean blob; + + private boolean file; + + private boolean queue; + + private boolean table; + + /** + * Initializes an {@code AccountSASService} object with all fields set to false. + */ + private AccountSASService() { + } + + /** + * Creates an {@code AccountSASService} from the specified services string. This method will throw an + * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid service. + * + * @param servicesString + * A {@code String} which represents the {@code SharedAccessAccountServices}. + * + * @return A {@code AccountSASService} generated from the given {@code String}. + * @throws IllegalArgumentException If {@code servicesString} contains a character other than b, f, q, or t. + */ + public static AccountSASService parse(String servicesString) { + AccountSASService services = new AccountSASService(); + + for (int i = 0; i < servicesString.length(); i++) { + char c = servicesString.charAt(i); + switch (c) { + case 'b': + services.blob = true; + break; + case 'f': + services.file = true; + break; + case 'q': + services.queue = true; + break; + case 't': + services.table = true; + break; + default: + throw new IllegalArgumentException( + String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Services", + servicesString, c)); + } + } + return services; + } + + /** + * Permission to access blob resources granted. + */ + public boolean blob() { + return blob; + } + + /** + * Permission to access blob resources granted. + */ + public AccountSASService blob(boolean blob) { + this.blob = blob; + return this; + } + + /** + * Permission to access file resources granted. + */ + public boolean file() { + return file; + } + + /** + * Permission to access file resources granted. + */ + public AccountSASService file(boolean file) { + this.file = file; + return this; + } + + /** + * Permission to access queue resources granted. + */ + public boolean queue() { + return queue; + } + + /** + * Permission to access queue resources granted. + */ + public AccountSASService queue(boolean queue) { + this.queue = queue; + return this; + } + + /** + * Permission to access table resources granted. + */ + public boolean table() { + return table; + } + + /** + * Permission to access table resources granted. + */ + public AccountSASService table(boolean table) { + this.table = table; + return this; + } + + /** + * Converts the given services to a {@code String}. Using this method will guarantee the services are in an order + * accepted by the service. + * + * @return A {@code String} which represents the {@code AccountSASServices}. + */ + @Override + public String toString() { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-an-account-sas + StringBuilder value = new StringBuilder(); + + if (this.blob) { + value.append('b'); + } + if (this.queue) { + value.append('q'); + } + if (this.table) { + value.append('t'); + } + if (this.file) { + value.append('f'); + } + + return value.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java new file mode 100644 index 0000000000000..d60118d87b121 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AccountSASSignatureValues.java @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.security.InvalidKeyException; +import java.time.OffsetDateTime; + +/** + * AccountSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage account. Once + * all the values here are set appropriately, call generateSASQueryParameters to obtain a representation of the SAS + * which can actually be applied to blob urls. Note: that both this class and {@link SASQueryParameters} exist because + * the former is mutable and a logical representation while the latter is immutable and used to generate actual REST + * requests. + *

    + * Please see + * here + * for more conceptual information on SAS: + *

    + *

    + * Please see + * here for further + * descriptions of the parameters, including which are required: + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_sas "Sample code for AccountSASSignatureValues")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ +final class AccountSASSignatureValues { + + private String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + + private SASProtocol protocol; + + private OffsetDateTime startTime; + + private OffsetDateTime expiryTime; + + private String permissions; + + private IPRange ipRange; + + private String services; + + private String resourceTypes; + + /** + * Initializes an {@code AccountSASSignatureValues} object with the version number set to the default and all + * other values empty. + */ + AccountSASSignatureValues() { + } + + /** + * If null or empty, this defaults to the service version targeted by this version of the library. + */ + public String version() { + return version; + } + + /** + * If null or empty, this defaults to the service version targeted by this version of the library. + */ + public AccountSASSignatureValues version(String version) { + this.version = version; + return this; + } + + /** + * {@link SASProtocol} + */ + public SASProtocol protocol() { + return protocol; + } + + /** + * {@link SASProtocol} + */ + public AccountSASSignatureValues protocol(SASProtocol protocol) { + this.protocol = protocol; + return this; + } + + /** + * When the SAS will take effect. + */ + public OffsetDateTime startTime() { + return startTime; + } + + /** + * When the SAS will take effect. + */ + public AccountSASSignatureValues startTime(OffsetDateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * The time after which the SAS will no longer work. + */ + public OffsetDateTime expiryTime() { + return expiryTime; + } + + /** + * The time after which the SAS will no longer work. + */ + public AccountSASSignatureValues expiryTime(OffsetDateTime expiryTime) { + this.expiryTime = expiryTime; + return this; + } + + /** + * Specifies which operations the SAS user may perform. Please refer to {@link AccountSASPermission} for help + * constructing the permissions string. + */ + public String permissions() { + return permissions; + } + + /** + * Specifies which operations the SAS user may perform. Please refer to {@link AccountSASPermission} for help + * constructing the permissions string. + */ + public AccountSASSignatureValues permissions(String permissions) { + this.permissions = permissions; + return this; + } + + /** + * {@link IPRange} + */ + public IPRange ipRange() { + return ipRange; + } + + /** + * {@link IPRange} + */ + public AccountSASSignatureValues ipRange(IPRange ipRange) { + this.ipRange = ipRange; + return this; + } + + /** + * The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASService} to + * construct this value. + */ + public String services() { + return services; + } + + /** + * The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASService} to + * construct this value. + */ + public AccountSASSignatureValues services(String services) { + this.services = services; + return this; + } + + /** + * The values that indicate the resource types accessible with this SAS. Please refer + * to {@link AccountSASResourceType} to construct this value. + */ + public String resourceTypes() { + return resourceTypes; + } + + /** + * The values that indicate the resource types accessible with this SAS. Please refer + * to {@link AccountSASResourceType} to construct this value. + */ + public AccountSASSignatureValues resourceTypes(String resourceTypes) { + this.resourceTypes = resourceTypes; + return this; + } + + /** + * Generates a {@link SASQueryParameters} object which contains all SAS query parameters needed to make an actual + * REST request. + * + * @param sharedKeyCredentials + * Credentials for the storage account and corresponding primary or secondary key. + * + * @return {@link SASQueryParameters} + * @throws RuntimeException If the HMAC-SHA256 signature for {@code sharedKeyCredentials} fails to generate. + */ + public SASQueryParameters generateSASQueryParameters(SharedKeyCredential sharedKeyCredentials) { + Utility.assertNotNull("SharedKeyCredential", sharedKeyCredentials); + Utility.assertNotNull("services", this.services); + Utility.assertNotNull("resourceTypes", this.resourceTypes); + Utility.assertNotNull("expiryTime", this.expiryTime); + Utility.assertNotNull("permissions", this.permissions); + Utility.assertNotNull("version", this.version); + + // Signature is generated on the un-url-encoded values. + final String stringToSign = stringToSign(sharedKeyCredentials); + + String signature; + try { + signature = sharedKeyCredentials.computeHmac256(stringToSign); + } catch (InvalidKeyException e) { + throw new RuntimeException(e); // The key should have been validated by now. If it is no longer valid here, we fail. + } + + return new SASQueryParameters(this.version, this.services, resourceTypes, + this.protocol, this.startTime, this.expiryTime, this.ipRange, null, + null, this.permissions, signature, null, null, null, null, null, null); + } + + private String stringToSign(final SharedKeyCredential sharedKeyCredentials) { + return String.join("\n", + sharedKeyCredentials.accountName(), + AccountSASPermission.parse(this.permissions).toString(), // guarantees ordering + this.services, + resourceTypes, + this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(), + this.protocol == null ? "" : this.protocol.toString(), + this.version, + Constants.EMPTY_STRING // Account SAS requires an additional newline character + ); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AnonymousCredentialPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AnonymousCredentialPolicy.java new file mode 100644 index 0000000000000..d54b264702f6b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AnonymousCredentialPolicy.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import reactor.core.publisher.Mono; + +/** + * Anonymous credentials are to be used with with HTTP(S) requests that read blobs from public containers or requests + * that use a Shared Access Signature (SAS). This is because Anonymous credentials will not set an Authorization header. + * Pass an instance of this class as the credentials parameter when creating a new pipeline (typically with + * {@link StorageClient}). + */ +public final class AnonymousCredentialPolicy implements HttpPipelinePolicy { + + /** + * Returns an empty instance of {@code AnonymousCredentials}. + */ + public AnonymousCredentialPolicy() { + } + + + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + return next.process(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java new file mode 100644 index 0000000000000..7b4585580e16f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncClient.java @@ -0,0 +1,190 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.AppendBlobAccessConditions; +import com.azure.storage.blob.models.AppendBlobItem; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.Unpooled; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.nio.ByteBuffer; + + +/** + * Client to an append blob. It may only be instantiated through a {@link AppendBlobClientBuilder#buildAsyncClient()}, via + * the method {@link BlobAsyncClient#asAppendBlobAsyncClient()}, or via the method + * {@link ContainerAsyncClient#getAppendBlobAsyncClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient}, + * and operations on the service are available on {@link StorageAsyncClient}. + * + *

    + * Please refer + * to the Azure Docs + * for more information. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public final class AppendBlobAsyncClient extends BlobAsyncClient { + final AppendBlobAsyncRawClient appendBlobAsyncRawClient; + + /** + * Indicates the maximum number of bytes that can be sent in a call to appendBlock. + */ + public static final int MAX_APPEND_BLOCK_BYTES = 4 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in an append blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Package-private constructor for use by {@link AppendBlobClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + AppendBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { + super(azureBlobStorageBuilder, snapshot); + appendBlobAsyncRawClient = new AppendBlobAsyncRawClient(azureBlobStorageBuilder.build()); + } + + /** + * Creates a 0-length append blob. Call appendBlock to append data to an append blob. + * + * @return + * A reactive response containing the information of the created appended blob. + */ + public Mono> create() { + return this.create(null, null, null); + } + + /** + * Creates a 0-length append blob. Call appendBlock to append data to an append blob. + * + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the information of the created appended blob. + */ + public Mono> create(BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { + return appendBlobAsyncRawClient + .create(headers, metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); + } + + /** + * Commits a new block of data to the end of the existing append blob. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return + * A reactive response containing the information of the append blob operation. + */ + public Mono> appendBlock(Flux data, long length) { + return this.appendBlock(data, length, null); + } + + /** + * Commits a new block of data to the end of the existing append blob. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param appendBlobAccessConditions + * {@link AppendBlobAccessConditions} + * + * @return + * A reactive response containing the information of the append blob operation. + */ + public Mono> appendBlock(Flux data, long length, + AppendBlobAccessConditions appendBlobAccessConditions) { + return appendBlobAsyncRawClient + .appendBlock(data.map(Unpooled::wrappedBuffer), length, appendBlobAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. + * + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * The source {@link BlobRange} to copy. + * + * @return + * A reactive response containing the information of the append blob operation. + */ + public Mono> appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) { + return this.appendBlockFromUrl(sourceURL, sourceRange, null, null, + null); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. + * + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions + * {@link AppendBlobAccessConditions} + * @param sourceAccessConditions + * {@link SourceModifiedAccessConditions} + * + * @return + * A reactive response containing the information of the append blob operation. + */ + public Mono> appendBlockFromUrl(URL sourceURL, BlobRange sourceRange, + byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions) { + return appendBlobAsyncRawClient + .appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new AppendBlobItem(rb.deserializedHeaders()))); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java new file mode 100644 index 0000000000000..15bf8e09e4d1f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobAsyncRawClient.java @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.AppendBlobAccessConditions; +import com.azure.storage.blob.models.AppendBlobsAppendBlockFromUrlResponse; +import com.azure.storage.blob.models.AppendBlobsAppendBlockResponse; +import com.azure.storage.blob.models.AppendBlobsCreateResponse; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; + +import static com.azure.storage.blob.Utility.postProcessResponse; + + +/** + * Represents a URL to an append blob. It may be obtained by direct construction or via the create method on a + * {@link ContainerAsyncClient} object. This class does not hold any state about a particular append blob but is instead a + * convenient way of sending off appropriate requests to the resource on the service. Please refer to the + * Azure Docs + */ +final class AppendBlobAsyncRawClient extends BlobAsyncRawClient { + + /** + * Indicates the maximum number of bytes that can be sent in a call to appendBlock. + */ + public static final int MAX_APPEND_BLOCK_BYTES = 4 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in an append blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Creates a {@code AppendBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided + * pipeline to make HTTP requests. + */ + AppendBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { + super(azureBlobStorage, null); + } + + /** + * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. For more information, see + * the Azure Docs. + * + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create() { + return this.create(null, null, null); + } + + /** + * Creates a 0-length append blob. Call AppendBlock to append data to an append blob. For more information, see + * the Azure Docs. + * + * @param headers {@link BlobHTTPHeaders} + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create(BlobHTTPHeaders headers, Metadata metadata, + BlobAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.appendBlobs().createWithRestResponseAsync(null, + null, 0, null, metadata, null, null, + null, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Commits a new block of data to the end of the existing append blob. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.appendBlock")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono appendBlock(Flux data, long length) { + return this.appendBlock(data, length, null); + } + + /** + * Commits a new block of data to the end of the existing append blob. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param appendBlobAccessConditions {@link AppendBlobAccessConditions} + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_blob "Sample code for AppendBlobAsyncRawClient.appendBlock")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono appendBlock(Flux data, long length, + AppendBlobAccessConditions appendBlobAccessConditions) { + appendBlobAccessConditions = appendBlobAccessConditions == null ? new AppendBlobAccessConditions() + : appendBlobAccessConditions; + + return postProcessResponse(this.azureBlobStorage.appendBlobs().appendBlockWithRestResponseAsync( + null, null, data, length, null, null, + null, null, null, null, + appendBlobAccessConditions.leaseAccessConditions(), + appendBlobAccessConditions.appendPositionAccessConditions(), + appendBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. For more information, see the + * Azure Docs. + *

    + * + * @param sourceURL The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange The source {@link BlobRange} to copy. + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_from_url "Sample code for AppendBlobAsyncRawClient.appendBlockFromUrl")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) { + return this.appendBlockFromUrl(sourceURL, sourceRange, null, null, + null); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. For more information, see the + * Azure Docs. + *

    + * + * @param sourceURL The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange {@link BlobRange} + * @param sourceContentMD5 An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions {@link AppendBlobAccessConditions} + * @param sourceAccessConditions {@link SourceModifiedAccessConditions} + * @return Emits the successful response. + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=append_from_url "Sample code for AppendBlobAsyncRawClient.appendBlockFromUrl")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono appendBlockFromUrl(URL sourceURL, BlobRange sourceRange, + byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions) { + + sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; + destAccessConditions = destAccessConditions == null + ? new AppendBlobAccessConditions() : destAccessConditions; + + return postProcessResponse( + this.azureBlobStorage.appendBlobs().appendBlockFromUrlWithRestResponseAsync(null, null, + sourceURL, 0, sourceRange.toString(), sourceContentMD5, null, null, + destAccessConditions.leaseAccessConditions(), + destAccessConditions.appendPositionAccessConditions(), + destAccessConditions.modifiedAccessConditions(), sourceAccessConditions, Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java new file mode 100644 index 0000000000000..47a379649659f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClient.java @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.storage.blob.models.AppendBlobAccessConditions; +import com.azure.storage.blob.models.AppendBlobItem; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.io.InputStream; +import java.net.URL; +import java.nio.ByteBuffer; +import java.time.Duration; + + +/** + * Client to an append blob. It may only be instantiated through a {@link AppendBlobClientBuilder}, via + * the method {@link BlobClient#asAppendBlobClient()}, or via the method + * {@link ContainerClient#getAppendBlobClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient}, + * and operations on the service are available on {@link StorageClient}. + * + *

    + * Please refer to the Azure Docs + * for more information. + */ +public final class AppendBlobClient extends BlobClient { + + AppendBlobAsyncClient appendBlobAsyncClient; + + /** + * Indicates the maximum number of bytes that can be sent in a call to appendBlock. + */ + public static final int MAX_APPEND_BLOCK_BYTES = 4 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in an append blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Package-private constructor for use by {@link AppendBlobClientBuilder}. + * @param appendBlobAsyncClient the async append blob client + */ + AppendBlobClient(AppendBlobAsyncClient appendBlobAsyncClient) { + super(appendBlobAsyncClient); + this.appendBlobAsyncClient = appendBlobAsyncClient; + } + + /** + * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, + * it will be overwritten. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream() { + return getBlobOutputStream(null); + } + + /** + * Creates and opens an output stream to write data to the append blob. If the blob already exists on the service, + * it will be overwritten. + * + * @param accessConditions + * A {@link BlobAccessConditions} object that represents the access conditions for the blob. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream(AppendBlobAccessConditions accessConditions) { + return new BlobOutputStream(appendBlobAsyncClient, accessConditions); + } + + /** + * Creates a 0-length append blob. Call appendBlock to append data to an append blob. + * + * @return + * The information of the created appended blob. + */ + public Response create() { + return this.create(null, null, null, null); + } + + /** + * Creates a 0-length append blob. Call appendBlock to append data to an append blob. + * + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the created appended blob. + */ + public Response create(BlobHTTPHeaders headers, Metadata metadata, + BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = appendBlobAsyncClient.create(headers, metadata, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Commits a new block of data to the end of the existing append blob. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data + * The data to write to the blob. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return + * The information of the append blob operation. + */ + public Response appendBlock(InputStream data, long length) { + return this.appendBlock(data, length, null, null); + } + + /** + * Commits a new block of data to the end of the existing append blob. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param appendBlobAccessConditions + * {@link AppendBlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the append blob operation. + */ + public Response appendBlock(InputStream data, long length, + AppendBlobAccessConditions appendBlobAccessConditions, Duration timeout) { + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) MAX_APPEND_BLOCK_BYTES)) + .map(i -> i * MAX_APPEND_BLOCK_BYTES) + .concatMap(pos -> Mono.fromCallable(() -> { + long count = pos + MAX_APPEND_BLOCK_BYTES > length ? length - pos : MAX_APPEND_BLOCK_BYTES; + byte[] cache = new byte[(int) count]; + int read = 0; + while (read < count) { + read += data.read(cache, read, (int) count - read); + } + return ByteBuffer.wrap(cache); + })); + + Mono> response = appendBlobAsyncClient.appendBlock(fbb.subscribeOn(Schedulers.elastic()), length, appendBlobAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. + * + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * The source {@link BlobRange} to copy. + * + * @return + * The information of the append blob operation. + */ + public Response appendBlockFromUrl(URL sourceURL, BlobRange sourceRange) { + return this.appendBlockFromUrl(sourceURL, sourceRange, null, null, + null, null); + } + + /** + * Commits a new block of data from another blob to the end of this append blob. + * + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions + * {@link AppendBlobAccessConditions} + * @param sourceAccessConditions + * {@link SourceModifiedAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the append blob operation. + */ + public Response appendBlockFromUrl(URL sourceURL, BlobRange sourceRange, + byte[] sourceContentMD5, AppendBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions, Duration timeout) { + Mono> response = appendBlobAsyncClient.appendBlockFromUrl(sourceURL, sourceRange, sourceContentMD5, destAccessConditions, sourceAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java new file mode 100644 index 0000000000000..c46883e7fecf9 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/AppendBlobClientBuilder.java @@ -0,0 +1,333 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent AppendBlobClientBuilder for instantiating a {@link AppendBlobClient} or {@link AppendBlobAsyncClient} + * using {@link AppendBlobClientBuilder#buildAsyncClient()} or {@link AppendBlobClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link AppendBlobClient} or {@code .buildAsyncClient()} to create a {@link AppendBlobAsyncClient}. + */ +public final class AppendBlobClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private String containerName; + private String blobName; + private String snapshot; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link AppendBlobClient AppendBlobClients} + * and {@link AppendBlobAsyncClient AppendBlobAsyncClients}. + */ + public AppendBlobClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(containerName); + Objects.requireNonNull(blobName); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .pipeline(pipeline); + } + + /** + * @return a {@link AppendBlobClient} created from the configurations in this builder. + */ + public AppendBlobClient buildClient() { + return new AppendBlobClient(buildAsyncClient()); + } + + /** + * @return a {@link AppendBlobAsyncClient} created from the configurations in this builder. + */ + public AppendBlobAsyncClient buildAsyncClient() { + return new AppendBlobAsyncClient(buildImpl(), snapshot); + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name) + * @param endpoint URL of the service + * @return the updated AppendBlobClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL or is using an unknown host. + */ + public AppendBlobClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + BlobURLParts parts = URLParser.parse(url); + this.endpoint = parts.scheme() + "://" + parts.host(); + + if (parts.containerName() != null) { + this.containerName = parts.containerName(); + } + + if (parts.blobName() != null) { + this.blobName = parts.blobName(); + } + + if (parts.snapshot() != null) { + this.snapshot = parts.snapshot(); + } + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * @param containerName the name of the container + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Sets the name of the blob this client is connecting to. + * @param blobName the name of the blob + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * Sets the snapshot of the blob this client is connecting to. + * @param snapshot the snapshot identifier for the blob + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated AppendBlobClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey. + */ + public AppendBlobClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated AppendBlobClientBuilder object + */ + public AppendBlobClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java new file mode 100644 index 0000000000000..7ec72ecf30b53 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncClient.java @@ -0,0 +1,777 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpResponse; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.implementation.http.UrlBuilder; +import com.azure.core.implementation.util.FluxUtil; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.StorageAccountInfo; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; + +/** + * Client to a blob of any type: block, append, or page. It may only be instantiated through a {@link BlobClientBuilder} or via + * the method {@link ContainerAsyncClient#getBlobAsyncClient(String)}. This class does not hold any state about a particular + * blob, but is instead a convenient way of sending appropriate requests to the resource on the service. + * + *

    + * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please + * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. This + * client can be converted into one of these clients easily through the methods {@link #asBlockBlobAsyncClient}, + * {@link #asPageBlobAsyncClient}, and {@link #asAppendBlobAsyncClient()}. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient}, + * and operations on the service are available on {@link StorageAsyncClient}. + * + *

    + * Please refer to the Azure Docs + * for more information. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public class BlobAsyncClient { + private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; + private static final int BLOB_MAX_DOWNLOAD_BLOCK_SIZE = 100 * Constants.MB; + + final BlobAsyncRawClient blobAsyncRawClient; + + /** + * Package-private constructor for use by {@link BlobClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + BlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { + this.blobAsyncRawClient = new BlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); + } + + /** + * Creates a new {@link BlockBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be block blobs. + * + * @return + * A {@link BlockBlobAsyncClient} to this resource. + */ + public BlockBlobAsyncClient asBlockBlobAsyncClient() { + return new BlockBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + } + + /** + * Creates a new {@link AppendBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be append blobs. + * + * @return + * A {@link AppendBlobAsyncClient} to this resource. + */ + public AppendBlobAsyncClient asAppendBlobAsyncClient() { + return new AppendBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + } + + /** + * Creates a new {@link PageBlobAsyncClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be page blobs. + * + * @return + * A {@link PageBlobAsyncClient} to this resource. + */ + public PageBlobAsyncClient asPageBlobAsyncClient() { + return new PageBlobAsyncClient(new AzureBlobStorageBuilder().url(getBlobUrl().toString()).pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline()), blobAsyncRawClient.snapshot); + } + + /** + * Initializes a {@link ContainerAsyncClient} object pointing to the container this blob is in. This method does + * not create a container. It simply constructs the URL to the container and offers access to methods relevant to + * containers. + * + * @return A {@link ContainerAsyncClient} object pointing to the container containing the blob + */ + public ContainerAsyncClient getContainerAsyncClient() { + BlobURLParts parts = URLParser.parse(getBlobUrl()); + return new ContainerAsyncClient(new AzureBlobStorageBuilder() + .url(String.format("%s://%s/%s", parts.scheme(), parts.host(), parts.containerName())) + .pipeline(blobAsyncRawClient.azureBlobStorage.httpPipeline())); + } + + /** + * Gets the URL of the blob represented by this client. + * @return the URL. + * @throws RuntimeException If the blob is using a malformed URL. + */ + public URL getBlobUrl() { + try { + UrlBuilder urlBuilder = UrlBuilder.parse(blobAsyncRawClient.azureBlobStorage.url()); + if (blobAsyncRawClient.snapshot != null) { + urlBuilder.query("snapshot=" + blobAsyncRawClient.snapshot); + } + return urlBuilder.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), blobAsyncRawClient.azureBlobStorage.url()), e); + } + } + + /** + * Gets if the blob this client represents exists in the cloud. + * + * @return + * true if the blob exists, false if it doesn't + */ + public Mono> exists() { + return this.getProperties() + .map(cp -> (Response) new SimpleResponse<>(cp, true)) + .onErrorResume(t -> t instanceof StorageException && ((StorageException) t).statusCode() == 404, t -> { + HttpResponse response = ((StorageException) t).response(); + return Mono.just(new SimpleResponse<>(response.request(), response.statusCode(), response.headers(), false)); + }); + } + + /** + * Copies the data at the source URL to a blob. For more information, see the + * Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * + * @return + * A reactive response containing the copy ID for the long running operation. + */ + public Mono> startCopyFromURL(URL sourceURL) { + return this.startCopyFromURL(sourceURL, null, null, null); + } + + /** + * Copies the data at the source URL to a blob. For more information, see the + * Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * + * @return + * A reactive response containing the copy ID for the long running operation. + */ + public Mono> startCopyFromURL(URL sourceURL, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + return blobAsyncRawClient + .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyId())); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * + * @return + * A reactive response signalling completion. + */ + public Mono abortCopyFromURL(String copyId) { + return this.abortCopyFromURL(copyId, null); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions) { + return blobAsyncRawClient + .abortCopyFromURL(copyId, leaseAccessConditions) + .map(VoidResponse::new); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + * @param copySource + * The source URL to copy from. + * + * @return + * A reactive response containing the copy ID for the long running operation. + */ + public Mono> copyFromURL(URL copySource) { + return this.copyFromURL(copySource, null, null, null); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + * @param copySource + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * + * @return + * A reactive response containing the copy ID for the long running operation. + */ + public Mono> copyFromURL(URL copySource, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + return blobAsyncRawClient + .syncCopyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyId())); + } + + /** + * Reads the entire blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @return + * A reactive response containing the blob data. + */ + public Mono>> download() { + return this.download(null, null, false, null); + } + + /** + * Reads a range of bytes from a blob. Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @param range + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * @param rangeGetContentMD5 + * Whether the contentMD5 for the specified blob range should be returned. + * @param options {@link ReliableDownloadOptions} + * + * @return A reactive response containing the blob data. + */ + public Mono>> download(BlobRange range, BlobAccessConditions accessConditions, + boolean rangeGetContentMD5, ReliableDownloadOptions options) { + return blobAsyncRawClient + .download(range, accessConditions, rangeGetContentMD5) + .map(response -> new SimpleResponse<>( + response.rawResponse(), + response.body(options).map(ByteBuf::nioBuffer).switchIfEmpty(Flux.just(ByteBuffer.allocate(0))))); + } + + /** + * Downloads the entire blob into a file specified by the path. The file will be created if it doesn't exist. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + *

    + * This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra call, + * use the other overload providing the {@link BlobRange} parameter. + * + * @param filePath A non-null {@link OutputStream} instance where the downloaded data will be written. + * @return An empty response + */ + public Mono downloadToFile(String filePath) { + return this.downloadToFile(filePath, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, false, null); + } + + /** + * Downloads a range of bytes blob into a file specified by the path. The file will be created if it doesn't exist. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + *

    + * This method makes an extra HTTP call to get the length of the blob in the beginning. To avoid this extra call, + * provide the {@link BlobRange} parameter. + * + * @param filePath + * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param range + * {@link BlobRange} + * @param blockSize + * the size of a chunk to download at a time, in bytes + * @param accessConditions + * {@link BlobAccessConditions} + * @param rangeGetContentMD5 + * Whether the contentMD5 for the specified blob range should be returned. + * @param options {@link ReliableDownloadOptions} + * @return An empty response + * @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB. + * @throws UncheckedIOException If an I/O error occurs. + */ + public Mono downloadToFile(String filePath, BlobRange range, Integer blockSize, BlobAccessConditions accessConditions, + boolean rangeGetContentMD5, ReliableDownloadOptions options) { + if (blockSize < 0 || blockSize > BLOB_MAX_DOWNLOAD_BLOCK_SIZE) { + throw new IllegalArgumentException("Block size should not exceed 100MB"); + } + + return Mono.using(() -> downloadToFileResourceSupplier(filePath), + channel -> Mono.justOrEmpty(range) + .switchIfEmpty(getFullBlobRange(accessConditions)) + .flatMapMany(rg -> Flux.fromIterable(sliceBlobRange(rg, blockSize))) + .flatMap(chunk -> blobAsyncRawClient + .download(chunk, accessConditions, rangeGetContentMD5) + .subscribeOn(Schedulers.elastic()) + .flatMap(dar -> FluxUtil.bytebufStreamToFile(dar.body(options), channel, chunk.offset() - (range == null ? 0 : range.offset())))) + .then(), this::downloadToFileCleanup); + } + + private AsynchronousFileChannel downloadToFileResourceSupplier(String filePath) { + try { + return AsynchronousFileChannel.open(Paths.get(filePath), StandardOpenOption.READ, StandardOpenOption.WRITE); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private void downloadToFileCleanup(AsynchronousFileChannel channel) { + try { + channel.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private Mono getFullBlobRange(BlobAccessConditions accessConditions) { + return getProperties(accessConditions).map(rb -> new BlobRange(0, rb.value().blobSize())); + } + + private List sliceBlobRange(BlobRange blobRange, Integer blockSize) { + if (blockSize == null) { + blockSize = BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE; + } + long offset = blobRange.offset(); + long length = blobRange.count(); + List chunks = new ArrayList<>(); + for (long pos = offset; pos < offset + length; pos += blockSize) { + long count = blockSize; + if (pos + count > offset + length) { + count = offset + length - pos; + } + chunks.add(new BlobRange(pos, count)); + } + return chunks; + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + * @return + * A reactive response signalling completion. + */ + public Mono delete() { + return this.delete(null, null); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + * @param deleteBlobSnapshotOptions + * Specifies the behavior for deleting the snapshots on this blob. {@code Include} will delete the base blob + * and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being deleted, you must + * pass null. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions) { + return blobAsyncRawClient + .delete(deleteBlobSnapshotOptions, accessConditions) + .map(VoidResponse::new); + } + + /** + * Returns the blob's metadata and properties. + * + * @return + * A reactive response containing the blob properties and metadata. + */ + public Mono> getProperties() { + return this.getProperties(null); + } + + /** + * Returns the blob's metadata and properties. + * + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the blob properties and metadata. + */ + public Mono> getProperties(BlobAccessConditions accessConditions) { + return blobAsyncRawClient + .getProperties(accessConditions) + .map(rb -> new SimpleResponse<>(rb, new BlobProperties(rb.deserializedHeaders()))); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the + * others will all be erased. In order to preserve existing values, they must be + * passed alongside the header being changed. For more information, see the + * Azure Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * + * @return + * A reactive response signalling completion. + */ + public Mono setHTTPHeaders(BlobHTTPHeaders headers) { + return this.setHTTPHeaders(headers, null); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the + * others will all be erased. In order to preserve existing values, they must be + * passed alongside the header being changed. For more information, see the + * Azure Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions) { + return blobAsyncRawClient + .setHTTPHeaders(headers, accessConditions) + .map(VoidResponse::new); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing + * metadata. If old values must be preserved, they must be downloaded and included in the + * call to this method. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * + * @return + * A reactive response signalling completion. + */ + public Mono setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing + * metadata. If old values must be preserved, they must be downloaded and included in the + * call to this method. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono setMetadata(Metadata metadata, BlobAccessConditions accessConditions) { + return blobAsyncRawClient + .setMetadata(metadata, accessConditions) + .map(VoidResponse::new); + } + + /** + * Creates a read-only snapshot of a blob. + * + * @return + * A reactive response containing the ID of the new snapshot. + */ + public Mono> createSnapshot() { + return this.createSnapshot(null, null); + } + + /** + * Creates a read-only snapshot of a blob. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the ID of the new snapshot. + */ + public Mono> createSnapshot(Metadata metadata, BlobAccessConditions accessConditions) { + return blobAsyncRawClient + .createSnapshot(metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().snapshot())); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + * + * @param tier + * The new tier for the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono setTier(AccessTier tier) { + return this.setTier(tier, null); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + * + * @param tier + * The new tier for the blob. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions) { + return blobAsyncRawClient + .setTier(tier, leaseAccessConditions) + .map(VoidResponse::new); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + * @return + * A reactive response signalling completion. + */ + public Mono undelete() { + return blobAsyncRawClient + .undelete() + .map(VoidResponse::new); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedId + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * + * @return + * A reactive response containing the lease ID. + */ + public Mono> acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedID + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the lease ID. + */ + public Mono> acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions) { + return blobAsyncRawClient + .acquireLease(proposedID, duration, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * A reactive response containing the renewed lease ID. + */ + public Mono> renewLease(String leaseID) { + return this.renewLease(leaseID, null); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the renewed lease ID. + */ + public Mono> renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + return blobAsyncRawClient + .renewLease(leaseID, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono releaseLease(String leaseID) { + return this.releaseLease(leaseID, null); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response signalling completion. + */ + public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + return blobAsyncRawClient + .releaseLease(leaseID, modifiedAccessConditions) + .map(VoidResponse::new); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @return + * A reactive response containing the remaining time in the broken lease in seconds. + */ + public Mono> breakLease() { + return this.breakLease(null, null); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the + * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the remaining time in the broken lease in seconds. + */ + public Mono> breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions) { + return blobAsyncRawClient + .breakLease(breakPeriodInSeconds, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseTime())); + } + + /** + * ChangeLease changes the blob's lease ID. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return + * A reactive response containing the new lease ID. + */ + public Mono> changeLease(String leaseId, String proposedID) { + return this.changeLease(leaseId, proposedID, null); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return A reactive response containing the new lease ID. + */ + public Mono> changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions) { + return blobAsyncRawClient + .changeLease(leaseId, proposedID, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * + * @return a reactor response containing the sku name and account kind. + */ + // TODO (unknown): determine this return type + public Mono> getAccountInfo() { + return blobAsyncRawClient + .getAccountInfo() + .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java new file mode 100644 index 0000000000000..002ba761a3bf8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobAsyncRawClient.java @@ -0,0 +1,766 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; +import com.azure.storage.blob.models.BlobsAbortCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsAcquireLeaseResponse; +import com.azure.storage.blob.models.BlobsBreakLeaseResponse; +import com.azure.storage.blob.models.BlobsChangeLeaseResponse; +import com.azure.storage.blob.models.BlobsCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsCreateSnapshotResponse; +import com.azure.storage.blob.models.BlobsDeleteResponse; +import com.azure.storage.blob.models.BlobsGetAccountInfoResponse; +import com.azure.storage.blob.models.BlobsGetPropertiesResponse; +import com.azure.storage.blob.models.BlobsReleaseLeaseResponse; +import com.azure.storage.blob.models.BlobsRenewLeaseResponse; +import com.azure.storage.blob.models.BlobsSetHTTPHeadersResponse; +import com.azure.storage.blob.models.BlobsSetMetadataResponse; +import com.azure.storage.blob.models.BlobsSetTierResponse; +import com.azure.storage.blob.models.BlobsStartCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsUndeleteResponse; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import reactor.core.publisher.Mono; + +import java.net.URL; + +import static com.azure.storage.blob.Utility.postProcessResponse; + +/** + * Represents a URL to a blob of any type: block, append, or page. It may be obtained by direct construction or via the + * create method on a {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is + * instead a convenient way of sending off appropriate requests to the resource on the service. Please refer to the + * Azure Docs for more information. + */ +class BlobAsyncRawClient { + + protected AzureBlobStorageImpl azureBlobStorage; + + final String snapshot; + + /** + * Creates a {@code BlobAsyncRawClient} object pointing to the account specified by the URL and using the provided pipeline to + * make HTTP requests.. + */ + BlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { + this.azureBlobStorage = azureBlobStorage; + this.snapshot = snapshot; + } + + /** + * Copies the data at the source URL to a blob. For more information, see the Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy "Sample code for BlobAsyncRawClient.startCopyFromURL")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy_helper "Helper for start_copy sample.")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono startCopyFromURL(URL sourceURL) { + return this.startCopyFromURL(sourceURL, null, null, null); + } + + /** + * Copies the data at the source URL to a blob. For more information, see the Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy "Sample code for BlobAsyncRawClient.startCopyFromURL")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=start_copy_helper "Helper for start_copy sample.")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono startCopyFromURL(URL sourceURL, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + sourceModifiedAccessConditions = sourceModifiedAccessConditions == null + ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; + destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; + + // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. + SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) + .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) + .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) + .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().startCopyFromURLWithRestResponseAsync( + null, null, sourceURL, null, metadata, null, sourceConditions, + destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. For + * more information, see the Azure Docs. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=abort_copy "Sample code for BlobAsyncRawClient.abortCopyFromURL")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono abortCopyFromURL(String copyId) { + return this.abortCopyFromURL(copyId, null); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. For + * more information, see the Azure Docs. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=abort_copy "Sample code for BlobAsyncRawClient.abortCopyFromURL")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono abortCopyFromURL(String copyId, + LeaseAccessConditions leaseAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blobs().abortCopyFromURLWithRestResponseAsync( + null, null, copyId, null, null, leaseAccessConditions, Context.NONE)); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * For more information, see the Azure Docs + * + * @param copySource + * The source URL to copy from. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=sync_copy "Sample code for BlobAsyncRawClient.copyFromURL")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono syncCopyFromURL(URL copySource) { + return this.syncCopyFromURL(copySource, null, null, null); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * For more information, see the Azure Docs + * + * @param copySource + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=sync_copy "Sample code for BlobAsyncRawClient.copyFromURL")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono syncCopyFromURL(URL copySource, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + sourceModifiedAccessConditions = sourceModifiedAccessConditions == null + ? new ModifiedAccessConditions() : sourceModifiedAccessConditions; + destAccessConditions = destAccessConditions == null ? new BlobAccessConditions() : destAccessConditions; + + // We want to hide the SourceAccessConditions type from the user for consistency's sake, so we convert here. + SourceModifiedAccessConditions sourceConditions = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceModifiedAccessConditions.ifModifiedSince()) + .sourceIfUnmodifiedSince(sourceModifiedAccessConditions.ifUnmodifiedSince()) + .sourceIfMatch(sourceModifiedAccessConditions.ifMatch()) + .sourceIfNoneMatch(sourceModifiedAccessConditions.ifNoneMatch()); + + return postProcessResponse(this.azureBlobStorage.blobs().copyFromURLWithRestResponseAsync( + null, null, copySource, null, metadata, null, sourceConditions, + destAccessConditions.modifiedAccessConditions(), destAccessConditions.leaseAccessConditions(), Context.NONE)); + } + + /** + * Reads a range of bytes from a blob. The response also includes the blob's properties and metadata. For more + * information, see the Azure Docs. + *

    + * Note that the response body has reliable download functionality built in, meaning that a failed download stream + * will be automatically retried. This behavior may be configured with {@link ReliableDownloadOptions}. + * + * @return Emits the successful response. + * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download + * "Sample code for BlobAsyncRawClient.download")] \n For more samples, please see the [Samples + * file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono download() { + return this.download(null, null, false); + } + + /** + * Reads a range of bytes from a blob. The response also includes the blob's properties and metadata. For more + * information, see the Azure Docs. + *

    + * Note that the response body has reliable download functionality built in, meaning that a failed download stream + * will be automatically retried. This behavior may be configured with {@link ReliableDownloadOptions}. + * + * @param range + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * @param rangeGetContentMD5 + * Whether the contentMD5 for the specified blob range should be returned. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlobAsyncRawClient.download")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono download(BlobRange range, BlobAccessConditions accessConditions, + boolean rangeGetContentMD5) { + range = range == null ? new BlobRange(0) : range; + Boolean getMD5 = rangeGetContentMD5 ? rangeGetContentMD5 : null; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + HTTPGetterInfo info = new HTTPGetterInfo() + .offset(range.offset()) + .count(range.count()) + .eTag(accessConditions.modifiedAccessConditions().ifMatch()); + + // TODO: range is BlobRange but expected as String + // TODO: figure out correct response + return postProcessResponse(this.azureBlobStorage.blobs().downloadWithRestResponseAsync( + null, null, snapshot, null, null, range.toHeaderValue(), getMD5, + null, null, null, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)) + // Convert the autorest response to a DownloadAsyncResponse, which enable reliable download. + .map(response -> { + // If there wasn't an etag originally specified, lock on the one returned. + info.eTag(response.deserializedHeaders().eTag()); + return new DownloadAsyncResponse(response, info, + // In the event of a stream failure, make a new request to pick up where we left off. + newInfo -> + this.download(new BlobRange(newInfo.offset(), newInfo.count()), + new BlobAccessConditions().modifiedAccessConditions( + new ModifiedAccessConditions().ifMatch(info.eTag())), false)); + }); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. For more + * information, see the Azure Docs. + * + * @return Emits the successful response. + * @apiNote ## Sample Code \n [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_delete + * "Sample code for BlobAsyncRawClient.delete")] \n For more samples, please see the [Samples + * file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono delete() { + return this.delete(null, null); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. For more + * information, see the Azure Docs. + * + * @param deleteBlobSnapshotOptions + * Specifies the behavior for deleting the snapshots on this blob. {@code Include} will delete the base blob + * and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being deleted, you must + * pass null. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_delete "Sample code for BlobAsyncRawClient.delete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().deleteWithRestResponseAsync( + null, null, snapshot, null, null, deleteBlobSnapshotOptions, + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)); + } + + /** + * Returns the blob's metadata and properties. For more information, see the Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getProperties() { + return this.getProperties(null); + } + + /** + * Returns the blob's metadata and properties. For more information, see the Azure Docs. + * + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getProperties(BlobAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().getPropertiesWithRestResponseAsync( + null, null, snapshot, null, null, null, + null, null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Changes a blob's HTTP header properties. For more information, see the Azure + * Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setHTTPHeaders")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setHTTPHeaders(BlobHTTPHeaders headers) { + return this.setHTTPHeaders(headers, null); + } + + /** + * Changes a blob's HTTP header properties. For more information, see the Azure Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setHTTPHeaders")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setHTTPHeaders(BlobHTTPHeaders headers, + BlobAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setHTTPHeadersWithRestResponseAsync( + null, null, null, null, headers, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Changes a blob's metadata. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null); + } + + /** + * Changes a blob's metadata. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=properties_metadata "Sample code for BlobAsyncRawClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setMetadata(Metadata metadata, BlobAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().setMetadataWithRestResponseAsync( + null, null, null, metadata, null, null, + null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Creates a read-only snapshot of a blob. For more information, see the Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=snapshot "Sample code for BlobAsyncRawClient.createSnapshot")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono createSnapshot() { + return this.createSnapshot(null, null); + } + + /** + * Creates a read-only snapshot of a blob. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=snapshot "Sample code for BlobAsyncRawClient.createSnapshot")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono createSnapshot(Metadata metadata, BlobAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blobs().createSnapshotWithRestResponseAsync( + null, null, null, metadata, null, null, + null, null, accessConditions.modifiedAccessConditions(), + accessConditions.leaseAccessConditions(), Context.NONE)); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + *

    + * For detailed information about block blob level tiering see the Azure Docs. + * + * @param tier + * The new tier for the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=tier "Sample code for BlobAsyncRawClient.setTier")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setTier(AccessTier tier) { + return this.setTier(tier, null); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + *

    + * For detailed information about block blob level tiering see the Azure Docs. + * + * @param tier + * The new tier for the blob. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=tier "Sample code for BlobAsyncRawClient.setTier")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions) { + Utility.assertNotNull("tier", tier); + + return postProcessResponse(this.azureBlobStorage.blobs().setTierWithRestResponseAsync( + null, null, tier, null, null, leaseAccessConditions, Context.NONE)); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * For more information, see the Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=undelete "Sample code for BlobAsyncRawClient.undelete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono undelete() { + return postProcessResponse(this.azureBlobStorage.blobs().undeleteWithRestResponseAsync(null, + null, Context.NONE)); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). For more information, see the Azure Docs. + * + * @param proposedId + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). For more information, see the Azure Docs. + * + * @param proposedID + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code duration} is outside the bounds of 15 to 60 or isn't -1. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono acquireLease(String proposedID, int duration, + ModifiedAccessConditions modifiedAccessConditions) { + if (!(duration == -1 || (duration >= 15 && duration <= 60))) { + // Throwing is preferred to Mono.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("Duration must be -1 or between 15 and 60."); + } + + return postProcessResponse(this.azureBlobStorage.blobs().acquireLeaseWithRestResponseAsync( + null, null, null, duration, proposedID, null, + modifiedAccessConditions, Context.NONE)); + } + + /** + * Renews the blob's previously-acquired lease. For more information, see the Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono renewLease(String leaseID) { + return this.renewLease(leaseID, null); + } + + /** + * Renews the blob's previously-acquired lease. For more information, see the Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blobs().renewLeaseWithRestResponseAsync(null, + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Releases the blob's previously-acquired lease. For more information, see the Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono releaseLease(String leaseID) { + return this.releaseLease(leaseID, null); + } + + /** + * Releases the blob's previously-acquired lease. For more information, see the Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono releaseLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blobs().releaseLeaseWithRestResponseAsync(null, + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. For more information, see the + * Azure Docs. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + * + * @return + * Emits the successful response. + */ + public Mono breakLease() { + return this.breakLease(null, null); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. For more information, see the + * Azure Docs. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the + * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono breakLease(Integer breakPeriodInSeconds, + ModifiedAccessConditions modifiedAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blobs().breakLeaseWithRestResponseAsync(null, + null, null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono changeLease(String leaseId, String proposedID) { + return this.changeLease(leaseId, proposedID, null); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blob_lease "Sample code for BlobAsyncRawClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono changeLease(String leaseId, String proposedID, + ModifiedAccessConditions modifiedAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blobs().changeLeaseWithRestResponseAsync(null, + null, leaseId, proposedID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for BlobAsyncRawClient.getAccountInfo")] \n + * For more samples, please see the [Samples file](https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getAccountInfo() { + return postProcessResponse( + this.azureBlobStorage.blobs().getAccountInfoWithRestResponseAsync(null, null, Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java new file mode 100644 index 0000000000000..f47c3cf6d7830 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClient.java @@ -0,0 +1,803 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlobStartCopyFromURLHeaders; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import com.azure.storage.blob.models.StorageAccountInfo; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.time.Duration; + +/** + * Client to a blob of any type: block, append, or page. It may only be instantiated through a {@link BlobClientBuilder} or via + * the method {@link ContainerClient#getBlobClient(String)}. This class does not hold any state about a particular + * blob, but is instead a convenient way of sending appropriate requests to the resource on the service. + * + *

    + * This client offers the ability to download blobs. Note that uploading data is specific to each type of blob. Please + * refer to the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient} for upload options. This + * client can be converted into one of these clients easily through the methods {@link #asBlockBlobClient}, {@link #asPageBlobClient}, + * and {@link #asAppendBlobClient}. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient}, + * and operations on the service are available on {@link StorageClient}. + * + *

    + * Please refer to the Azure Docs + * for more information. + */ +public class BlobClient { + private static final int BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE = 4 * Constants.MB; + private final BlobAsyncClient blobAsyncClient; + + /** + * Package-private constructor for use by {@link BlobClientBuilder}. + * @param blobAsyncClient the async blob client + */ + BlobClient(BlobAsyncClient blobAsyncClient) { + this.blobAsyncClient = blobAsyncClient; + } + + /** + * Creates a new {@link BlockBlobClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be block blobs. + * + * @return + * A {@link BlockBlobClient} to this resource. + */ + public BlockBlobClient asBlockBlobClient() { + return new BlockBlobClient(blobAsyncClient.asBlockBlobAsyncClient()); + } + + /** + * Creates a new {@link AppendBlobClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be append blobs. + * + * @return + * A {@link AppendBlobClient} to this resource. + */ + public AppendBlobClient asAppendBlobClient() { + return new AppendBlobClient(blobAsyncClient.asAppendBlobAsyncClient()); + } + + /** + * Creates a new {@link PageBlobClient} to this resource, maintaining configurations. Only do this for blobs + * that are known to be page blobs. + * + * @return + * A {@link PageBlobClient} to this resource. + */ + public PageBlobClient asPageBlobClient() { + return new PageBlobClient(blobAsyncClient.asPageBlobAsyncClient()); + } + + /** + * Initializes a {@link ContainerClient} object pointing to the container this blob is in. This method does + * not create a container. It simply constructs the URL to the container and offers access to methods relevant to + * containers. + * + * @return + * A {@link ContainerClient} object pointing to the container containing the blob + */ + public ContainerClient getContainerClient() { + return new ContainerClient(blobAsyncClient.getContainerAsyncClient()); + } + + /** + * Gets the URL of the blob represented by this client. + * @return the URL. + */ + public URL getBlobUrl() { + return blobAsyncClient.getBlobUrl(); + } + + /** + * Opens a blob input stream to download the blob. + *

    + * + * @return An InputStream object that represents the stream to use for reading from the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public final BlobInputStream openInputStream() { + return openInputStream(new BlobRange(0), null); + } + + /** + * Opens a blob input stream to download the specified range of the blob. + *

    + * + * @param range + * {@link BlobRange} + * @param accessConditions + * An {@link BlobAccessConditions} object that represents the access conditions for the blob. + * + * @return An InputStream object that represents the stream to use for reading from the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public final BlobInputStream openInputStream(BlobRange range, BlobAccessConditions accessConditions) { + return new BlobInputStream(blobAsyncClient, range.offset(), range.count(), accessConditions); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + * @return true if the container exists, false if it doesn't + */ + public Response exists() { + return this.exists(null); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return + * true if the container exists, false if it doesn't + */ + public Response exists(Duration timeout) { + Mono> response = blobAsyncClient.exists(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Copies the data at the source URL to a blob. For more information, see the + * Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * + * @return + * The copy ID for the long running operation. + */ + public Response startCopyFromURL(URL sourceURL) { + return this.startCopyFromURL(sourceURL, null, null, null, null); + } + + /** + * Copies the data at the source URL to a blob. For more information, see the + * Azure Docs + * + * @param sourceURL + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The copy ID for the long running operation. + */ + public Response startCopyFromURL(URL sourceURL, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Duration timeout) { + Mono> response = blobAsyncClient + .startCopyFromURL(sourceURL, metadata, sourceModifiedAccessConditions, destAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse abortCopyFromURL(String copyId) { + return this.abortCopyFromURL(copyId, null, null); + } + + /** + * Stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. + * + * @param copyId + * The id of the copy operation to abort. Returned as the {@code copyId} field on the {@link + * BlobStartCopyFromURLHeaders} object. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse abortCopyFromURL(String copyId, LeaseAccessConditions leaseAccessConditions, Duration timeout) { + Mono response = blobAsyncClient + .abortCopyFromURL(copyId, leaseAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + * @param copySource + * The source URL to copy from. + * + * @return + * The copy ID for the long running operation. + */ + public Response copyFromURL(URL copySource) { + return this.copyFromURL(copySource, null, null, null, null); + } + + /** + * Copies the data at the source URL to a blob and waits for the copy to complete before returning a response. + * + * @param copySource + * The source URL to copy from. URLs outside of Azure may only be copied to block blobs. + * @param metadata + * {@link Metadata} + * @param sourceModifiedAccessConditions + * {@link ModifiedAccessConditions} against the source. Standard HTTP Access conditions related to the + * modification of data. ETag and LastModifiedTime are used to construct conditions related to when the blob + * was changed relative to the given request. The request will fail if the specified condition is not + * satisfied. + * @param destAccessConditions + * {@link BlobAccessConditions} against the destination. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The copy ID for the long running operation. + */ + public Response copyFromURL(URL copySource, Metadata metadata, + ModifiedAccessConditions sourceModifiedAccessConditions, BlobAccessConditions destAccessConditions, + Duration timeout) { + Mono> response = blobAsyncClient + .copyFromURL(copySource, metadata, sourceModifiedAccessConditions, destAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Downloads the entire blob into an output stream. Uploading data must be done from the {@link BlockBlobClient}, + * {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @param stream + * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @return A response containing status code and HTTP headers. + * @throws UncheckedIOException If an I/O error occurs. + */ + public VoidResponse download(OutputStream stream) { + return this.download(stream, null, null, null, false, null); + } + + /** + * Downloads a range of bytes from a blob into an output stream. Uploading data must be done from the {@link BlockBlobClient}, + * {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @param stream + * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param options {@link ReliableDownloadOptions} + * @param range + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * @param rangeGetContentMD5 + * Whether the contentMD5 for the specified blob range should be returned. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + * @throws UncheckedIOException If an I/O error occurs. + * + */ + public VoidResponse download(OutputStream stream, ReliableDownloadOptions options, BlobRange range, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) { + Mono download = blobAsyncClient + .download(range, accessConditions, rangeGetContentMD5, options) + .flatMapMany(res -> res.value() + .doOnNext(bf -> { + try { + stream.write(bf.array()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }).map(bf -> res)) + .last() + .map(VoidResponse::new); + + return Utility.blockWithOptionalTimeout(download, timeout); + } + + /** + * Downloads the entire blob into a file specified by the path. The file will be created if it doesn't exist. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @param filePath + * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @throws IOException If an I/O error occurs + */ + public void downloadToFile(String filePath) throws IOException { + this.downloadToFile(filePath, null, null, BLOB_DEFAULT_DOWNLOAD_BLOCK_SIZE, null, false, null); + } + + /** + * Downloads a range of bytes blob into a file specified by the path. The file will be created if it doesn't exist. + * Uploading data must be done from the {@link BlockBlobClient}, {@link PageBlobClient}, or {@link AppendBlobClient}. + * + * @param filePath + * A non-null {@link OutputStream} instance where the downloaded data will be written. + * @param options {@link ReliableDownloadOptions} + * @param range + * {@link BlobRange} + * @param blockSize + * the size of a chunk to download at a time, in bytes + * @param accessConditions + * {@link BlobAccessConditions} + * @param rangeGetContentMD5 + * Whether the contentMD5 for the specified blob range should be returned. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @throws IOException If an I/O error occurs + */ + public void downloadToFile(String filePath, ReliableDownloadOptions options, BlobRange range, Integer blockSize, + BlobAccessConditions accessConditions, boolean rangeGetContentMD5, Duration timeout) throws IOException { + Mono download = blobAsyncClient.downloadToFile(filePath, range, blockSize, accessConditions, rangeGetContentMD5, options); + + try { + Utility.blockWithOptionalTimeout(download, timeout); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + * @return A response containing status code and HTTP headers. + */ + public VoidResponse delete() { + return this.delete(null, null, null); + } + + /** + * Deletes the specified blob or snapshot. Note that deleting a blob also deletes all its snapshots. + * + * @param deleteBlobSnapshotOptions + * Specifies the behavior for deleting the snapshots on this blob. {@code Include} will delete the base blob + * and all snapshots. {@code Only} will delete only the snapshots. If a snapshot is being deleted, you must + * pass null. + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return A response containing status code and HTTP headers. + */ + public VoidResponse delete(DeleteSnapshotsOptionType deleteBlobSnapshotOptions, + BlobAccessConditions accessConditions, Duration timeout) { + Mono response = blobAsyncClient + .delete(deleteBlobSnapshotOptions, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the blob's metadata and properties. + * + * @return + * The blob properties and metadata. + */ + public Response getProperties() { + return this.getProperties(null, null); + } + + /** + * Returns the blob's metadata and properties. + * + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The blob properties and metadata. + */ + public Response getProperties(BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = blobAsyncClient + .getProperties(accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the + * others will all be erased. In order to preserve existing values, they must be + * passed alongside the header being changed. For more information, see the + * Azure Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers) { + return this.setHTTPHeaders(headers, null, null); + } + + /** + * Changes a blob's HTTP header properties. if only one HTTP header is updated, the + * others will all be erased. In order to preserve existing values, they must be + * passed alongside the header being changed. For more information, see the + * Azure Docs. + * + * @param headers + * {@link BlobHTTPHeaders} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setHTTPHeaders(BlobHTTPHeaders headers, BlobAccessConditions accessConditions, + Duration timeout) { + Mono response = blobAsyncClient + .setHTTPHeaders(headers, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing + * metadata. If old values must be preserved, they must be downloaded and included in the + * call to this method. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null, null); + } + + /** + * Changes a blob's metadata. The specified metadata in this method will replace existing + * metadata. If old values must be preserved, they must be downloaded and included in the + * call to this method. For more information, see the Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setMetadata(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { + Mono response = blobAsyncClient + .setMetadata(metadata, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Creates a read-only snapshot of a blob. + * + * @return + * The ID of the new snapshot. + */ + public Response createSnapshot() { + return this.createSnapshot(null, null, null); + } + + /** + * Creates a read-only snapshot of a blob. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The ID of the new snapshot. + */ + public Response createSnapshot(Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = blobAsyncClient + .createSnapshot(metadata, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + * + * @param tier + * The new tier for the blob. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setTier(AccessTier tier) { + return this.setTier(tier, null, null); + } + + /** + * Sets the tier on a blob. The operation is allowed on a page blob in a premium storage account or a block blob in + * a blob storage or GPV2 account. A premium page blob's tier determines the allowed size, IOPS, and bandwidth of + * the blob. A block blob's tier determines the Hot/Cool/Archive storage type. This does not update the blob's etag. + * + * @param tier + * The new tier for the blob. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse setTier(AccessTier tier, LeaseAccessConditions leaseAccessConditions, Duration timeout) { + Mono response = blobAsyncClient + .setTier(tier, leaseAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + * @return A response containing status code and HTTP headers. + */ + public VoidResponse undelete() { + return this.undelete(null); + } + + /** + * Undelete restores the content and metadata of a soft-deleted blob and/or any associated soft-deleted snapshots. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse undelete(Duration timeout) { + Mono response = blobAsyncClient + .undelete(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedId + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * + * @return + * The lease ID. + */ + public Response acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null, null); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedID + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The lease ID. + */ + public Response acquireLease(String proposedID, int duration, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = blobAsyncClient + .acquireLease(proposedID, duration, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * The renewed lease ID. + */ + public Response renewLease(String leaseID) { + return this.renewLease(leaseID, null, null); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The renewed lease ID. + */ + public Response renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, + Duration timeout) { + Mono> response = blobAsyncClient + .renewLease(leaseID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse releaseLease(String leaseID) { + return this.releaseLease(leaseID, null, null); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse releaseLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = blobAsyncClient + .releaseLease(leaseID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @return + * The remaining time in the broken lease in seconds. + */ + public Response breakLease() { + return this.breakLease(null, null, null); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the + * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The remaining time in the broken lease in seconds. + */ + public Response breakLease(Integer breakPeriodInSeconds, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = blobAsyncClient + .breakLease(breakPeriodInSeconds, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * ChangeLease changes the blob's lease ID. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return + * The new lease ID. + */ + public Response changeLease(String leaseId, String proposedID) { + return this.changeLease(leaseId, proposedID, null, null); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return The new lease ID. + */ + public Response changeLease(String leaseId, String proposedID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = blobAsyncClient + .changeLease(leaseId, proposedID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * + * @return The sku name and account kind. + */ + public Response getAccountInfo() { + return this.getAccountInfo(null); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the Azure Docs. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return The sku name and account kind. + */ + public Response getAccountInfo(Duration timeout) { + Mono> response = blobAsyncClient + .getAccountInfo(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java new file mode 100644 index 0000000000000..2238af18e48e9 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java @@ -0,0 +1,333 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent BlobClientBuilder for instantiating a {@link BlobClient} or {@link BlobAsyncClient} + * using {@link BlobClientBuilder#buildClient()} or {@link BlobClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link BlobClient} or {@code .buildAsyncClient()} to create a {@link BlobAsyncClient}. + */ +public final class BlobClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private String containerName; + private String blobName; + private String snapshot; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link BlobClient BlobClients} + * and {@link BlobAsyncClient BlobAsyncClients}. + */ + public BlobClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(containerName); + Objects.requireNonNull(blobName); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .pipeline(pipeline); + } + + /** + * @return a {@link BlobClient} created from the configurations in this builder. + */ + public BlobClient buildClient() { + return new BlobClient(buildAsyncClient()); + } + + /** + * @return a {@link BlobAsyncClient} created from the configurations in this builder. + */ + public BlobAsyncClient buildAsyncClient() { + return new BlobAsyncClient(buildImpl(), snapshot); + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name) + * @param endpoint URL of the service + * @return the updated BlobClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL. + */ + public BlobClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + BlobURLParts parts = URLParser.parse(url); + this.endpoint = parts.scheme() + "://" + parts.host(); + + if (parts.containerName() != null) { + this.containerName = parts.containerName(); + } + + if (parts.blobName() != null) { + this.blobName = parts.blobName(); + } + + if (parts.snapshot() != null) { + this.snapshot = parts.snapshot(); + } + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * @param containerName the name of the container + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Sets the name of the blob this client is connecting to. + * @param blobName the name of the blob + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * Sets the snapshot of the blob this client is connecting to. + * @param snapshot the snapshot identifier for the blob + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated BlobClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey. + */ + public BlobClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated BlobClientBuilder object + */ + public BlobClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobConfiguration.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobConfiguration.java new file mode 100644 index 0000000000000..ae1e422a24c0a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobConfiguration.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.blob; + +class BlobConfiguration { + static final String NAME = "storage-blob"; + static final String VERSION = "1.0.0-SNAPSHOT"; +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java new file mode 100644 index 0000000000000..2e093f50738f2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobInputStream.java @@ -0,0 +1,456 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.blob; + +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobRange; +import reactor.netty.ByteBufFlux; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + +/** + * Provides an input stream to read a given blob resource. + */ +public final class BlobInputStream extends InputStream { + /** + * Holds the reference to the blob this stream is associated with. + */ + private final BlobAsyncClient blobClient; + + /** + * A flag to determine if the stream is faulted, if so the last error will be thrown on next operation. + */ + private volatile boolean streamFaulted; + + /** + * Holds the last exception this stream encountered. + */ + private IOException lastError; + + /** + * Holds the stream length. + */ + private long streamLength; + + /** + * Holds the stream read size for both block and page blobs. + */ + private final int readSize; + + /** + * Holds the reference to the current buffered data. + */ + private ByteBuffer currentBuffer; + + /** + * Holds an absolute byte position for the mark feature. + */ + private long markedPosition; + + /** + * Holds the mark delta for which the mark position is expired. + */ + private int markExpiry; + + /** + * Holds an absolute byte position of the current read position. + */ + private long currentAbsoluteReadPosition; + + /** + * Holds the absolute byte position of the start of the current buffer. + */ + private long bufferStartOffset; + + /** + * Holds the length of the current buffer in bytes. + */ + private int bufferSize; + + /** + * Holds the {@link BlobAccessConditions} object that represents the access conditions for the blob. + */ + private BlobAccessConditions accessCondition; + + /** + * Offset of the source blob this class is configured to stream from. + */ + private final long blobRangeOffset; + + /** + * Initializes a new instance of the BlobInputStream class. + * + * @param blobClient + * A {@link BlobClient} object which represents the blob that this stream is associated with. + * @param accessCondition + * An {@link BlobAccessConditions} object which represents the access conditions for the blob. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + BlobInputStream(final BlobAsyncClient blobClient, final BlobAccessConditions accessCondition) throws StorageException { + this(blobClient, 0, null, accessCondition); + } + + /** + * Initializes a new instance of the BlobInputStream class. + * Note that if {@code blobRangeOffset} is not {@code 0} or {@code blobRangeLength} is not {@code null}, there will + * be no content MD5 verification. + * + * @param blobClient + * A {@link BlobClient} object which represents the blob that this stream is associated with. + * @param blobRangeOffset + * The offset of blob data to begin stream. + * @param blobRangeLength + * How much data the stream should return after blobRangeOffset. + * @param accessCondition + * An {@link BlobAccessConditions} object which represents the access conditions for the blob. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + BlobInputStream(final BlobAsyncClient blobClient, long blobRangeOffset, Long blobRangeLength, + final BlobAccessConditions accessCondition) + throws StorageException { + + this.blobRangeOffset = blobRangeOffset; + this.blobClient = blobClient; + this.streamFaulted = false; + this.currentAbsoluteReadPosition = blobRangeOffset; + this.readSize = 4 * Constants.MB; + this.accessCondition = accessCondition; + + if (blobRangeOffset < 0 || (blobRangeLength != null && blobRangeLength <= 0)) { + throw new IndexOutOfBoundsException(); + } + + BlobProperties properties = blobClient.getProperties().block().value(); + this.streamLength = blobRangeLength == null + ? properties.blobSize() - this.blobRangeOffset + : Math.min(properties.blobSize() - this.blobRangeOffset, blobRangeLength); + + this.reposition(blobRangeOffset); + } + + /** + * Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without + * blocking by the next invocation of a method for this input stream. The next invocation might be the same thread + * or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes. + * + * @return An int which represents an estimate of the number of bytes that can be read (or skipped + * over) + * from this input stream without blocking, or 0 when it reaches the end of the input stream. + * + * @throws IOException + * If an I/O error occurs. + */ + @Override + public synchronized int available() throws IOException { + return this.bufferSize - (int) (this.currentAbsoluteReadPosition - this.bufferStartOffset); + } + + /** + * Helper function to check if the stream is faulted, if it is it surfaces the exception. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + private synchronized void checkStreamState() throws IOException { + if (this.streamFaulted) { + throw this.lastError; + } + } + + /** + * Closes this input stream and releases any system resources associated with the stream. + * + * @throws IOException + * If an I/O error occurs. + */ + @Override + public synchronized void close() throws IOException { + this.currentBuffer = null; + this.streamFaulted = true; + this.lastError = new IOException(SR.STREAM_CLOSED); + } + + /** + * Dispatches a read operation of N bytes. When using sparse page blobs, the page ranges are evaluated and zero + * bytes may be generated on the client side for some ranges that do not exist. + * + * @param readLength + * An int which represents the number of bytes to read. + * + * @throws IOException + * If an I/O error occurs. + */ + private synchronized void dispatchRead(final int readLength) throws IOException { + try { + this.currentBuffer = this.blobClient.blobAsyncRawClient.download(new BlobRange(this.currentAbsoluteReadPosition, (long) readLength), this.accessCondition, false) + .flatMap(res -> ByteBufFlux.fromInbound(res.body(null)).aggregate().asByteBuffer()) + .block(); + + this.bufferSize = readLength; + this.bufferStartOffset = this.currentAbsoluteReadPosition; + } catch (final StorageException e) { + this.streamFaulted = true; + this.lastError = new IOException(e); + throw this.lastError; + } + } + + /** + * Marks the current position in this input stream. A subsequent call to the reset method repositions this stream at + * the last marked position so that subsequent reads re-read the same bytes. + * + * @param readlimit + * An int which represents the maximum limit of bytes that can be read before the mark + * position becomes invalid. + */ + @Override + public synchronized void mark(final int readlimit) { + this.markedPosition = this.currentAbsoluteReadPosition; + this.markExpiry = readlimit; + } + + /** + * Tests if this input stream supports the mark and reset methods. Whether or not mark and reset are supported is an + * invariant property of a particular input stream instance. The markSupported method of {@link InputStream} returns + * false. + * + * @return True if this stream instance supports the mark and reset methods; False + * otherwise. + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If + * no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks + * until input data is available, the end of the stream is detected, or an exception is thrown. + * + * @return An int which represents the total number of bytes read into the buffer, or -1 if + * there is no more data because the end of the stream has been reached. + * + * @throws IOException + * If an I/O error occurs. + */ + @Override + public int read() throws IOException { + final byte[] tBuff = new byte[1]; + final int numberOfBytesRead = this.read(tBuff, 0, 1); + + if (numberOfBytesRead > 0) { + return tBuff[0] & 0xFF; + } else if (numberOfBytesRead == 0) { + throw new IOException(SR.UNEXPECTED_STREAM_READ_ERROR); + } else { + return -1; + } + } + + /** + * Reads some number of bytes from the input stream and stores them into the buffer array b. The number + * of bytes + * actually read is returned as an integer. This method blocks until input data is available, end of file is + * detected, or an exception is thrown. If the length of b is zero, then no bytes are read and 0 is + * returned; + * otherwise, there is an attempt to read at least one byte. If no byte is available because the stream is at the + * end of the file, the value -1 is returned; otherwise, at least one byte is read and stored into b. + * + * The first byte read is stored into element b[0], the next one into b[1], and so on. The + * number of bytes read is, + * at most, equal to the length of b. Let k be the number of bytes actually read; these + * bytes will be stored in + * elements b[0] through b[k-1], leaving elements b[k] through + * b[b.length-1] unaffected. + * + * The read(b) method for class {@link InputStream} has the same effect as: + * + * read(b, 0, b.length) + * + * @param b + * A byte array which represents the buffer into which the data is read. + * + * @throws IOException + * If the first byte cannot be read for any reason other than the end of the file, if the input stream + * has been closed, or if some other I/O error occurs. + * @throws NullPointerException + * If the byte array b is null. + */ + @Override + public int read(final byte[] b) throws IOException { + return this.read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to + * read as many as len bytes, but a smaller number may be read. The number of bytes actually read is + * returned as an integer. This + * method blocks until input data is available, end of file is detected, or an exception is thrown. + * + * If len is zero, then no bytes are read and 0 is returned; otherwise, there is an attempt to read at + * least one + * byte. If no byte is available because the stream is at end of file, the value -1 is returned; otherwise, at least + * one byte is read and stored into b. + * + * The first byte read is stored into element b[off], the next one into b[off+1], and so + * on. The number of bytes + * read is, at most, equal to len. Let k be the number of bytes actually read; these bytes + * will be stored in + * elements b[off] through b[off+k-1], leaving elements b[off+k] through + * b[off+len-1] unaffected. + * + * In every case, elements b[0] through b[off] and elements b[off+len] + * through b[b.length-1] are unaffected. + * + * The read(b, off, len) method for class {@link InputStream} simply calls the method + * read() repeatedly. If the first such + * call results in an IOException, that exception is returned from the call to the + * read(b, off, len) method. If any + * subsequent call to read() results in a IOException, the exception is caught and treated + * as if it were end of + * file; the bytes read up to that point are stored into b and the number of bytes read before the + * exception + * occurred is returned. The default implementation of this method blocks until the requested amount of input data + * len has been read, end of file is detected, or an exception is thrown. Subclasses are encouraged to + * provide a + * more efficient implementation of this method. + * + * @param b + * A byte array which represents the buffer into which the data is read. + * @param off + * An int which represents the start offset in the byte array at which the data + * is written. + * @param len + * An int which represents the maximum number of bytes to read. + * + * @return An int which represents the total number of bytes read into the buffer, or -1 if + * there is no more data because the end of the stream has been reached. + * + * @throws IOException + * If the first byte cannot be read for any reason other than end of file, or if the input stream has + * been closed, or if some other I/O error occurs. + * @throws NullPointerException + * If the byte array b is null. + * @throws IndexOutOfBoundsException + * If off is negative, len is negative, or len is greater than + * b.length - off. + */ + @Override + public int read(final byte[] b, final int off, final int len) throws IOException { + if (off < 0 || len < 0 || len > b.length - off) { + throw new IndexOutOfBoundsException(); + } + + return this.readInternal(b, off, len); + } + + /** + * Performs internal read to the given byte buffer. + * + * @param b + * A byte array which represents the buffer into which the data is read. + * @param off + * An int which represents the start offset in the byte array b at + * which the data is written. + * @param len + * An int which represents the maximum number of bytes to read. + * + * @return An int which represents the total number of bytes read into the buffer, or -1 if + * there is no more data because the end of the stream has been reached. + * + * @throws IOException + * If the first byte cannot be read for any reason other than end of file, or if the input stream has + * been closed, or if some other I/O error occurs. + */ + private synchronized int readInternal(final byte[] b, final int off, int len) throws IOException { + this.checkStreamState(); + + // if buffer is empty do next get operation + if ((this.currentBuffer == null || this.currentBuffer.remaining() == 0) + && this.currentAbsoluteReadPosition < this.streamLength + this.blobRangeOffset) { + this.dispatchRead((int) Math.min(this.readSize, this.streamLength + this.blobRangeOffset - this.currentAbsoluteReadPosition)); + } + + len = Math.min(len, this.readSize); + + final int numberOfBytesRead; + if (currentBuffer.remaining() == 0) { + numberOfBytesRead = -1; + } else { + numberOfBytesRead = Math.min(len, this.currentBuffer.remaining()); + // do read from buffer + this.currentBuffer = this.currentBuffer.get(b, off, numberOfBytesRead); + } + + if (numberOfBytesRead > 0) { + this.currentAbsoluteReadPosition += numberOfBytesRead; + } + + // update markers + if (this.markExpiry > 0 && this.markedPosition + this.markExpiry < this.currentAbsoluteReadPosition) { + this.markedPosition = this.blobRangeOffset; + this.markExpiry = 0; + } + + return numberOfBytesRead; + } + + /** + * Repositions the stream to the given absolute byte offset. + * + * @param absolutePosition + * A long which represents the absolute byte offset withitn the stream reposition. + */ + private synchronized void reposition(final long absolutePosition) { + this.currentAbsoluteReadPosition = absolutePosition; + this.currentBuffer = ByteBuffer.allocate(0); + this.bufferStartOffset = absolutePosition; + } + + /** + * Repositions this stream to the position at the time the mark method was last called on this input stream. Note + * repositioning the blob read stream will disable blob MD5 checking. + * + * @throws IOException + * If this stream has not been marked or if the mark has been invalidated. + */ + @Override + public synchronized void reset() throws IOException { + if (this.markedPosition + this.markExpiry < this.currentAbsoluteReadPosition) { + throw new IOException(SR.MARK_EXPIRED); + } + this.reposition(this.markedPosition); + } + + /** + * Skips over and discards n bytes of data from this input stream. The skip method may, for a variety of reasons, + * end up skipping over some smaller number of bytes, possibly 0. This may result from any of a number of + * conditions; reaching end of file before n bytes have been skipped is only one possibility. The actual number of + * bytes skipped is returned. If n is negative, no bytes are skipped. + * + * Note repositioning the blob read stream will disable blob MD5 checking. + * + * @param n + * A long which represents the number of bytes to skip. + */ + @Override + public synchronized long skip(final long n) throws IOException { + if (n == 0) { + return 0; + } + + if (n < 0 || this.currentAbsoluteReadPosition + n > this.streamLength + this.blobRangeOffset) { + throw new IndexOutOfBoundsException(); + } + + this.reposition(this.currentAbsoluteReadPosition + n); + return n; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java new file mode 100644 index 0000000000000..176fe06c321d1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobOutputStream.java @@ -0,0 +1,671 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.blob; + +import com.azure.storage.blob.models.AppendBlobAccessConditions; +import com.azure.storage.blob.models.AppendPositionAccessConditions; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.PageBlobAccessConditions; +import com.azure.storage.blob.models.PageRange; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import reactor.core.CoreSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.publisher.Operators; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; + + +public class BlobOutputStream extends OutputStream { + /** + * Holds the {@link BlobAccessConditions} object that represents the access conditions for the blob. + */ + private BlobAccessConditions accessCondition; + + private AppendPositionAccessConditions appendPositionAccessConditions; + + /** + * Used for block blobs, holds the block id prefix. + */ + private String blockIdPrefix; + + /** + * Used for block blobs, holds the block list. + */ + private TreeMap blockList; + + /** + * Holds the write threshold of number of bytes to buffer prior to dispatching a write. For block blob this is the + * block size, for page blob this is the Page commit size. + */ + private int internalWriteThreshold = -1; + + /** + * Holds the last exception this stream encountered. + */ + private volatile IOException lastError = null; + + + private long initialBlobOffset; + + /** + * Holds the reference to the blob this stream is associated with. + */ + private final BlobAsyncClient blobClient; + + /** + * Determines if this stream is used against a page blob or block blob. + */ + private BlobType streamType = BlobType.BLOCK_BLOB; + + /** + * Initializes a new instance of the BlobOutputStream class. + * + * @param parentBlob + * A {@link BlobAsyncClient} object which represents the blob that this stream is associated with. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + private BlobOutputStream(final BlobAsyncClient parentBlob) throws StorageException { + this.blobClient = parentBlob; +// completion = Flux.defer(() -> { +// if (this.streamType == BlobType.APPEND_BLOB) { +// return writeProcessor.concatMap(b -> { +// long offset = currentOffset.getAndAdd(b.length); +// return dispatchWrite(b, offset); +// }); +// } else { +// return writeProcessor.map(b -> Tuples.of(b, currentOffset.getAndAdd(b.length))) +// .flatMap(chunk -> dispatchWrite(chunk.getT1(), chunk.getT2())); +// } +// }) +// .doOnError(t -> { +// if (t instanceof IOException) { +// lastError = (IOException) t; +// } else { +// lastError = new IOException(t); +// } +// completionSink.error(t); +// }) +// .doOnNext(length -> completionSink.next(length)) +// .doOnComplete(() -> completionSink.complete()); + } + + /** + * Initializes a new instance of the BlobOutputStream class for a CloudBlockBlob + * + * @param parentBlob + * A {@link BlobAsyncClient} object which represents the blob that this stream is associated with. + * @param accessCondition + * An {@link BlobAccessConditions} object which represents the access conditions for the blob. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + BlobOutputStream(final BlockBlobAsyncClient parentBlob, final BlobAccessConditions accessCondition) throws StorageException { + this((BlobAsyncClient) parentBlob); + + this.accessCondition = accessCondition; + this.blockList = new TreeMap<>(); + this.blockIdPrefix = UUID.randomUUID().toString() + "-"; + + this.streamType = BlobType.BLOCK_BLOB; + this.internalWriteThreshold = (int) BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + } + + /** + * Initializes a new instance of the BlobOutputStream class for a CloudPageBlob + * + * @param parentBlob + * A {@link PageBlobClient} object which represents the blob that this stream is associated with. + * @param length + * A long which represents the length of the page blob in bytes, which must be a multiple of + * 512. + * @param accessCondition + * An {@link BlobAccessConditions} object which represents the access conditions for the blob. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + BlobOutputStream(final PageBlobAsyncClient parentBlob, final long length, final BlobAccessConditions accessCondition) + throws StorageException { + this((BlobAsyncClient) parentBlob); + this.streamType = BlobType.PAGE_BLOB; + this.accessCondition = accessCondition; + this.internalWriteThreshold = (int) Math.min(BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE, length); + } + + /** + * Initializes a new instance of the BlobOutputStream class for a CloudAppendBlob + * + * @param parentBlob + * A {@link AppendBlobAsyncClient} object which represents the blob that this stream is associated with. + * @param accessCondition + * An {@link BlobAccessConditions} object which represents the access conditions for the blob. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + BlobOutputStream(final AppendBlobAsyncClient parentBlob, final AppendBlobAccessConditions accessCondition) + throws StorageException { + this((BlobAsyncClient) parentBlob); + this.streamType = BlobType.APPEND_BLOB; + + this.accessCondition = new BlobAccessConditions(); + if (accessCondition != null) { + this.appendPositionAccessConditions = accessCondition.appendPositionAccessConditions(); + this.accessCondition = new BlobAccessConditions().modifiedAccessConditions(accessCondition.modifiedAccessConditions()).leaseAccessConditions(accessCondition.leaseAccessConditions()); + if (accessCondition.appendPositionAccessConditions().appendPosition() != null) { + this.initialBlobOffset = accessCondition.appendPositionAccessConditions().appendPosition(); + } else { + this.initialBlobOffset = parentBlob.getProperties().block().value().blobSize(); + } + } + + this.internalWriteThreshold = (int) BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + } + + /** + * Helper function to check if the stream is faulted, if it is it surfaces the exception. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + private void checkStreamState() throws IOException { + if (this.lastError != null) { + throw this.lastError; + } + } + + /** + * Closes this output stream and releases any system resources associated with this stream. If any data remains in + * the buffer it is committed to the service. + * + * @throws IOException + * If an I/O error occurs. + */ + @Override + public synchronized void close() throws IOException { + try { + // if the user has already closed the stream, this will throw a STREAM_CLOSED exception + // if an exception was thrown by any thread in the threadExecutor, realize it now + this.checkStreamState(); + + // flush any remaining data + this.flush(); + + // try to commit the blob + try { + this.commit(); + } catch (final StorageException e) { + throw new IOException(e); + } + } finally { + // if close() is called again, an exception will be thrown + this.lastError = new IOException(SR.STREAM_CLOSED); + } + } + + /** + * Commits the blob, for block blob this uploads the block list. + * + * @throws StorageException + * An exception representing any error which occurred during the operation. + */ + private synchronized void commit() throws StorageException { + if (this.streamType == BlobType.BLOCK_BLOB) { + // wait for all blocks to finish + assert this.blobClient instanceof BlockBlobAsyncClient; + final BlockBlobAsyncClient blobRef = (BlockBlobAsyncClient) this.blobClient; + blobRef.commitBlockList(new ArrayList<>(this.blockList.values()), null, null, this.accessCondition).block(); + } + } + + /** + * Dispatches a write operation for a given length. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + private Mono dispatchWrite(Flux bufferRef, int writeLength, long offset) { + if (writeLength == 0) { + return Mono.empty(); + } + + if (this.streamType == BlobType.PAGE_BLOB && (writeLength % Constants.PAGE_SIZE != 0)) { + return Mono.error(new IOException(String.format(SR.INVALID_NUMBER_OF_BYTES_IN_THE_BUFFER, writeLength))); + } + + if (this.streamType == BlobType.BLOCK_BLOB) { + final String blockID = this.getCurrentBlockId(); + this.blockList.put(offset, blockID); + return BlobOutputStream.this.writeBlock(bufferRef, blockID, writeLength).then(Mono.just(writeLength)); + } else if (this.streamType == BlobType.PAGE_BLOB) { + return BlobOutputStream.this.writePages(bufferRef, offset, writeLength).then(Mono.just(writeLength)); + } else if (this.streamType == BlobType.APPEND_BLOB) { + // We cannot differentiate between max size condition failing only in the retry versus failing in the + // first attempt and retry even for a single writer scenario. So we will eliminate the latter and handle + // the former in the append block method. + if (this.appendPositionAccessConditions != null && this.appendPositionAccessConditions.maxSize() != null + && this.initialBlobOffset > this.appendPositionAccessConditions.maxSize()) { + this.lastError = new IOException(SR.INVALID_BLOCK_SIZE); + return Mono.error(this.lastError); + } + + return BlobOutputStream.this.appendBlock(bufferRef, offset, writeLength).then(Mono.justOrEmpty(writeLength)); + } else { + return Mono.error(new RuntimeException("Unknown blob type " + this.streamType)); + } + } + + private Mono writeBlock(Flux blockData, String blockId, long writeLength) { + assert this.blobClient instanceof BlockBlobAsyncClient; + final BlockBlobAsyncClient blobRef = (BlockBlobAsyncClient) this.blobClient; + + LeaseAccessConditions leaseAccessConditions = accessCondition == null ? null : accessCondition.leaseAccessConditions(); + + return blobRef.stageBlock(blockId, blockData, writeLength, leaseAccessConditions) + .then() + .onErrorResume(t -> t instanceof StorageException, e -> { + this.lastError = new IOException(e); + return null; + }); + } + + private Mono writePages(Flux pageData, long offset, long writeLength) { + assert this.blobClient instanceof PageBlobAsyncClient; + final PageBlobAsyncClient blobRef = (PageBlobAsyncClient) this.blobClient; + + PageBlobAccessConditions pageBlobAccessConditions = accessCondition == null ? null : new PageBlobAccessConditions().leaseAccessConditions(accessCondition.leaseAccessConditions()).modifiedAccessConditions(accessCondition.modifiedAccessConditions()); + + return blobRef.pageBlobAsyncRawClient.uploadPages(new PageRange().start(offset).end(offset + writeLength - 1), pageData, pageBlobAccessConditions) + .then() + .onErrorResume(t -> t instanceof StorageException, e -> { + this.lastError = new IOException(e); + return null; + }); + } + + private Mono appendBlock(Flux blockData, long offset, long writeLength) { + assert this.blobClient instanceof AppendBlobAsyncClient; + final AppendBlobAsyncClient blobRef = (AppendBlobAsyncClient) this.blobClient; + if (this.appendPositionAccessConditions == null) { + appendPositionAccessConditions = new AppendPositionAccessConditions(); + } + this.appendPositionAccessConditions.appendPosition(offset); + + AppendBlobAccessConditions appendBlobAccessConditions = accessCondition == null ? null : new AppendBlobAccessConditions().leaseAccessConditions(accessCondition.leaseAccessConditions()).modifiedAccessConditions(accessCondition.modifiedAccessConditions()); + return blobRef.appendBlobAsyncRawClient.appendBlock(blockData, writeLength, appendBlobAccessConditions) + .then() + .onErrorResume(t -> t instanceof IOException || t instanceof StorageException, e -> { + this.lastError = new IOException(e); + return null; + }); + } + + /** + * Flushes this output stream and forces any buffered output bytes to be written out. If any data remains in the + * buffer it is committed to the service. + * + * @throws IOException + * If an I/O error occurs. + */ + @Override + public void flush() throws IOException { + this.checkStreamState(); + } + + /** + * Generates a new block ID to be used for PutBlock. + * + * @return Base64 encoded block ID + */ + private String getCurrentBlockId() { + String blockIdSuffix = String.format("%06d", this.blockList.size()); + + byte[] blockIdInBytes; + blockIdInBytes = (this.blockIdPrefix + blockIdSuffix).getBytes(StandardCharsets.UTF_8); + + return Base64.getEncoder().encodeToString(blockIdInBytes); + } + + /** + * Writes b.length bytes from the specified byte array to this output stream. + *

    + * + * @param data + * A byte array which represents the data to write. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + @Override + public void write(final byte[] data) throws IOException { + this.write(data, 0, data.length); + } + + /** + * Writes length bytes from the specified byte array starting at offset to this output stream. + *

    + * + * @param data + * A byte array which represents the data to write. + * @param offset + * An int which represents the start offset in the data. + * @param length + * An int which represents the number of bytes to write. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + @Override + public void write(final byte[] data, final int offset, final int length) throws IOException { + if (offset < 0 || length < 0 || length > data.length - offset) { + throw new IndexOutOfBoundsException(); + } + + this.writeInternal(data, offset, length); + } + + /** + * Writes the specified byte to this output stream. The general contract for write is that one byte is written to + * the output stream. The byte to be written is the eight low-order bits of the argument b. The 24 high-order bits + * of b are ignored. + *

    + * true is acceptable for you. + * + * @param byteVal + * An int which represents the bye value to write. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + @Override + public void write(final int byteVal) throws IOException { + this.write(new byte[] { (byte) (byteVal & 0xFF) }); + } + + /** + * Writes the data to the buffer and triggers writes to the service as needed. + * + * @param data + * A byte array which represents the data to write. + * @param offset + * An int which represents the start offset in the data. + * @param length + * An int which represents the number of bytes to write. + * + * @throws IOException + * If an I/O error occurs. In particular, an IOException may be thrown if the output stream has been + * closed. + */ + private void writeInternal(final byte[] data, int offset, int length) { + int chunks = (int) (Math.ceil((double) length / (double) this.internalWriteThreshold)); + Flux chunkPositions = Flux.range(0, chunks).map(c -> offset + c * this.internalWriteThreshold); + if (this.streamType == BlobType.APPEND_BLOB) { + chunkPositions.concatMap(pos -> processChunk(data, pos, offset, length)).then().block(); + } else { + chunkPositions.concatMap(pos -> processChunk(data, pos, offset, length)).then().block(); + } + +// synchronized (outBufferLock) { +// while (length > 0) { +// this.checkStreamState(); +// +// final int availableBufferBytes = this.internalWriteThreshold - this.outBuffer.size(); +// final int nextWrite = Math.min(availableBufferBytes, length); +// +// this.outBuffer.write(data, offset, nextWrite); +// offset += nextWrite; +// length -= nextWrite; +// +// if (this.outBuffer.size() == this.internalWriteThreshold) { +// this.writeSink.next(outBuffer.toByteArray()); +// outBuffer.reset(); +// numInFlight.incrementAndGet(); +// } +// } +// } + } + + private Mono processChunk(byte[] data, int position, int offset, int length) { + int chunkLength = this.internalWriteThreshold; + if (position + chunkLength > offset + length) { + chunkLength = offset + length - position; + } + Flux chunkData = new ByteBufStreamFromByteArray(data, 64 * 1024, position, chunkLength); + return dispatchWrite(chunkData, chunkLength, position - offset) + .doOnError(t -> { + if (t instanceof IOException) { + lastError = (IOException) t; + } else { + lastError = new IOException(t); + } + }); + } + + private static final class ByteBufStreamFromByteArray extends Flux { + private final ByteBufAllocator alloc; + private final byte[] bigByteArray; + private final int chunkSize; + private final int offset; + private final int length; + + ByteBufStreamFromByteArray(byte[] bigByteArray, int chunkSize, int offset, int length) { + this.alloc = ByteBufAllocator.DEFAULT; + this.bigByteArray = bigByteArray; + this.chunkSize = chunkSize; + this.offset = offset; + this.length = length; + } + + @Override + public void subscribe(CoreSubscriber actual) { + ByteBufStreamFromByteArray.FileReadSubscription subscription = new ByteBufStreamFromByteArray.FileReadSubscription(actual, bigByteArray, alloc, chunkSize, offset, length); + actual.onSubscribe(subscription); + } + + static final class FileReadSubscription implements Subscription, CompletionHandler { + private static final int NOT_SET = -1; + private static final long serialVersionUID = -6831808726875304256L; + // + private final Subscriber subscriber; + private volatile int position; + // + private final byte[] bigByteArray; + private final ByteBufAllocator alloc; + private final int chunkSize; + private final int offset; + private final int length; + // + private volatile boolean done; + private Throwable error; + private volatile ByteBuf next; + private volatile boolean cancelled; + // + volatile int wip; + @SuppressWarnings("rawtypes") + static final AtomicIntegerFieldUpdater WIP = AtomicIntegerFieldUpdater.newUpdater(ByteBufStreamFromByteArray.FileReadSubscription.class, "wip"); + volatile long requested; + @SuppressWarnings("rawtypes") + static final AtomicLongFieldUpdater REQUESTED = AtomicLongFieldUpdater.newUpdater(ByteBufStreamFromByteArray.FileReadSubscription.class, "requested"); + // + + FileReadSubscription(Subscriber subscriber, byte[] bigByteArray, ByteBufAllocator alloc, int chunkSize, int offset, int length) { + this.subscriber = subscriber; + // + this.bigByteArray = bigByteArray; + this.alloc = alloc; + this.chunkSize = chunkSize; + this.offset = offset; + this.length = length; + // + this.position = NOT_SET; + } + + //region Subscription implementation + + @Override + public void request(long n) { + if (Operators.validate(n)) { + Operators.addCap(REQUESTED, this, n); + drain(); + } + } + + @Override + public void cancel() { + this.cancelled = true; + } + + //endregion + + //region CompletionHandler implementation + + @Override + public void completed(Integer bytesRead, ByteBuf buffer) { + if (!cancelled) { + if (bytesRead == -1) { + done = true; + } else { + // use local variable to perform fewer volatile reads + int pos = position; + // + int bytesWanted = (int) Math.min(bytesRead, maxRequired(pos)); + buffer.writerIndex(bytesWanted); + int position2 = pos + bytesWanted; + //noinspection NonAtomicOperationOnVolatileField + position = position2; + next = buffer; + if (position2 >= offset + length) { + done = true; + } + } + drain(); + } + } + + @Override + public void failed(Throwable exc, ByteBuf attachment) { + if (!cancelled) { + // must set error before setting done to true + // so that is visible in drain loop + error = exc; + done = true; + drain(); + } + } + + //endregion + + private void drain() { + if (WIP.getAndIncrement(this) != 0) { + return; + } + // on first drain (first request) we initiate the first read + if (position == NOT_SET) { + position = offset; + doRead(); + } + int missed = 1; + for (;;) { + if (cancelled) { + return; + } + if (REQUESTED.get(this) > 0) { + boolean emitted = false; + // read d before next to avoid race + boolean d = done; + ByteBuf bb = next; + if (bb != null) { + next = null; + // + // try { + subscriber.onNext(bb); + // } finally { + // Note: Don't release here, we follow netty disposal pattern + // it's consumers responsiblity to release chunks after consumption. + // + // ReferenceCountUtil.release(bb); + // } + // + emitted = true; + } else { + emitted = false; + } + if (d) { + if (error != null) { + subscriber.onError(error); + // exit without reducing wip so that further drains will be NOOP + return; + } else { + subscriber.onComplete(); + // exit without reducing wip so that further drains will be NOOP + return; + } + } + if (emitted) { + // do this after checking d to avoid calling read + // when done + Operators.produced(REQUESTED, this, 1); + // + doRead(); + } + } + missed = WIP.addAndGet(this, -missed); + if (missed == 0) { + return; + } + } + } + + private void doRead() { + // use local variable to limit volatile reads + int pos = position; + int readSize = Math.min(chunkSize, maxRequired(pos)); + ByteBuf innerBuf = alloc.buffer(readSize, readSize); + try { + innerBuf.writeBytes(bigByteArray, pos, readSize); + completed(readSize, innerBuf); + } catch (Exception e) { + failed(e, innerBuf); + } + } + + private int maxRequired(long pos) { + long maxRequired = offset + length - pos; + if (maxRequired <= 0) { + return 0; + } else { + int m = (int) (maxRequired); + // support really large files by checking for overflow + if (m < 0) { + return Integer.MAX_VALUE; + } else { + return m; + } + } + } + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobProperties.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobProperties.java new file mode 100644 index 0000000000000..321a7c061f387 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobProperties.java @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.implementation.util.ImplUtils; +import com.azure.storage.blob.models.BlobGetPropertiesHeaders; +import com.azure.storage.blob.models.BlobType; +import com.azure.storage.blob.models.Metadata; + +public class BlobProperties { + + private final BlobType blobType; + + private final Metadata metadata; + + private final long blobSize; + + private final byte[] contentMD5; + + private final String contentEncoding; + + private final String contentDisposition; + + private final String contentLanguage; + + private final String cacheControl; + + //todo decide datetime representation for last modified time + + + BlobProperties(BlobGetPropertiesHeaders generatedHeaders) { + this.blobType = generatedHeaders.blobType(); + this.metadata = new Metadata(generatedHeaders.metadata()); + this.blobSize = generatedHeaders.contentLength() == null ? 0 : generatedHeaders.contentLength(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.contentEncoding = generatedHeaders.contentEncoding(); + this.contentDisposition = generatedHeaders.contentDisposition(); + this.contentLanguage = generatedHeaders.contentLanguage(); + this.cacheControl = generatedHeaders.cacheControl(); + } + + + /** + * @return the blob type + */ + public BlobType blobType() { + return blobType; + } + + /** + * @return the metadata associated with this blob + */ + public Metadata metadata() { + return metadata; + } + + /** + * @return the size of the blob in bytes + */ + public long blobSize() { + return blobSize; + } + + /** + * @return the MD5 of the blob's content + */ + public byte[] contentMD5() { + return ImplUtils.clone(contentMD5); + } + + /** + * @return the encoding of the blob's content + */ + public String contentEncoding() { + return contentEncoding; + } + + /** + * @return the disposition of the blob's content + */ + public String contentDisposition() { + return contentDisposition; + } + + /** + * @return the language of the blob's content + */ + public String contentLanguage() { + return contentLanguage; + } + + /** + * @return the caching control for the blob + */ + public String cacheControl() { + return cacheControl; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java new file mode 100644 index 0000000000000..6dd79f092ecd3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobSASPermission.java @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.util.Locale; + +/** + * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a blob. Setting + * a value to true means that any SAS which uses these permissions will grant permissions for that operation. Once all + * the values are set, this should be serialized with toString and set as the permissions field on a + * {@link ServiceSASSignatureValues} object. It is possible to construct the permissions string without this class, but + * the order of the permissions is particular and this class guarantees correctness. + */ +final class BlobSASPermission { + + private boolean read; + + private boolean add; + + private boolean create; + + private boolean write; + + private boolean delete; + + /** + * Initializes a {@code BlobSASPermission} object with all fields set to false. + */ + private BlobSASPermission() { + } + + /** + * Creates a {@code BlobSASPermission} from the specified permissions string. This method will throw an + * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid permission. + * + * @param permString + * A {@code String} which represents the {@code BlobSASPermission}. + * + * @return A {@code BlobSASPermission} generated from the given {@code String}. + * @throws IllegalArgumentException If {@code permString} contains a character other than r, a, c, w, or d. + */ + public static BlobSASPermission parse(String permString) { + BlobSASPermission permissions = new BlobSASPermission(); + + for (int i = 0; i < permString.length(); i++) { + char c = permString.charAt(i); + switch (c) { + case 'r': + permissions.read = true; + break; + case 'a': + permissions.add = true; + break; + case 'c': + permissions.create = true; + break; + case 'w': + permissions.write = true; + break; + case 'd': + permissions.delete = true; + break; + default: + throw new IllegalArgumentException( + String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permString, c)); + } + } + return permissions; + } + + /** + * Specifies Read access granted. + */ + public boolean read() { + return read; + } + + /** + * Specifies Read access granted. + */ + public BlobSASPermission read(boolean read) { + this.read = read; + return this; + } + + /** + * Specifies Add access granted. + */ + public boolean add() { + return add; + } + + /** + * Specifies Add access granted. + */ + public BlobSASPermission add(boolean add) { + this.add = add; + return this; + } + + /** + * Specifies Create access granted. + */ + public boolean create() { + return create; + } + + /** + * Specifies Create access granted. + */ + public BlobSASPermission create(boolean create) { + this.create = create; + return this; + } + + /** + * Specifies Write access granted. + */ + public boolean write() { + return write; + } + + /** + * Specifies Write access granted. + */ + public BlobSASPermission write(boolean write) { + this.write = write; + return this; + } + + /** + * Specifies Delete access granted. + */ + public boolean delete() { + return delete; + } + + /** + * Specifies Delete access granted. + */ + public BlobSASPermission delete(boolean delete) { + this.delete = delete; + return this; + } + + /** + * Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an + * order accepted by the service. + * + * @return A {@code String} which represents the {@code BlobSASPermission}. + */ + @Override + public String toString() { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas + + final StringBuilder builder = new StringBuilder(); + + if (this.read) { + builder.append('r'); + } + + if (this.add) { + builder.append('a'); + } + + if (this.create) { + builder.append('c'); + } + + if (this.write) { + builder.append('w'); + } + + if (this.delete) { + builder.append('d'); + } + + return builder.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java new file mode 100644 index 0000000000000..473d998c446b2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlobURLParts.java @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.implementation.http.UrlBuilder; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +/** + * A BlobURLParts object represents the components that make up an Azure Storage Container/Blob URL. You may parse an + * existing URL into its parts with the {@link URLParser} class. You may construct a URL from parts by calling toURL(). + * It is also possible to use the empty constructor to buildClient a blobURL from scratch. + * NOTE: Changing any SAS-related field requires computing a new SAS signature. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=url_parts "Sample code for BlobURLParts")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ +final class BlobURLParts { + + private String scheme; + + private String host; + + private String containerName; + + private String blobName; + + private String snapshot; + + private SASQueryParameters sasQueryParameters; + + private Map unparsedParameters; + + /** + * Initializes a BlobURLParts object with all fields set to null, except unparsedParameters, which is an empty map. + * This may be useful for constructing a URL to a blob storage resource from scratch when the constituent parts are + * already known. + */ + BlobURLParts() { + unparsedParameters = new HashMap<>(); + } + + /** + * The scheme. Ex: "https://". + */ + public String scheme() { + return scheme; + } + + /** + * The scheme. Ex: "https://". + */ + public BlobURLParts scheme(String scheme) { + this.scheme = scheme; + return this; + } + + /** + * The host. Ex: "account.blob.core.windows.net". + */ + public String host() { + return host; + } + + /** + * The host. Ex: "account.blob.core.windows.net". + */ + public BlobURLParts host(String host) { + this.host = host; + return this; + } + + /** + * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed. + */ + public String containerName() { + return containerName; + } + + /** + * The container name or {@code null} if a {@link StorageAsyncRawClient} was parsed. + */ + public BlobURLParts containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * The blob name or {@code null} if a {@link StorageAsyncRawClient} or {@link ContainerAsyncClient} was parsed. + */ + public String blobName() { + return blobName; + } + + /** + * The blob name or {@code null} if a {@link StorageAsyncRawClient} or {@link ContainerAsyncClient} was parsed. + */ + public BlobURLParts blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed. + */ + public String snapshot() { + return snapshot; + } + + /** + * The snapshot time or {@code null} if anything except a URL to a snapshot was parsed. + */ + public BlobURLParts snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * A {@link SASQueryParameters} representing the SAS query parameters or {@code null} if there were no such + * parameters. + */ + public SASQueryParameters sasQueryParameters() { + return sasQueryParameters; + } + + /** + * A {@link SASQueryParameters} representing the SAS query parameters or {@code null} if there were no such + * parameters. + */ + public BlobURLParts sasQueryParameters(SASQueryParameters sasQueryParameters) { + this.sasQueryParameters = sasQueryParameters; + return this; + } + + /** + * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were + * no such parameters. + */ + public Map unparsedParameters() { + return unparsedParameters; + } + + /** + * The query parameter key value pairs aside from SAS parameters and snapshot time or {@code null} if there were + * no such parameters. + */ + public BlobURLParts unparsedParameters(Map unparsedParameters) { + this.unparsedParameters = unparsedParameters; + return this; + } + + /** + * Converts the blob URL parts to a {@link URL}. + * + * @return A {@code java.net.URL} to the blob resource composed of all the elements in the object. + * + * @throws MalformedURLException + * The fields present on the BlobURLParts object were insufficient to construct a valid URL or were + * ill-formatted. + */ + public URL toURL() throws MalformedURLException { + UrlBuilder url = new UrlBuilder().scheme(this.scheme).host(this.host); + + StringBuilder path = new StringBuilder(); + if (this.containerName != null) { + path.append(this.containerName); + if (this.blobName != null) { + path.append('/'); + path.append(this.blobName); + } + } + url.path(path.toString()); + + if (this.snapshot != null) { + url.setQueryParameter(Constants.SNAPSHOT_QUERY_PARAMETER, this.snapshot); + } + if (this.sasQueryParameters != null) { + String encodedSAS = this.sasQueryParameters.encode(); + if (encodedSAS.length() != 0) { + url.query(encodedSAS); + } + } + + for (Map.Entry entry : this.unparsedParameters.entrySet()) { + // The commas are intentionally encoded. + url.setQueryParameter(entry.getKey(), + Utility.safeURLEncode(String.join(",", entry.getValue()))); + } + + return url.toURL(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java new file mode 100644 index 0000000000000..ada7a125d4ef1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncClient.java @@ -0,0 +1,447 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.ResponseBase; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.implementation.util.FluxUtil; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlockBlobItem; +import com.azure.storage.blob.models.BlockItem; +import com.azure.storage.blob.models.BlockListType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.UUID; + +/** + * Client to a block blob. It may only be instantiated through a {@link BlockBlobClientBuilder}, via + * the method {@link BlobAsyncClient#asBlockBlobAsyncClient()}, or via the method + * {@link ContainerAsyncClient#getBlockBlobAsyncClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient}, + * and operations on the service are available on {@link StorageAsyncClient}. + * + *

    + * Please refer + * to the Azure Docs + * for more information. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public final class BlockBlobAsyncClient extends BlobAsyncClient { + static final int BLOB_DEFAULT_UPLOAD_BLOCK_SIZE = 4 * Constants.MB; + static final int BLOB_MAX_UPLOAD_BLOCK_SIZE = 100 * Constants.MB; + + final BlockBlobAsyncRawClient blockBlobAsyncRawClient; + + /** + * Indicates the maximum number of bytes that can be sent in a call to upload. + */ + public static final int MAX_UPLOAD_BLOB_BYTES = 256 * Constants.MB; + + /** + * Indicates the maximum number of bytes that can be sent in a call to stageBlock. + */ + public static final int MAX_STAGE_BLOCK_BYTES = 100 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in a block blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Package-private constructor for use by {@link BlockBlobClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + BlockBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { + super(azureBlobStorageBuilder, snapshot); + this.blockBlobAsyncRawClient = new BlockBlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + *

    + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return + * A reactive response containing the information of the uploaded block blob. + */ + public Mono> upload(Flux data, long length) { + return this.upload(data, length, null, null, null); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + *

    + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the information of the uploaded block blob. + */ + public Mono> upload(Flux data, long length, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions) { + return blockBlobAsyncRawClient + .upload(data.map(Unpooled::wrappedBuffer), length, headers, metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob, with the content of the specified file. + * + * @param filePath Path to the upload file + * @return An empty response + */ + public Mono uploadFromFile(String filePath) { + return this.uploadFromFile(filePath, BLOB_DEFAULT_UPLOAD_BLOCK_SIZE, null, null, null); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob, with the content of the specified file. + * + * @param filePath Path to the upload file + * @param blockSize Size of the blocks to upload + * @param headers {@link BlobHTTPHeaders} + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @return An empty response + * @throws IllegalArgumentException If {@code blockSize} is less than 0 or greater than 100MB + * @throws UncheckedIOException If an I/O error occurs + */ + public Mono uploadFromFile(String filePath, Integer blockSize, BlobHTTPHeaders headers, Metadata metadata, + BlobAccessConditions accessConditions) { + if (blockSize < 0 || blockSize > BLOB_MAX_UPLOAD_BLOCK_SIZE) { + throw new IllegalArgumentException("Block size should not exceed 100MB"); + } + + return Mono.using(() -> uploadFileResourceSupplier(filePath), + channel -> { + final SortedMap blockIds = new TreeMap<>(); + return Flux.fromIterable(sliceFile(filePath, blockSize)) + .doOnNext(chunk -> blockIds.put(chunk.offset(), getBlockID())) + .flatMap(chunk -> { + String blockId = blockIds.get(chunk.offset()); + return stageBlock(blockId, FluxUtil.byteBufStreamFromFile(channel, chunk.offset(), chunk.count()), chunk.count(), null); + }) + .then(Mono.defer(() -> commitBlockList(new ArrayList<>(blockIds.values()), headers, metadata, accessConditions))) + .then() + .doOnTerminate(() -> { + try { + channel.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + }, this::uploadFileCleanup); + } + + private AsynchronousFileChannel uploadFileResourceSupplier(String filePath) { + try { + return AsynchronousFileChannel.open(Paths.get(filePath), StandardOpenOption.READ); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private void uploadFileCleanup(AsynchronousFileChannel channel) { + try { + channel.close(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private String getBlockID() { + return Base64.getEncoder().encodeToString(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)); + } + + private List sliceFile(String path, Integer blockSize) { + if (blockSize == null) { + blockSize = BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + } + File file = new File(path); + assert file.exists(); + List ranges = new ArrayList<>(); + for (long pos = 0; pos < file.length(); pos += blockSize) { + long count = blockSize; + if (pos + count > file.length()) { + count = file.length() - pos; + } + ranges.add(new BlobRange(pos, count)); + } + return ranges; + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return + * A reactive response signalling completion. + */ + public Mono stageBlock(String base64BlockID, Flux data, + long length) { + return this.stageBlock(base64BlockID, data, length, null); + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flux must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono stageBlock(String base64BlockID, Flux data, long length, + LeaseAccessConditions leaseAccessConditions) { + return blockBlobAsyncRawClient + .stageBlock(base64BlockID, data, length, leaseAccessConditions) + .map(VoidResponse::new); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * + * @return + * A reactive response signalling completion. + */ + public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange) { + return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null, + null, null); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param sourceModifiedAccessConditions + * {@link SourceModifiedAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions, + SourceModifiedAccessConditions sourceModifiedAccessConditions) { + return blockBlobAsyncRawClient + .stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions) + .map(VoidResponse::new); + } + + /** + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * + * @return + * A reactive response containing the list of blocks. + */ + public Flux listBlocks(BlockListType listType) { + return this.listBlocks(listType, null); + } + + /** + * + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response containing the list of blocks. + */ + public Flux listBlocks(BlockListType listType, + LeaseAccessConditions leaseAccessConditions) { + return blockBlobAsyncRawClient + .listBlocks(listType, leaseAccessConditions) + .map(ResponseBase::value) + .flatMapMany(bl -> { + Flux committed = Flux.fromIterable(bl.committedBlocks()) + .map(block -> new BlockItem(block, true)); + Flux uncommitted = Flux.fromIterable(bl.uncommittedBlocks()) + .map(block -> new BlockItem(block, false)); + return Flux.concat(committed, uncommitted); + }); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * + * @return + * A reactive response containing the information of the block blob. + */ + public Mono> commitBlockList(List base64BlockIDs) { + return this.commitBlockList(base64BlockIDs, null, null, null); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the information of the block blob. + */ + public Mono> commitBlockList(List base64BlockIDs, + BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { + return blockBlobAsyncRawClient + .commitBlockList(base64BlockIDs, headers, metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java new file mode 100644 index 0000000000000..03b7e650167b6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobAsyncRawClient.java @@ -0,0 +1,364 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlockBlobsCommitBlockListResponse; +import com.azure.storage.blob.models.BlockBlobsGetBlockListResponse; +import com.azure.storage.blob.models.BlockBlobsStageBlockFromURLResponse; +import com.azure.storage.blob.models.BlockBlobsStageBlockResponse; +import com.azure.storage.blob.models.BlockBlobsUploadResponse; +import com.azure.storage.blob.models.BlockListType; +import com.azure.storage.blob.models.BlockLookupList; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.util.List; + +import static com.azure.storage.blob.Utility.postProcessResponse; + +/** + * Represents a URL to a block blob. It may be obtained by direct construction or via the create method on a + * {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is instead a convenient + * way of sending off appropriate requests to the resource on the service. Please refer to the + * Azure Docs + * for more information on block blobs. + */ +final class BlockBlobAsyncRawClient extends BlobAsyncRawClient { + + /** + * Indicates the maximum number of bytes that can be sent in a call to upload. + */ + public static final int MAX_UPLOAD_BLOB_BYTES = 256 * Constants.MB; + + /** + * Indicates the maximum number of bytes that can be sent in a call to stageBlock. + */ + public static final int MAX_STAGE_BLOCK_BYTES = 100 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in a block blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Creates a {@code BlockBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided + */ + BlockBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { + super(azureBlobStorage, snapshot); + } + + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + *

    + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlockBlobAsyncRawClient.upload")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono upload(Flux data, long length) { + return this.upload(data, length, null, null, null); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + *

    + * + * @param data + * The data to write to the blob. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=upload_download "Sample code for BlockBlobAsyncRawClient.upload")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono upload(Flux data, long length, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blockBlobs().uploadWithRestResponseAsync(null, + null, data, length, null, metadata, null, null, + null, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.stageBlock")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono stageBlock(String base64BlockID, Flux data, + long length) { + return this.stageBlock(base64BlockID, data, length, null); + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * emitted by the {@code Flux}. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.stageBlock")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono stageBlock(String base64BlockID, Flux data, long length, + LeaseAccessConditions leaseAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blockBlobs().stageBlockWithRestResponseAsync(null, + null, base64BlockID, length, data, null, null, null, + null, null, null, leaseAccessConditions, Context.NONE)); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=block_from_url "Sample code for BlockBlobAsyncRawClient.stageBlockFromURL")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange) { + return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null, + null, null); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param sourceModifiedAccessConditions + * {@link SourceModifiedAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=block_from_url "Sample code for BlockBlobAsyncRawClient.stageBlockFromURL")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions, + SourceModifiedAccessConditions sourceModifiedAccessConditions) { + sourceRange = sourceRange == null ? new BlobRange(0) : sourceRange; + + return postProcessResponse( + this.azureBlobStorage.blockBlobs().stageBlockFromURLWithRestResponseAsync(null, null, + base64BlockID, 0, sourceURL, sourceRange.toHeaderValue(), sourceContentMD5, null, + null, null, null, null, + leaseAccessConditions, sourceModifiedAccessConditions, Context.NONE)); + } + + /** + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.listBlocks")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono listBlocks(BlockListType listType) { + return this.listBlocks(listType, null); + } + + /** + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.listBlocks")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono listBlocks(BlockListType listType, + LeaseAccessConditions leaseAccessConditions) { + return postProcessResponse(this.azureBlobStorage.blockBlobs().getBlockListWithRestResponseAsync( + null, null, listType, snapshot, null, null, null, + leaseAccessConditions, Context.NONE)); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + *

    + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.commitBlockList")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono commitBlockList(List base64BlockIDs) { + return this.commitBlockList(base64BlockIDs, null, null, null); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + *

    + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=blocks "Sample code for BlockBlobAsyncRawClient.commitBlockList")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono commitBlockList(List base64BlockIDs, + BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.blockBlobs().commitBlockListWithRestResponseAsync( + null, null, new BlockLookupList().latest(base64BlockIDs), null, metadata, + null, null, null, null, headers, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java new file mode 100644 index 0000000000000..9dced1f87022b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClient.java @@ -0,0 +1,407 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.BlockBlobItem; +import com.azure.storage.blob.models.BlockItem; +import com.azure.storage.blob.models.BlockListType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URL; +import java.time.Duration; +import java.util.List; + +/** + * Client to a block blob. It may only be instantiated through a {@link BlockBlobClientBuilder}, via + * the method {@link BlobClient#asBlockBlobClient()}, or via the method + * {@link ContainerClient#getBlockBlobClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient}, + * and operations on the service are available on {@link StorageClient}. + * + *

    + * Please refer to the Azure Docs + * for more information. + */ +public final class BlockBlobClient extends BlobClient { + + private BlockBlobAsyncClient blockBlobAsyncClient; + /** + * Indicates the maximum number of bytes that can be sent in a call to upload. + */ + public static final int MAX_UPLOAD_BLOB_BYTES = 256 * Constants.MB; + + /** + * Indicates the maximum number of bytes that can be sent in a call to stageBlock. + */ + public static final int MAX_STAGE_BLOCK_BYTES = 100 * Constants.MB; + + /** + * Indicates the maximum number of blocks allowed in a block blob. + */ + public static final int MAX_BLOCKS = 50000; + + /** + * Package-private constructor for use by {@link BlockBlobClientBuilder}. + * @param blockBlobAsyncClient the async block blob client + */ + BlockBlobClient(BlockBlobAsyncClient blockBlobAsyncClient) { + super(blockBlobAsyncClient); + this.blockBlobAsyncClient = blockBlobAsyncClient; + } + + /** + * Creates and opens an output stream to write data to the block blob. If the blob already exists on the service, + * it will be overwritten. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream() { + return getBlobOutputStream(null); + } + + /** + * Creates and opens an output stream to write data to the block blob. If the blob already exists on the service, + * it will be overwritten. + * + * @param accessConditions + * A {@link BlobAccessConditions} object that represents the access conditions for the blob. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream(BlobAccessConditions accessConditions) { + return new BlobOutputStream(blockBlobAsyncClient, accessConditions); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + * + * @param data + * The data to write to the blob. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * provided in the {@link InputStream}. + * + * @return + * The information of the uploaded block blob. + * @throws IOException If an I/O error occurs + */ + public Response upload(InputStream data, long length) throws IOException { + return this.upload(data, length, null, null, null, null); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not + * supported with PutBlob; the content of the existing blob is overwritten with the new content. To + * perform a partial update of a block blob's, use PutBlock and PutBlockList. + * For more information, see the + * Azure Docs. + * + * @param data + * The data to write to the blob. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * provided in the {@link InputStream}. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the uploaded block blob. + * @throws IOException If an I/O error occurs + */ + public Response upload(InputStream data, long length, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) throws IOException { + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE)) + .map(i -> i * BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE) + .concatMap(pos -> Mono.fromCallable(() -> { + long count = pos + BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE > length ? length - pos : BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + byte[] cache = new byte[(int) count]; + int read = 0; + while (read < count) { + read += data.read(cache, read, (int) count - read); + } + return ByteBufAllocator.DEFAULT.buffer((int) count).writeBytes(cache); + })); + + Mono> upload = blockBlobAsyncClient.blockBlobAsyncRawClient + .upload(fbb.subscribeOn(Schedulers.elastic()), length, headers, metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new BlockBlobItem(rb.deserializedHeaders()))); + + try { + return Utility.blockWithOptionalTimeout(upload, timeout); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * + * @param filePath Path of the file to upload + * @throws IOException If an I/O error occurs + */ + public void uploadFromFile(String filePath) throws IOException { + this.uploadFromFile(filePath, null, null, null, null); + } + + /** + * Creates a new block blob, or updates the content of an existing block blob. + * + * @param filePath Path of the file to upload + * @param headers {@link BlobHTTPHeaders} + * @param metadata {@link Metadata} + * @param accessConditions {@link BlobAccessConditions} + * @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @throws IOException If an I/O error occurs + */ + public void uploadFromFile(String filePath, BlobHTTPHeaders headers, Metadata metadata, + BlobAccessConditions accessConditions, Duration timeout) throws IOException { + Mono upload = this.blockBlobAsyncClient.uploadFromFile(filePath, BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE, headers, metadata, accessConditions); + + try { + Utility.blockWithOptionalTimeout(upload, timeout); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * provided in the {@link InputStream}. + * @return A response containing status code and HTTP headers + */ + public VoidResponse stageBlock(String base64BlockID, InputStream data, long length) { + return this.stageBlock(base64BlockID, data, length, null, null); + } + + /** + * Uploads the specified block to the block blob's "staging area" to be later committed by a call to + * commitBlockList. For more information, see the + * Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param data + * The data to write to the block. + * @param length + * The exact length of the data. It is important that this value match precisely the length of the data + * provided in the {@link InputStream}. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse stageBlock(String base64BlockID, InputStream data, long length, + LeaseAccessConditions leaseAccessConditions, Duration timeout) { + + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE)) + .map(i -> i * BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE) + .concatMap(pos -> Mono.fromCallable(() -> { + long count = pos + BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE > length ? length - pos : BlockBlobAsyncClient.BLOB_DEFAULT_UPLOAD_BLOCK_SIZE; + byte[] cache = new byte[(int) count]; + int read = 0; + while (read < count) { + read += data.read(cache, read, (int) count - read); + } + return ByteBufAllocator.DEFAULT.buffer((int) count).writeBytes(cache); + })); + + Mono response = blockBlobAsyncClient.stageBlock(base64BlockID, + fbb.subscribeOn(Schedulers.elastic()), length, leaseAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @return A response containing status code and HTTP headers + */ + public VoidResponse stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange) { + return this.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, null, + null, null, null); + } + + /** + * Creates a new block to be committed as part of a blob where the contents are read from a URL. For more + * information, see the Azure Docs. + * + * @param base64BlockID + * A Base64 encoded {@code String} that specifies the ID for this block. Note that all block ids for a given + * blob must be the same length. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can + * be authenticated via Shared Key. However, if the source is a blob in another account, the source blob + * must either be public or must be authenticated via a shared access signature. If the source blob is + * public, no authentication is required to perform the operation. + * @param sourceRange + * {@link BlobRange} + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param sourceModifiedAccessConditions + * {@link SourceModifiedAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse stageBlockFromURL(String base64BlockID, URL sourceURL, + BlobRange sourceRange, byte[] sourceContentMD5, LeaseAccessConditions leaseAccessConditions, + SourceModifiedAccessConditions sourceModifiedAccessConditions, Duration timeout) { + Mono response = blockBlobAsyncClient.stageBlockFromURL(base64BlockID, sourceURL, sourceRange, sourceContentMD5, leaseAccessConditions, sourceModifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * + * @return + * The list of blocks. + */ + public Iterable listBlocks(BlockListType listType) { + return this.listBlocks(listType, null, null); + } + + /** + * + * Returns the list of blocks that have been uploaded as part of a block blob using the specified block list filter. + * For more information, see the + * Azure Docs. + * + * @param listType + * Specifies which type of blocks to return. + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The list of blocks. + */ + public Iterable listBlocks(BlockListType listType, + LeaseAccessConditions leaseAccessConditions, Duration timeout) { + Flux response = blockBlobAsyncClient.listBlocks(listType, leaseAccessConditions); + + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * + * @return + * The information of the block blob. + */ + public Response commitBlockList(List base64BlockIDs) { + return this.commitBlockList(base64BlockIDs, null, null, null, null); + } + + /** + * Writes a blob by specifying the list of block IDs that are to make up the blob. + * In order to be written as part of a blob, a block must have been successfully written + * to the server in a prior stageBlock operation. You can call commitBlockList to update a blob + * by uploading only those blocks that have changed, then committing the new and existing + * blocks together. Any blocks not specified in the block list and permanently deleted. + * For more information, see the + * Azure Docs. + * + * @param base64BlockIDs + * A list of base64 encode {@code String}s that specifies the block IDs to be committed. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the block blob. + */ + public Response commitBlockList(List base64BlockIDs, + BlobHTTPHeaders headers, Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = blockBlobAsyncClient.commitBlockList(base64BlockIDs, headers, metadata, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java new file mode 100644 index 0000000000000..4774228c27648 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/BlockBlobClientBuilder.java @@ -0,0 +1,337 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent BlockBlobClientBuilder for instantiating a {@link BlockBlobClient} or {@link BlockBlobAsyncClient} + * using {@link BlockBlobClientBuilder#buildClient()} or {@link BlockBlobClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link BlockBlobClient} or {@code .buildAsyncClient()} to create a {@link BlockBlobAsyncClient}. + */ +public final class BlockBlobClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private String containerName; + private String blobName; + private String snapshot; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link BlockBlobClient BlockBlobClients} + * and {@link BlockBlobAsyncClient BlockBlobAsyncClients}. + */ + public BlockBlobClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + /** + * Constructs an instance of BlockBlobAsyncClient based on the configurations stored in the appendBlobClientBuilder. + * @return a new client instance + */ + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(containerName); + Objects.requireNonNull(blobName); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .pipeline(pipeline); + } + + /** + * @return a {@link BlockBlobClient} created from the configurations in this builder. + */ + public BlockBlobClient buildClient() { + return new BlockBlobClient(buildAsyncClient()); + } + + /** + * @return a {@link BlockBlobAsyncClient} created from the configurations in this builder. + */ + public BlockBlobAsyncClient buildAsyncClient() { + return new BlockBlobAsyncClient(buildImpl(), snapshot); + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name) + * @param endpoint URL of the service + * @return the updated BlockBlobClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL. + */ + public BlockBlobClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + BlobURLParts parts = URLParser.parse(url); + this.endpoint = parts.scheme() + "://" + parts.host(); + + if (parts.containerName() != null) { + this.containerName = parts.containerName(); + } + + if (parts.blobName() != null) { + this.blobName = parts.blobName(); + } + + if (parts.snapshot() != null) { + this.snapshot = parts.snapshot(); + } + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * @param containerName the name of the container + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Sets the name of the blob this client is connecting to. + * @param blobName the name of the blob + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * Sets the snapshot of the blob this client is connecting to. + * @param snapshot the snapshot identifier for the blob + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated BlockBlobClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey + */ + public BlockBlobClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated BlockBlobClientBuilder object + */ + public BlockBlobClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java b/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java new file mode 100644 index 0000000000000..653625b572c15 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/Constants.java @@ -0,0 +1,295 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +/** + * RESERVED FOR INTERNAL USE. Contains storage constants. + */ +final class Constants { + + /** + * The master Microsoft Azure Storage header prefix. + */ + static final String PREFIX_FOR_STORAGE_HEADER = "x-ms-"; + /** + * Constant representing a kilobyte (Non-SI version). + */ + static final int KB = 1024; + /** + * Constant representing a megabyte (Non-SI version). + */ + static final int MB = 1024 * KB; + /** + * An empty {@code String} to use for comparison. + */ + static final String EMPTY_STRING = ""; + /** + * Specifies HTTP. + */ + static final String HTTP = "http"; + /** + * Specifies HTTPS. + */ + static final String HTTPS = "https"; + /** + * Specifies both HTTPS and HTTP. + */ + static final String HTTPS_HTTP = "https,http"; + /** + * The default type for content-type and accept. + */ + static final String UTF8_CHARSET = "UTF-8"; + /** + * The query parameter for snapshots. + */ + static final String SNAPSHOT_QUERY_PARAMETER = "snapshot"; + /** + * The word redacted. + */ + static final String REDACTED = "REDACTED"; + /** + * The default amount of parallelism for TransferManager operations. + */ + // We chose this to match Go, which followed AWS' default. + static final int TRANSFER_MANAGER_DEFAULT_PARALLELISM = 5; + + /** + * The size of a page, in bytes, in a page blob. + */ + public static final int PAGE_SIZE = 512; + + + /** + * Private Default Ctor + */ + private Constants() { + // Private to prevent construction. + } + + /** + * Defines constants for use with HTTP headers. + */ + static final class HeaderConstants { + /** + * The Authorization header. + */ + static final String AUTHORIZATION = "Authorization"; + + /** + * The header that indicates the client request ID. + */ + static final String CLIENT_REQUEST_ID_HEADER = PREFIX_FOR_STORAGE_HEADER + "client-request-id"; + + /** + * The ContentEncoding header. + */ + static final String CONTENT_ENCODING = "Content-Encoding"; + + /** + * The ContentLangauge header. + */ + static final String CONTENT_LANGUAGE = "Content-Language"; + + /** + * The ContentLength header. + */ + static final String CONTENT_LENGTH = "Content-Length"; + + /** + * The ContentMD5 header. + */ + static final String CONTENT_MD5 = "Content-MD5"; + + /** + * The ContentType header. + */ + static final String CONTENT_TYPE = "Content-Type"; + + /** + * The header that specifies the date. + */ + static final String DATE = PREFIX_FOR_STORAGE_HEADER + "date"; + + /** + * The header that specifies the error code on unsuccessful responses. + */ + static final String ERROR_CODE = PREFIX_FOR_STORAGE_HEADER + "error-code"; + + /** + * The IfMatch header. + */ + static final String IF_MATCH = "If-Match"; + + /** + * The IfModifiedSince header. + */ + static final String IF_MODIFIED_SINCE = "If-Modified-Since"; + + /** + * The IfNoneMatch header. + */ + static final String IF_NONE_MATCH = "If-None-Match"; + + /** + * The IfUnmodifiedSince header. + */ + static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; + + /** + * The Range header. + */ + static final String RANGE = "Range"; + + /** + * The copy source header. + */ + static final String COPY_SOURCE = "x-ms-copy-source"; + + /** + * The version header. + */ + static final String VERSION = "x-ms-version"; + + /** + * The current storage version header value. + */ + static final String TARGET_STORAGE_VERSION = "2018-11-09"; + + /** + * The UserAgent header. + */ + static final String USER_AGENT = "User-Agent"; + + /** + * Specifies the value to use for UserAgent header. + */ + static final String USER_AGENT_PREFIX = "Azure-Storage"; + + /** + * Specifies the value to use for UserAgent header. + */ + static final String USER_AGENT_VERSION = "11.0.1"; + + private HeaderConstants() { + // Private to prevent construction. + } + } + + static final class UrlConstants { + + /** + * The SAS service version parameter. + */ + static final String SAS_SERVICE_VERSION = "sv"; + + /** + * The SAS services parameter. + */ + static final String SAS_SERVICES = "ss"; + + /** + * The SAS resource types parameter. + */ + static final String SAS_RESOURCES_TYPES = "srt"; + + /** + * The SAS protocol parameter. + */ + static final String SAS_PROTOCOL = "spr"; + + /** + * The SAS start time parameter. + */ + static final String SAS_START_TIME = "st"; + + /** + * The SAS expiration time parameter. + */ + static final String SAS_EXPIRY_TIME = "se"; + + /** + * The SAS IP range parameter. + */ + static final String SAS_IP_RANGE = "sip"; + + /** + * The SAS signed identifier parameter. + */ + static final String SAS_SIGNED_IDENTIFIER = "si"; + + /** + * The SAS signed resource parameter. + */ + static final String SAS_SIGNED_RESOURCE = "sr"; + + /** + * The SAS signed permissions parameter. + */ + static final String SAS_SIGNED_PERMISSIONS = "sp"; + + /** + * The SAS signature parameter. + */ + static final String SAS_SIGNATURE = "sig"; + + /** + * The SAS cache control parameter. + */ + static final String SAS_CACHE_CONTROL = "rscc"; + + /** + * The SAS content disposition parameter. + */ + static final String SAS_CONTENT_DISPOSITION = "rscd"; + + /** + * The SAS content encoding parameter. + */ + static final String SAS_CONTENT_ENCODING = "rsce"; + + /** + * The SAS content language parameter. + */ + static final String SAS_CONTENT_LANGUAGE = "rscl"; + + /** + * The SAS content type parameter. + */ + static final String SAS_CONTENT_TYPE = "rsct"; + + /** + * The SAS signed object id parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_OBJECT_ID = "skoid"; + + /** + * The SAS signed tenant id parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_TENANT_ID = "sktid"; + + /** + * The SAS signed key-start parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_KEY_START = "skt"; + + /** + * The SAS signed key-expiry parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_KEY_EXPIRY = "ske"; + + /** + * The SAS signed service parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_KEY_SERVICE = "sks"; + + /** + * The SAS signed version parameter for user delegation SAS. + */ + public static final String SAS_SIGNED_KEY_VERSION = "skv"; + + private UrlConstants() { + // Private to prevent construction. + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java new file mode 100644 index 0000000000000..406a7440b0c5b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncClient.java @@ -0,0 +1,881 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpResponse; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.BlobFlatListSegment; +import com.azure.storage.blob.models.BlobHierarchyListSegment; +import com.azure.storage.blob.models.BlobItem; +import com.azure.storage.blob.models.BlobPrefix; +import com.azure.storage.blob.models.ContainerAccessConditions; +import com.azure.storage.blob.models.ContainerAccessPolicies; +import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; +import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ListBlobsOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.SignedIdentifier; +import com.azure.storage.blob.models.StorageAccountInfo; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.Duration; +import java.util.List; + +/** + * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method + * {@link StorageAsyncClient#getContainerAsyncClient(String)}. This class does not hold any + * state about a particular blob but is instead a convenient way of sending off appropriate requests to + * the resource on the service. It may also be used to construct URLs to blobs. + * + *

    + * This client contains operations on a container. Operations on a blob are available on {@link BlobAsyncClient} through + * {@link #getBlobAsyncClient(String)}, and operations on the service are available on {@link StorageAsyncClient}. + * + *

    + * Please refer to the Azure Docs + * for more information on containers. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public final class ContainerAsyncClient { + ContainerAsyncRawClient containerAsyncRawClient; + + public static final String ROOT_CONTAINER_NAME = "$root"; + + public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; + + public static final String LOG_CONTAINER_NAME = "$logs"; + + /** + * Package-private constructor for use by {@link ContainerClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + ContainerAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder) { + this.containerAsyncRawClient = new ContainerAsyncRawClient(azureBlobStorageBuilder.build()); + } + + /** + * Creates a new {@link BlockBlobAsyncClient} object by concatenating the blobName to the end of + * ContainerAsyncClient's URL. The new BlockBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlockBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's + * NewBlockBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link BlockBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName) { + return getBlockBlobAsyncClient(blobName, null); + } + + /** + * Creates a new {@link BlockBlobAsyncClient} object by concatenating the blobName to the end of + * ContainerAsyncClient's URL. The new BlockBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlockBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's + * NewBlockBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link BlockBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public BlockBlobAsyncClient getBlockBlobAsyncClient(String blobName, String snapshot) { + return new BlockBlobAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) + .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + } + + /** + * Creates creates a new PageBlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new PageBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the PageBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's + * NewPageBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link PageBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public PageBlobAsyncClient getPageBlobAsyncClient(String blobName) { + return getPageBlobAsyncClient(blobName, null); + } + + /** + * Creates creates a new PageBlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new PageBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the PageBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's + * NewPageBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link PageBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public PageBlobAsyncClient getPageBlobAsyncClient(String blobName, String snapshot) { + return new PageBlobAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) + .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + } + + /** + * Creates creates a new AppendBlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new AppendBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the AppendBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's + * NewAppendBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link AppendBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public AppendBlobAsyncClient getAppendBlobAsyncClient(String blobName) { + return getAppendBlobAsyncClient(blobName, null); + } + + /** + * Creates creates a new AppendBlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new AppendBlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the AppendBlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's + * NewAppendBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link AppendBlobAsyncClient} object which references the blob with the specified name in this container. + */ + public AppendBlobAsyncClient getAppendBlobAsyncClient(String blobName, String snapshot) { + return new AppendBlobAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) + .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + } + + /** + * Creates a new BlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's + * getBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link BlobAsyncClient} object which references the blob with the specified name in this container. + */ + public BlobAsyncClient getBlobAsyncClient(String blobName) { + return getBlobAsyncClient(blobName, null); + } + + /** + * Creates a new BlobAsyncClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new BlobAsyncClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlobAsyncClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's + * getBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link BlobAsyncClient} object which references the blob with the specified name in this container. + */ + public BlobAsyncClient getBlobAsyncClient(String blobName, String snapshot) { + return new BlobAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.appendToURLPath(getContainerUrl(), blobName).toString()) + .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline()), snapshot); + } + + /** + * Initializes a {@link StorageAsyncClient} object pointing to the storage account this container is in. + * + * @return + * A {@link StorageAsyncClient} object pointing to the specified storage account + */ + public StorageAsyncClient getStorageAsyncClient() { + return new StorageAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.stripLastPathSegment(getContainerUrl()).toString()) + .pipeline(containerAsyncRawClient.azureBlobStorage.httpPipeline())); + } + + /** + * Gets the URL of the container represented by this client. + * @return the URL. + * @throws RuntimeException If the container has a malformed URL. + */ + public URL getContainerUrl() { + try { + return new URL(containerAsyncRawClient.azureBlobStorage.url()); + } catch (MalformedURLException e) { + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), containerAsyncRawClient.azureBlobStorage.url()), e); + } + } + + /** + * Gets if the container this client represents exists in the cloud. + * + * @return + * true if the container exists, false if it doesn't + */ + public Mono> exists() { + return this.getProperties(null) + .map(cp -> (Response) new SimpleResponse<>(cp, true)) + .onErrorResume(t -> t instanceof StorageException && ((StorageException) t).statusCode() == 404, t -> { + HttpResponse response = ((StorageException) t).response(); + return Mono.just(new SimpleResponse<>(response.request(), response.statusCode(), response.headers(), false)); + }); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @return + * A reactive response signalling completion. + */ + public Mono create() { + return this.create(null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * + * @return + * A reactive response signalling completion. + */ + public Mono create(Metadata metadata, PublicAccessType accessType) { + return containerAsyncRawClient + .create(metadata, accessType) + .map(VoidResponse::new); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @return + * A reactive response signalling completion. + */ + public Mono delete() { + return this.delete(null); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono delete(ContainerAccessConditions accessConditions) { + return containerAsyncRawClient + .delete(accessConditions) + .map(VoidResponse::new); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @return + * A reactive response containing the container properties. + */ + public Mono> getProperties() { + return this.getProperties(null); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response containing the container properties. + */ + public Mono> getProperties(LeaseAccessConditions leaseAccessConditions) { + return containerAsyncRawClient + .getProperties(leaseAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new ContainerProperties(rb.deserializedHeaders()))); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * + * @return + * A reactive response signalling completion. + */ + public Mono setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono setMetadata(Metadata metadata, + ContainerAccessConditions accessConditions) { + return containerAsyncRawClient + .setMetadata(metadata, accessConditions) + .map(VoidResponse::new); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @return + * A reactive response containing the container access policy. + */ + public Mono> getAccessPolicy() { + return this.getAccessPolicy(null); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return + * A reactive response containing the container access policy. + */ + public Mono> getAccessPolicy(LeaseAccessConditions leaseAccessConditions) { + return containerAsyncRawClient.getAccessPolicy(leaseAccessConditions); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * + * @return + * A reactive response signalling completion. + */ + public Mono setAccessPolicy(PublicAccessType accessType, + List identifiers) { + return this.setAccessPolicy(accessType, identifiers, null); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return + * A reactive response signalling completion. + */ + public Mono setAccessPolicy(PublicAccessType accessType, + List identifiers, ContainerAccessConditions accessConditions) { + return containerAsyncRawClient + .setAccessPolicy(accessType, identifiers, accessConditions) + .map(VoidResponse::new); + } + + /** + * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. + * The directories are flattened and only actual blobs and no directories are returned. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return + * + *

      + *
    • foo/foo1 + *
    • foo/foo2 + *
    • bar + *
    + * + * @return + * A reactive response emitting the flattened blobs. + */ + public Flux listBlobsFlat() { + return this.listBlobsFlat(new ListBlobsOptions()); + } + + /** + * Returns a reactive Publisher emitting all the blobs in this container lazily as needed. + * The directories are flattened and only actual blobs and no directories are returned. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return + * + *

      + *
    • foo/foo1 + *
    • foo/foo2 + *
    • bar + *
    + * + * @param options + * {@link ListBlobsOptions} + * + * @return + * A reactive response emitting the listed blobs, flattened. + */ + public Flux listBlobsFlat(ListBlobsOptions options) { + return containerAsyncRawClient + .listBlobsFlatSegment(null, options) + .flatMapMany(response -> listBlobsFlatHelper(options, response)); + } + + private Flux listBlobsFlatHelper(ListBlobsOptions options, ContainersListBlobFlatSegmentResponse response) { + Flux result; + BlobFlatListSegment segment = response.value().segment(); + if (segment != null && segment.blobItems() != null) { + result = Flux.fromIterable(segment.blobItems()); + } else { + result = Flux.empty(); + } + + if (response.value().nextMarker() != null) { + // Recursively add the continuation items to the observable. + result = result.concatWith(containerAsyncRawClient.listBlobsFlatSegment(response.value().nextMarker(), options) + .flatMapMany(r -> listBlobsFlatHelper(options, r))); + } + + return result; + } + + /** + * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under + * the given directory (prefix). Directories will have {@link BlobItem#isPrefix()} set to + * true. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return the following results when prefix=null: + * + *

      + *
    • foo/ (isPrefix = true) + *
    • bar (isPrefix = false) + *
    + *

    + * will return the following results when prefix="foo/": + * + *

      + *
    • foo/foo1 (isPrefix = false) + *
    • foo/foo2 (isPrefix = false) + *
    + * + * @param directory + * The directory to list blobs underneath + * + * @return + * A reactive response emitting the prefixes and blobs. + */ + public Flux listBlobsHierarchy(String directory) { + return this.listBlobsHierarchy("/", new ListBlobsOptions().prefix(directory)); + } + + /** + * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under + * the given prefix (directory). Directories will have {@link BlobItem#isPrefix()} set to + * true. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return the following results when prefix=null: + * + *

      + *
    • foo/ (isPrefix = true) + *
    • bar (isPrefix = false) + *
    + *

    + * will return the following results when prefix="foo/": + * + *

      + *
    • foo/foo1 (isPrefix = false) + *
    • foo/foo2 (isPrefix = false) + *
    + * + * @param delimiter + * The delimiter for blob hierarchy, "/" for hierarchy based on directories + * @param options + * {@link ListBlobsOptions} + * + * @return + * A reactive response emitting the prefixes and blobs. + */ + public Flux listBlobsHierarchy(String delimiter, ListBlobsOptions options) { + return containerAsyncRawClient.listBlobsHierarchySegment(null, delimiter, options) + .flatMapMany(response -> listBlobsHierarchyHelper(delimiter, options, Context.NONE, response)); + } + + private Flux listBlobsHierarchyHelper(String delimiter, ListBlobsOptions options, + Context context, ContainersListBlobHierarchySegmentResponse response) { + Flux blobs; + Flux prefixes; + BlobHierarchyListSegment segment = response.value().segment(); + if (segment != null && segment.blobItems() != null) { + blobs = Flux.fromIterable(segment.blobItems()); + } else { + blobs = Flux.empty(); + } + if (segment != null && segment.blobPrefixes() != null) { + prefixes = Flux.fromIterable(segment.blobPrefixes()); + } else { + prefixes = Flux.empty(); + } + Flux result = blobs.concatWith(prefixes.map(prefix -> new BlobItem().name(prefix.name()).isPrefix(true))); + + if (response.value().nextMarker() != null) { + // Recursively add the continuation items to the observable. + result = result.concatWith(containerAsyncRawClient.listBlobsHierarchySegment(response.value().nextMarker(), delimiter, options) + .flatMapMany(r -> listBlobsHierarchyHelper(delimiter, options, context, r))); + } + + return result; + } + + /** + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param delimiter + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ +// public Flux listBlobsHierarchySegment(String marker, String delimiter, +// ListBlobsOptions options) { +// return this.listBlobsHierarchySegment(marker, delimiter, options, null); +// } + + /** + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param delimiter + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. + * @param options + * {@link ListBlobsOptions} + * @param context + * {@code Context} offers a means of passing arbitrary data (key/value pairs) to an + * {@link com.azure.core.http.HttpPipeline}'s policy objects. Most applications do not need to pass + * arbitrary data to the pipeline and can pass {@code Context.NONE} or {@code null}. Each context object is + * immutable. The {@code withContext} with data method creates a new {@code Context} object that refers to its + * parent, forming a linked list. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ +// public Flux listBlobsHierarchySegment(String marker, String delimiter, +// ListBlobsOptions options) { +// return containerAsyncRawClient +// .listBlobsHierarchySegment(null, delimiter, options) +// .flatMapMany(); +// } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedId + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * + * @return + * A reactive response containing the lease ID. + */ + public Mono> acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedID + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the lease ID. + */ + public Mono> acquireLease(String proposedID, int duration, ModifiedAccessConditions modifiedAccessConditions) { + return containerAsyncRawClient + .acquireLease(proposedID, duration, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * A reactive response containing the renewed lease ID. + */ + public Mono> renewLease(String leaseID) { + return this.renewLease(leaseID, null); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the renewed lease ID. + */ + public Mono> renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + return containerAsyncRawClient + .renewLease(leaseID, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * A reactive response signalling completion. + */ + public Mono releaseLease(String leaseID) { + return this.releaseLease(leaseID, null); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response signalling completion. + */ + public Mono releaseLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions) { + return containerAsyncRawClient + .releaseLease(leaseID, modifiedAccessConditions) + .map(VoidResponse::new); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @return + * A reactive response containing the remaining time in the broken lease. + */ + public Mono> breakLease() { + return this.breakLease(null, null); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the + * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response containing the remaining time in the broken lease. + */ + public Mono> breakLease(Integer breakPeriodInSeconds, ModifiedAccessConditions modifiedAccessConditions) { + return containerAsyncRawClient + .breakLease(breakPeriodInSeconds, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, Duration.ofSeconds(rb.deserializedHeaders().leaseTime()))); + } + + /** + * ChangeLease changes the blob's lease ID. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return + * A reactive response containing the new lease ID. + */ + public Mono> changeLease(String leaseId, String proposedID) { + return this.changeLease(leaseId, proposedID, null); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return A reactive response containing the new lease ID. + */ + public Mono> changeLease(String leaseId, String proposedID, ModifiedAccessConditions modifiedAccessConditions) { + return containerAsyncRawClient + .changeLease(leaseId, proposedID, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().leaseId())); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return + * A reactive response containing the account info. + */ + public Mono> getAccountInfo() { + return containerAsyncRawClient + .getAccountInfo() + .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java new file mode 100644 index 0000000000000..e4106549b208c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerAsyncRawClient.java @@ -0,0 +1,708 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +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.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.BlobListDetails; +import com.azure.storage.blob.models.ContainerAccessConditions; +import com.azure.storage.blob.models.ContainerAccessPolicies; +import com.azure.storage.blob.models.ContainersAcquireLeaseResponse; +import com.azure.storage.blob.models.ContainersBreakLeaseResponse; +import com.azure.storage.blob.models.ContainersChangeLeaseResponse; +import com.azure.storage.blob.models.ContainersCreateResponse; +import com.azure.storage.blob.models.ContainersDeleteResponse; +import com.azure.storage.blob.models.ContainersGetAccountInfoResponse; +import com.azure.storage.blob.models.ContainersGetPropertiesResponse; +import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; +import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; +import com.azure.storage.blob.models.ContainersReleaseLeaseResponse; +import com.azure.storage.blob.models.ContainersRenewLeaseResponse; +import com.azure.storage.blob.models.ContainersSetAccessPolicyResponse; +import com.azure.storage.blob.models.ContainersSetMetadataResponse; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ListBlobsOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.SignedIdentifier; +import reactor.core.publisher.Mono; + +import java.time.temporal.ChronoUnit; +import java.util.List; + +import static com.azure.storage.blob.Utility.postProcessResponse; + +/** + * Represents a URL to a container. It may be obtained by direct construction or via the create method on a + * {@link StorageAsyncRawClient} object. This class does not hold any state about a particular blob but is instead a convenient way + * of sending off appropriate requests to the resource on the service. It may also be used to construct URLs to blobs. + * Please refer to the + * Azure Docs + * for more information on containers. + */ +final class ContainerAsyncRawClient { + + public static final String ROOT_CONTAINER_NAME = "$root"; + + public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; + + public static final String LOG_CONTAINER_NAME = "$logs"; + + AzureBlobStorageImpl azureBlobStorage; + + /** + * Creates a {@code ContainerAsyncClient} object pointing to the account specified by the URL and using the provided + * pipeline to make HTTP requests. + */ + ContainerAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { + this.azureBlobStorage = azureBlobStorage; + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create() { + return this.create(null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create(Metadata metadata, PublicAccessType accessType) { + metadata = metadata == null ? new Metadata() : metadata; + + return postProcessResponse(this.azureBlobStorage.containers().createWithRestResponseAsync( + null, null, metadata, accessType, null, Context.NONE)); + + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono delete() { + return this.delete(null); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either + * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono delete(ContainerAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + + if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .deleteWithRestResponseAsync(null, null, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getProperties() { + return this.getProperties(null); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getProperties(LeaseAccessConditions leaseAccessConditions) { + return postProcessResponse(this.azureBlobStorage.containers() + .getPropertiesWithRestResponseAsync(null, null, null, + leaseAccessConditions, Context.NONE)); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has anything + * set other than {@link ModifiedAccessConditions#ifModifiedSince()}. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setMetadata(Metadata metadata, + ContainerAccessConditions accessConditions) { + metadata = metadata == null ? new Metadata() : metadata; + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + if (!validateNoEtag(accessConditions.modifiedAccessConditions()) + || accessConditions.modifiedAccessConditions().ifUnmodifiedSince() != null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "If-Modified-Since is the only HTTP access condition supported for this API"); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .setMetadataWithRestResponseAsync(null, null, metadata, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono> getAccessPolicy() { + return this.getAccessPolicy(null); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono> getAccessPolicy(LeaseAccessConditions leaseAccessConditions) { + return postProcessResponse(this.azureBlobStorage.containers().getAccessPolicyWithRestResponseAsync(null, null, null, leaseAccessConditions, Context.NONE) + .map(response -> new SimpleResponse<>(response, new ContainerAccessPolicies(response.deserializedHeaders().blobPublicAccess(), response.value())))); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setAccessPolicy(PublicAccessType accessType, + List identifiers) { + return this.setAccessPolicy(accessType, identifiers, null); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If {@link ContainerAccessConditions#modifiedAccessConditions()} has either + * {@link ModifiedAccessConditions#ifMatch()} or {@link ModifiedAccessConditions#ifNoneMatch()} set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setAccessPolicy(PublicAccessType accessType, + List identifiers, ContainerAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new ContainerAccessConditions() : accessConditions; + + if (!validateNoEtag(accessConditions.modifiedAccessConditions())) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException("ETag access conditions are not supported for this API."); + } + + /* + We truncate to seconds because the service only supports nanoseconds or seconds, but doing an + OffsetDateTime.now will only give back milliseconds (more precise fields are zeroed and not serialized). This + allows for proper serialization with no real detriment to users as sub-second precision on active time for + signed identifiers is not really necessary. + */ + if (identifiers != null) { + for (SignedIdentifier identifier : identifiers) { + if (identifier.accessPolicy() != null && identifier.accessPolicy().start() != null) { + identifier.accessPolicy().start( + identifier.accessPolicy().start().truncatedTo(ChronoUnit.SECONDS)); + } + if (identifier.accessPolicy() != null && identifier.accessPolicy().expiry() != null) { + identifier.accessPolicy().expiry( + identifier.accessPolicy().expiry().truncatedTo(ChronoUnit.SECONDS)); + } + } + } + + return postProcessResponse(this.azureBlobStorage.containers() + .setAccessPolicyWithRestResponseAsync(null, identifiers, null, accessType, + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)); + + } + + private boolean validateNoEtag(ModifiedAccessConditions modifiedAccessConditions) { + if (modifiedAccessConditions == null) { + return true; + } + return modifiedAccessConditions.ifMatch() == null && modifiedAccessConditions.ifNoneMatch() == null; + } + + /** + * Acquires a lease on the container for delete operations. The lease duration must be between 15 to + * 60 seconds, or infinite (-1). For more information, see the + * Azure Docs. + * + * @apiNote + * ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + * + * @param proposedId + * A {@code String} in any valid GUID format. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. + * A non-infinite lease can be between 15 and 60 seconds. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null); + } + + /** + * Acquires a lease on the container for delete operations. The lease duration must be between 15 to + * 60 seconds, or infinite (-1). For more information, see the + * Azure Docs. + * + * @param proposedID + * A {@code String} in any valid GUID format. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. + * A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or + * {@link ModifiedAccessConditions#ifNoneMatch()} is set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono acquireLease(String proposedID, int duration, + ModifiedAccessConditions modifiedAccessConditions) { + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().acquireLeaseWithRestResponseAsync( + null, null, duration, proposedID, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Renews the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono renewLease(String leaseID) { + return this.renewLease(leaseID, null); + } + + /** + * Renews the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or + * {@link ModifiedAccessConditions#ifNoneMatch()} is set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono renewLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions) { + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().renewLeaseWithRestResponseAsync(null, + leaseID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Releases the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono releaseLease(String leaseID) { + return this.releaseLease(leaseID, null); + } + + /** + * Releases the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or + * {@link ModifiedAccessConditions#ifNoneMatch()} is set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono releaseLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions) { + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().releaseLeaseWithRestResponseAsync( + null, leaseID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Breaks the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @apiNote + * ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + * + * @return Emits the successful response. + */ + public Mono breakLease() { + return this.breakLease(null, null); + } + + /** + * Breaks the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the time + * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or + * {@link ModifiedAccessConditions#ifNoneMatch()} is set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono breakLease(Integer breakPeriodInSeconds, + ModifiedAccessConditions modifiedAccessConditions) { + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().breakLeaseWithRestResponseAsync(null, + null, breakPeriodInSeconds, null, modifiedAccessConditions, Context.NONE)); + + } + + /** + * Changes the container's leaseAccessConditions. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono changeLease(String leaseID, String proposedID) { + return this.changeLease(leaseID, proposedID, null); + } + + /** + * Changes the container's leaseAccessConditions. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If either {@link ModifiedAccessConditions#ifMatch()} or + * {@link ModifiedAccessConditions#ifNoneMatch()} is set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono changeLease(String leaseID, String proposedID, + ModifiedAccessConditions modifiedAccessConditions) { + if (!this.validateNoEtag(modifiedAccessConditions)) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new UnsupportedOperationException( + "ETag access conditions are not supported for this API."); + } + + return postProcessResponse(this.azureBlobStorage.containers().changeLeaseWithRestResponseAsync(null, + leaseID, proposedID, null, null, modifiedAccessConditions, Context.NONE)); + } + + /** + * Returns a single segment of blobs starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono listBlobsFlatSegment(String marker, ListBlobsOptions options) { + options = options == null ? new ListBlobsOptions() : options; + + return postProcessResponse(this.azureBlobStorage.containers() + .listBlobFlatSegmentWithRestResponseAsync(null, options.prefix(), marker, + options.maxResults(), options.details().toList(), null, null, Context.NONE)); + } + + /** + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param delimiter + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * @throws UnsupportedOperationException If {@link ListBlobsOptions#details()} has {@link BlobListDetails#snapshots()} + * set. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono listBlobsHierarchySegment(String marker, String delimiter, + ListBlobsOptions options) { + options = options == null ? new ListBlobsOptions() : options; + if (options.details().snapshots()) { + throw new UnsupportedOperationException("Including snapshots in a hierarchical listing is not supported."); + } + + return postProcessResponse(this.azureBlobStorage.containers() + .listBlobHierarchySegmentWithRestResponseAsync(null, delimiter, options.prefix(), marker, + options.maxResults(), options.details().toList(), null, null, Context.NONE)); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getAccountInfo() { + return postProcessResponse( + this.azureBlobStorage.containers().getAccountInfoWithRestResponseAsync(null, Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java new file mode 100644 index 0000000000000..b8c1f9d8bd09e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClient.java @@ -0,0 +1,741 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.blob.models.BlobItem; +import com.azure.storage.blob.models.ContainerAccessConditions; +import com.azure.storage.blob.models.ContainerAccessPolicies; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ListBlobsOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.SignedIdentifier; +import com.azure.storage.blob.models.StorageAccountInfo; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.Duration; +import java.util.List; + +/** + * Client to a container. It may only be instantiated through a {@link ContainerClientBuilder} or via the method + * {@link StorageClient#getContainerClient(String)}. This class does not hold any + * state about a particular container but is instead a convenient way of sending off appropriate requests to + * the resource on the service. It may also be used to construct URLs to blobs. + * + *

    + * This client contains operations on a container. Operations on a blob are available on {@link BlobClient} through + * {@link #getBlobClient(String)}, and operations on the service are available on {@link StorageClient}. + * + *

    + * Please refer to the Azure Docs + * for more information on containers. + */ +public final class ContainerClient { + + private ContainerAsyncClient containerAsyncClient; + + public static final String ROOT_CONTAINER_NAME = "$root"; + + public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; + + public static final String LOG_CONTAINER_NAME = "$logs"; + + /** + * Package-private constructor for use by {@link ContainerClientBuilder}. + * @param containerAsyncClient the async container client + */ + ContainerClient(ContainerAsyncClient containerAsyncClient) { + this.containerAsyncClient = containerAsyncClient; + } + + /** + * Creates a new {@link BlockBlobClient} object by concatenating the blobName to the end of + * ContainerAsyncClient's URL. The new BlockBlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlockBlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's + * NewBlockBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link BlockBlobClient} object which references the blob with the specified name in this container. + */ + public BlockBlobClient getBlockBlobClient(String blobName) { + return new BlockBlobClient(containerAsyncClient.getBlockBlobAsyncClient(blobName)); + } + + /** + * Creates a new {@link BlockBlobClient} object by concatenating the blobName to the end of + * ContainerAsyncClient's URL. The new BlockBlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlockBlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewBlockBlobAsyncClient instead of calling this object's + * NewBlockBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link BlockBlobClient} object which references the blob with the specified name in this container. + */ + public BlockBlobClient getBlockBlobClient(String blobName, String snapshot) { + return new BlockBlobClient(containerAsyncClient.getBlockBlobAsyncClient(blobName, snapshot)); + } + + /** + * Creates creates a new PageBlobClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new PageBlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the PageBlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's + * NewPageBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link PageBlobClient} object which references the blob with the specified name in this container. + */ + public PageBlobClient getPageBlobClient(String blobName) { + return new PageBlobClient(containerAsyncClient.getPageBlobAsyncClient(blobName)); + } + + /** + * Creates creates a new PageBlobClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new PageBlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the PageBlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewPageBlobAsyncClient instead of calling this object's + * NewPageBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link PageBlobClient} object which references the blob with the specified name in this container. + */ + public PageBlobClient getPageBlobClient(String blobName, String snapshot) { + return new PageBlobClient(containerAsyncClient.getPageBlobAsyncClient(blobName, snapshot)); + } + + /** + * Creates creates a new AppendBlobClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new AppendBlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the AppendBlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's NewAppendBlobAsyncClient instead of calling this object's + * NewAppendBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link AppendBlobClient} object which references the blob with the specified name in this container. + */ + public AppendBlobClient getAppendBlobClient(String blobName) { + return new AppendBlobClient(containerAsyncClient.getAppendBlobAsyncClient(blobName)); + } + + /** + * Initializes a new BlobClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new BlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's + * getBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * + * @return A new {@link BlobClient} object which references the blob with the specified name in this container. + */ + public BlobClient getBlobClient(String blobName) { + return new BlobClient(containerAsyncClient.getBlobAsyncClient(blobName)); + } + + /** + * Initializes a new BlobClient object by concatenating blobName to the end of + * ContainerAsyncClient's URL. The new BlobClient uses the same request policy pipeline as the ContainerAsyncClient. + * To change the pipeline, create the BlobClient and then call its WithPipeline method passing in the + * desired pipeline object. Or, call this package's getBlobAsyncClient instead of calling this object's + * getBlobAsyncClient method. + * + * @param blobName + * A {@code String} representing the name of the blob. + * @param snapshot + * the snapshot identifier for the blob. + * + * @return A new {@link BlobClient} object which references the blob with the specified name in this container. + */ + public BlobClient getBlobClient(String blobName, String snapshot) { + return new BlobClient(containerAsyncClient.getBlobAsyncClient(blobName, snapshot)); + } + + /** + * Initializes a {@link StorageClient} object pointing to the storage account this container is in. + * + * @return + * A {@link StorageClient} object pointing to the specified storage account + */ + public StorageClient getStorageClient() { + return new StorageClient(containerAsyncClient.getStorageAsyncClient()); + } + + /** + * Gets the URL of the container represented by this client. + * @return the URL. + */ + public URL getContainerUrl() { + return containerAsyncClient.getContainerUrl(); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + * @return true if the container exists, false if it doesn't + */ + public Response exists() { + return this.exists(null); + } + + /** + * Gets if the container this client represents exists in the cloud. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return + * true if the container exists, false if it doesn't + */ + public Response exists(Duration timeout) { + Mono> response = containerAsyncClient.exists(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * @return A response containing status code and HTTP headers + */ + public VoidResponse create() { + return this.create(null, null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse create(Metadata metadata, PublicAccessType accessType, Duration timeout) { + Mono response = containerAsyncClient.create(metadata, accessType); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * @return A response containing status code and HTTP headers + */ + public VoidResponse delete() { + return this.delete(null, null); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @param accessConditions + * {@link ContainerAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse delete(ContainerAccessConditions accessConditions, Duration timeout) { + Mono response = containerAsyncClient.delete(accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @return + * The container properties. + */ + public Response getProperties() { + return this.getProperties(null, null); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The container properties. + */ + public Response getProperties(LeaseAccessConditions leaseAccessConditions, + Duration timeout) { + Mono> response = containerAsyncClient.getProperties(leaseAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @return A response containing status code and HTTP headers + */ + public VoidResponse setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null, null); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link ContainerAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse setMetadata(Metadata metadata, + ContainerAccessConditions accessConditions, Duration timeout) { + Mono response = containerAsyncClient.setMetadata(metadata, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @return + * The container access policy. + */ + public Response getAccessPolicy() { + return this.getAccessPolicy(null, null); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The container access policy. + */ + public Response getAccessPolicy(LeaseAccessConditions leaseAccessConditions, + Duration timeout) { + Mono> response = containerAsyncClient.getAccessPolicy(leaseAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * @return A response containing status code and HTTP headers + */ + public VoidResponse setAccessPolicy(PublicAccessType accessType, + List identifiers) { + return this.setAccessPolicy(accessType, identifiers, null, null); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions + * {@link ContainerAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers + */ + public VoidResponse setAccessPolicy(PublicAccessType accessType, + List identifiers, ContainerAccessConditions accessConditions, + Duration timeout) { + Mono response = containerAsyncClient.setAccessPolicy(accessType, identifiers, accessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns a lazy loaded list of blobs in this container, with folder structures flattened. + * The returned {@link Iterable} can be iterated through while new items are automatically + * retrieved as needed. + * + *

    + * Blob names are returned in lexicographic order. + * + *

    + * For more information, see the + * Azure Docs. + * + * @return + * The listed blobs, flattened. + */ + public Iterable listBlobsFlat() { + return this.listBlobsFlat(new ListBlobsOptions(), null); + } + + /** + * Returns a lazy loaded list of blobs in this container, with folder structures flattened. + * The returned {@link Iterable} can be iterated through while new items are automatically + * retrieved as needed. + * + *

    + * Blob names are returned in lexicographic order. + * + *

    + * For more information, see the + * Azure Docs. + * + * @param options + * {@link ListBlobsOptions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The listed blobs, flattened. + */ + public Iterable listBlobsFlat(ListBlobsOptions options, Duration timeout) { + Flux response = containerAsyncClient.listBlobsFlat(options); + + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Returns a reactive Publisher emitting all the blobs and directories (prefixes) under + * the given directory (prefix). Directories will have {@link BlobItem#isPrefix()} set to + * true. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return the following results when prefix=null: + * + *

      + *
    • foo/ (isPrefix = true) + *
    • bar (isPrefix = false) + *
    + *

    + * will return the following results when prefix="foo/": + * + *

      + *
    • foo/foo1 (isPrefix = false) + *
    • foo/foo2 (isPrefix = false) + *
    + * + * @param directory + * The directory to list blobs underneath + * + * @return + * A reactive response emitting the prefixes and blobs. + */ + public Iterable listBlobsHierarchy(String directory) { + return this.listBlobsHierarchy("/", new ListBlobsOptions().prefix(directory), null); + } + + /** + * Returns a reactive Publisher emitting all the blobs and prefixes (directories) under + * the given prefix (directory). Directories will have {@link BlobItem#isPrefix()} set to + * true. + * + *

    + * Blob names are returned in lexicographic order. For more information, see the + * Azure Docs. + * + *

    + * E.g. listing a container containing a 'foo' folder, which contains blobs 'foo1' and 'foo2', and a blob + * on the root level 'bar', will return the following results when prefix=null: + * + *

      + *
    • foo/ (isPrefix = true) + *
    • bar (isPrefix = false) + *
    + *

    + * will return the following results when prefix="foo/": + * + *

      + *
    • foo/foo1 (isPrefix = false) + *
    • foo/foo2 (isPrefix = false) + *
    + * + * @param delimiter + * The delimiter for blob hierarchy, "/" for hierarchy based on directories + * @param options + * {@link ListBlobsOptions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * A reactive response emitting the prefixes and blobs. + */ + public Iterable listBlobsHierarchy(String delimiter, ListBlobsOptions options, Duration timeout) { + Flux response = containerAsyncClient.listBlobsHierarchy(delimiter, options); + + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedId + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * + * @return + * The lease ID. + */ + public Response acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null, null); + } + + /** + * Acquires a lease on the blob for write and delete operations. The lease duration must be between 15 to 60 + * seconds, or infinite (-1). + * + * @param proposedID + * A {@code String} in any valid GUID format. May be null. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that + * never expires. A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The lease ID. + */ + public Response acquireLease(String proposedID, int duration, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = containerAsyncClient + .acquireLease(proposedID, duration, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * + * @return + * The renewed lease ID. + */ + public Response renewLease(String leaseID) { + return this.renewLease(leaseID, null, null); + } + + /** + * Renews the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The renewed lease ID. + */ + public Response renewLease(String leaseID, ModifiedAccessConditions modifiedAccessConditions, + Duration timeout) { + Mono> response = containerAsyncClient + .renewLease(leaseID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @return A response containing status code and HTTP headers + */ + public VoidResponse releaseLease(String leaseID) { + return this.releaseLease(leaseID, null, null); + } + + /** + * Releases the blob's previously-acquired lease. + * + * @param leaseID + * The leaseId of the active lease on the blob. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @return A response containing status code and HTTP headers. + */ + public VoidResponse releaseLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncClient + .releaseLease(leaseID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @return + * The remaining time in the broken lease. + */ + public Response breakLease() { + return this.breakLease(null, null, null); + } + + /** + * BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) constant + * to break a fixed-duration lease when it expires or an infinite lease immediately. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the + * time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break + * period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The remaining time in the broken lease. + */ + public Response breakLease(Integer breakPeriodInSeconds, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = containerAsyncClient + .breakLease(breakPeriodInSeconds, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * ChangeLease changes the blob's lease ID. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return + * The new lease ID. + */ + public Response changeLease(String leaseId, String proposedID) { + return this.changeLease(leaseId, proposedID, null, null); + } + + /** + * ChangeLease changes the blob's lease ID. For more information, see the Azure Docs. + * + * @param leaseId + * The leaseId of the active lease on the blob. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return The new lease ID. + */ + public Response changeLease(String leaseId, String proposedID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = containerAsyncClient + .changeLease(leaseId, proposedID, modifiedAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The account info. + */ + public Response getAccountInfo(Duration timeout) { + Mono> response = containerAsyncClient.getAccountInfo(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java new file mode 100644 index 0000000000000..c1e4e6bbdaeb2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerClientBuilder.java @@ -0,0 +1,314 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent ContainerClientBuilder for instantiating a {@link ContainerClient} or {@link ContainerAsyncClient} + * using {@link ContainerClientBuilder#buildClient()} or {@link ContainerClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, including the container name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link ContainerClient} or {@code .buildAsyncClient()} to create a {@link ContainerAsyncClient}. + */ +public final class ContainerClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private String containerName; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link ContainerClient ContainerClients} + * and {@link ContainerAsyncClient ContainerAsyncClients}. + */ + public ContainerClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + /** + * Constructs an instance of ContainerAsyncClient based on the configurations stored in the appendBlobClientBuilder. + * @return a new client instance + */ + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(containerName); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(String.format("%s/%s", endpoint, containerName)) + .pipeline(pipeline); + } + + /** + * @return a {@link ContainerClient} created from the configurations in this builder. + */ + public ContainerClient buildClient() { + return new ContainerClient(buildAsyncClient()); + } + + /** + * @return a {@link ContainerAsyncClient} created from the configurations in this builder. + */ + public ContainerAsyncClient buildAsyncClient() { + return new ContainerAsyncClient(buildImpl()); + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name) + * @param endpoint URL of the service + * @return the updated ContainerClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL. + */ + public ContainerClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + this.endpoint = url.getProtocol() + "://" + url.getAuthority(); + String path = url.getPath(); + if (path != null && !path.isEmpty() && !path.equals("/")) { + path = path.replaceAll("^/", "").replaceAll("/$", ""); + if (path.contains("/")) { + throw new IllegalArgumentException("Endpoint should contain exactly 0 or 1 path segments"); + } else { + this.containerName = path; + } + } + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * @param containerName the name of the container + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder containerName(String containerName) { + this.containerName = containerName; + return this; + } + + String endpoint() { + return this.endpoint; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated ContainerClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey + */ + public ContainerClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated ContainerClientBuilder object + */ + public ContainerClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerProperties.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerProperties.java new file mode 100644 index 0000000000000..9cada777b6236 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerProperties.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.blob.models.ContainerGetPropertiesHeaders; +import com.azure.storage.blob.models.PublicAccessType; + +public class ContainerProperties { + + private PublicAccessType blobPublicAccess; + + private boolean hasImmutabilityPolicy; + + private boolean hasLegalHold; + + //todo decide datetime representation for last modified time + + ContainerProperties(ContainerGetPropertiesHeaders generatedResponseHeaders) { + this.blobPublicAccess = generatedResponseHeaders.blobPublicAccess(); + this.hasImmutabilityPolicy = generatedResponseHeaders.hasImmutabilityPolicy(); + this.hasLegalHold = generatedResponseHeaders.hasLegalHold(); + } + + /** + * @return the access type for the container + */ + public PublicAccessType blobPublicAccess() { + return blobPublicAccess; + } + + /** + * @return the immutability status for the container + */ + public boolean hasImmutabilityPolicy() { + return hasImmutabilityPolicy; + } + + /** + * @return the legal hold status for the container + */ + public boolean hasLegalHold() { + return hasLegalHold; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java new file mode 100644 index 0000000000000..19d10f5444ee5 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerRawClient.java @@ -0,0 +1,652 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.ContainerAccessConditions; +import com.azure.storage.blob.models.ContainerAccessPolicies; +import com.azure.storage.blob.models.ContainersAcquireLeaseResponse; +import com.azure.storage.blob.models.ContainersBreakLeaseResponse; +import com.azure.storage.blob.models.ContainersChangeLeaseResponse; +import com.azure.storage.blob.models.ContainersCreateResponse; +import com.azure.storage.blob.models.ContainersDeleteResponse; +import com.azure.storage.blob.models.ContainersGetAccountInfoResponse; +import com.azure.storage.blob.models.ContainersGetPropertiesResponse; +import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; +import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; +import com.azure.storage.blob.models.ContainersReleaseLeaseResponse; +import com.azure.storage.blob.models.ContainersRenewLeaseResponse; +import com.azure.storage.blob.models.ContainersSetAccessPolicyResponse; +import com.azure.storage.blob.models.ContainersSetMetadataResponse; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ListBlobsOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.SignedIdentifier; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.List; + +/** + * Represents a URL to a container. It may be obtained by direct construction or via the create method on a + * {@link StorageAsyncRawClient} object. This class does not hold any state about a particular blob but is instead a convenient way + * of sending off appropriate requests to the resource on the service. It may also be used to construct URLs to blobs. + * Please refer to the + * Azure Docs + * for more information on containers. + */ +final class ContainerRawClient { + + private ContainerAsyncRawClient containerAsyncRawClient; + + public static final String ROOT_CONTAINER_NAME = "$root"; + + public static final String STATIC_WEBSITE_CONTAINER_NAME = "$web"; + + public static final String LOG_CONTAINER_NAME = "$logs"; + + + /** + * Creates a {@code ContainerAsyncClient} object pointing to the account specified by the URL and using the provided + * pipeline to make HTTP requests. + */ + ContainerRawClient(AzureBlobStorageImpl azureBlobStorage) { + this.containerAsyncRawClient = new ContainerAsyncRawClient(azureBlobStorage); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersCreateResponse create() { + return this.create(null, null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersCreateResponse create(Metadata metadata, PublicAccessType accessType, Duration timeout) { + Mono response = containerAsyncRawClient.create(metadata, accessType); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersDeleteResponse delete() { + return this.delete(null, null); + } + + /** + * Marks the specified container for deletion. The container and any blobs contained within it are later + * deleted during garbage collection. For more information, see the + * Azure Docs. + * + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.delete")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersDeleteResponse delete(ContainerAccessConditions accessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.delete(accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersGetPropertiesResponse getProperties() { + return this.getProperties(null, null); + } + + /** + * Returns the container's metadata and system properties. For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersGetPropertiesResponse getProperties(LeaseAccessConditions leaseAccessConditions, + Duration timeout) { + Mono response = containerAsyncRawClient.getProperties(leaseAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersSetMetadataResponse setMetadata(Metadata metadata) { + return this.setMetadata(metadata, null, null); + } + + /** + * Sets the container's metadata. For more information, see the + * Azure Docs. + * + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_basic "Sample code for ContainerAsyncClient.setMetadata")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersSetMetadataResponse setMetadata(Metadata metadata, + ContainerAccessConditions accessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.setMetadata(metadata, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Response getAccessPolicy() { + return this.getAccessPolicy(null, null); + } + + /** + * Returns the container's permissions. The permissions indicate whether container's blobs may be accessed publicly. + * For more information, see the + * Azure Docs. + * + * @param leaseAccessConditions + * By setting lease access conditions, requests will fail if the provided lease does not match the active + * lease on the blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.getAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Response getAccessPolicy(LeaseAccessConditions leaseAccessConditions, + Duration timeout) { + Mono> response = containerAsyncRawClient.getAccessPolicy(leaseAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersSetAccessPolicyResponse setAccessPolicy(PublicAccessType accessType, + List identifiers) { + return this.setAccessPolicy(accessType, identifiers, null, null); + } + + /** + * Sets the container's permissions. The permissions indicate whether blobs in a container may be accessed publicly. + * Note that, for each signed identifier, we will truncate the start and expiry times to the nearest second to + * ensure the time formatting is compatible with the service. For more information, see the + * Azure Docs. + * + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @param identifiers + * A list of {@link SignedIdentifier} objects that specify the permissions for the container. Please see + * here + * for more information. Passing null will clear all access policies. + * @param accessConditions + * {@link ContainerAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_policy "Sample code for ContainerAsyncClient.setAccessPolicy")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersSetAccessPolicyResponse setAccessPolicy(PublicAccessType accessType, + List identifiers, ContainerAccessConditions accessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.setAccessPolicy(accessType, identifiers, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Acquires a lease on the container for delete operations. The lease duration must be between 15 to + * 60 seconds, or infinite (-1). For more information, see the + * Azure Docs. + * + * @apiNote + * ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + * + * @param proposedId + * A {@code String} in any valid GUID format. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. + * A non-infinite lease can be between 15 and 60 seconds. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersAcquireLeaseResponse acquireLease(String proposedId, int duration) { + return this.acquireLease(proposedId, duration, null, null); + } + + /** + * Acquires a lease on the container for delete operations. The lease duration must be between 15 to + * 60 seconds, or infinite (-1). For more information, see the + * Azure Docs. + * + * @param proposedID + * A {@code String} in any valid GUID format. + * @param duration + * The duration of the lease, in seconds, or negative one (-1) for a lease that never expires. + * A non-infinite lease can be between 15 and 60 seconds. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.acquireLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersAcquireLeaseResponse acquireLease(String proposedID, int duration, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.acquireLease(proposedID, duration, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Renews the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersRenewLeaseResponse renewLease(String leaseID) { + return this.renewLease(leaseID, null, null); + } + + /** + * Renews the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.renewLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersRenewLeaseResponse renewLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.renewLease(leaseID, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Releases the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersReleaseLeaseResponse releaseLease(String leaseID) { + return this.releaseLease(leaseID, null, null); + } + + /** + * Releases the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.releaseLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersReleaseLeaseResponse releaseLease(String leaseID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.releaseLease(leaseID, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Breaks the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @apiNote + * ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/New-Storage-SDK-V10-Preview/src/test/java/com/microsoft/azure/storage/Samples.java) + * + * @return Emits the successful response. + */ + public ContainersBreakLeaseResponse breakLease() { + return this.breakLease(null, null, null); + } + + /** + * Breaks the container's previously-acquired lease. For more information, see the + * Azure Docs. + * + * @param breakPeriodInSeconds + * An optional {@code Integer} representing the proposed duration of seconds that the lease should continue + * before it is broken, between 0 and 60 seconds. This break period is only used if it is shorter than the time + * remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be + * available before the break period has expired, but the lease may be held for longer than the break period. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.breakLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersBreakLeaseResponse breakLease(Integer breakPeriodInSeconds, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.breakLease(breakPeriodInSeconds, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Changes the container's leaseAccessConditions. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param proposedID + * A {@code String} in any valid GUID format. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersChangeLeaseResponse changeLease(String leaseID, String proposedID) { + return this.changeLease(leaseID, proposedID, null, null); + } + + /** + * Changes the container's leaseAccessConditions. For more information, see the + * Azure Docs. + * + * @param leaseID + * The leaseId of the active lease on the container. + * @param proposedID + * A {@code String} in any valid GUID format. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=container_lease "Sample code for ContainerAsyncClient.changeLease")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersChangeLeaseResponse changeLease(String leaseID, String proposedID, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono response = containerAsyncRawClient.changeLease(leaseID, proposedID, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns a single segment of blobs starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersListBlobFlatSegmentResponse listBlobsFlatSegment(String marker, ListBlobsOptions options) { + return this.listBlobsFlatSegment(marker, options, null); + } + + /** + * Returns a single segment of blobs starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsFlatSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat "Sample code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_flat_helper "helper code for ContainerAsyncClient.listBlobsFlatSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersListBlobFlatSegmentResponse listBlobsFlatSegment(String marker, ListBlobsOptions options, + Duration timeout) { + Mono response = containerAsyncRawClient.listBlobsFlatSegment(marker, options); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param delimiter + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersListBlobHierarchySegmentResponse listBlobsHierarchySegment(String marker, String delimiter, + ListBlobsOptions options) { + return this.listBlobsHierarchySegment(marker, delimiter, options, null); + } + + /** + * Returns a single segment of blobs and blob prefixes starting from the specified Marker. Use an empty + * marker to start enumeration from the beginning. Blob names are returned in lexicographic order. + * After getting a segment, process it, and then call ListBlobs again (passing the the previously-returned + * Marker) to get the next segment. For more information, see the + * Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListBlobsHierarchySegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param delimiter + * The operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs + * whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may + * be a single character or a string. + * @param options + * {@link ListBlobsOptions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy "Sample code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=list_blobs_hierarchy_helper "helper code for ContainerAsyncClient.listBlobsHierarchySegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersListBlobHierarchySegmentResponse listBlobsHierarchySegment(String marker, String delimiter, + ListBlobsOptions options, Duration timeout) { + Mono response = containerAsyncRawClient.listBlobsHierarchySegment(marker, delimiter, options); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersGetAccountInfoResponse getAccountInfo() { + return this.getAccountInfo(null); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ContainerAsyncClient.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ContainersGetAccountInfoResponse getAccountInfo(Duration timeout) { + Mono response = containerAsyncRawClient.getAccountInfo(); + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java new file mode 100644 index 0000000000000..0ac5e0f6738a3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ContainerSASPermission.java @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + + +import java.util.Locale; + +/** + * This is a helper class to construct a string representing the permissions granted by a ServiceSAS to a container. + * Setting a value to true means that any SAS which uses these permissions will grant permissions for that operation. + * Once all the values are set, this should be serialized with toString and set as the permissions field on a + * {@link ServiceSASSignatureValues} object. It is possible to construct the permissions string without this class, but + * the order of the permissions is particular and this class guarantees correctness. + */ +final class ContainerSASPermission { + private boolean read; + + private boolean add; + + private boolean create; + + private boolean write; + + private boolean delete; + + private boolean list; + + /** + * Initializes an {@code ContainerSASPermssion} object with all fields set to false. + */ + private ContainerSASPermission() { + } + + /** + * Creates an {@code ContainerSASPermission} from the specified permissions string. This method will throw an + * {@code IllegalArgumentException} if it encounters a character that does not correspond to a valid permission. + * + * @param permString + * A {@code String} which represents the {@code ContainerSASPermission}. + * + * @return A {@code ContainerSASPermission} generated from the given {@code String}. + * @throws IllegalArgumentException If {@code permString} contains a character other than r, a, c, w, d, or l. + */ + public static ContainerSASPermission parse(String permString) { + ContainerSASPermission permissions = new ContainerSASPermission(); + + for (int i = 0; i < permString.length(); i++) { + char c = permString.charAt(i); + switch (c) { + case 'r': + permissions.read = true; + break; + case 'a': + permissions.add = true; + break; + case 'c': + permissions.create = true; + break; + case 'w': + permissions.write = true; + break; + case 'd': + permissions.delete = true; + break; + case 'l': + permissions.list = true; + break; + default: + throw new IllegalArgumentException( + String.format(Locale.ROOT, SR.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permString, c)); + } + } + return permissions; + } + + /** + * Specifies Read access granted. + */ + public boolean read() { + return read; + } + + /** + * Specifies Read access granted. + */ + public ContainerSASPermission read(boolean read) { + this.read = read; + return this; + } + + /** + * Specifies Add access granted. + */ + public boolean add() { + return add; + } + + /** + * Specifies Add access granted. + */ + public ContainerSASPermission add(boolean add) { + this.add = add; + return this; + } + + /** + * Specifies Create access granted. + */ + public boolean create() { + return create; + } + + /** + * Specifies Create access granted. + */ + public ContainerSASPermission create(boolean create) { + this.create = create; + return this; + } + + /** + * Specifies Write access granted. + */ + public boolean write() { + return write; + } + + /** + * Specifies Write access granted. + */ + public ContainerSASPermission write(boolean write) { + this.write = write; + return this; + } + + /** + * Specifies Delete access granted. + */ + public boolean delete() { + return delete; + } + + /** + * Specifies Delete access granted. + */ + public ContainerSASPermission delete(boolean delete) { + this.delete = delete; + return this; + } + + /** + * Specifies List access granted. + */ + public boolean list() { + return list; + } + + /** + * Specifies List access granted. + */ + public ContainerSASPermission list(boolean list) { + this.list = list; + return this; + } + + /** + * Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an + * order accepted by the service. + * + * @return A {@code String} which represents the {@code ContainerSASPermission}. + */ + @Override + public String toString() { + // The order of the characters should be as specified here to ensure correctness: + // https://docs.microsoft.com/en-us/rest/api/storageservices/constructing-a-service-sas + final StringBuilder builder = new StringBuilder(); + + if (this.read) { + builder.append('r'); + } + + if (this.add) { + builder.append('a'); + } + + if (this.create) { + builder.append('c'); + } + + if (this.write) { + builder.append('w'); + } + + if (this.delete) { + builder.append('d'); + } + + if (this.list) { + builder.append('l'); + } + + return builder.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java new file mode 100644 index 0000000000000..e22a3fa72a16c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadAsyncResponse.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.ResponseBase; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobDownloadHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.ReliableDownloadOptions; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.util.Map; +import java.util.function.Function; + +/** + * {@code DownloadAsyncResponse} wraps the protocol-layer response from {@link BlobAsyncClient#download(BlobRange, + * BlobAccessConditions, boolean, ReliableDownloadOptions)} to automatically retry failed reads from the body as + * appropriate. If the download is interrupted, the {@code DownloadAsyncResponse} will make a request to resume the download + * from where it left off, allowing the user to consume the data as one continuous stream, for any interruptions are + * hidden. The retry behavior is defined by the options passed to the {@link #body(ReliableDownloadOptions)}. The + * download will also lock on the blob's etag to ensure consistency. + *

    + * Note that the retries performed as a part of this reader are composed with those of any retries in an {@link + * com.azure.core.http.HttpPipeline} used in conjunction with this reader. That is, if this object issues a request to resume a download, + * an underlying pipeline may issue several retries as a part of that request. Furthermore, this reader only retries on + * network errors; timeouts and unexpected status codes are not retried. Therefore, the behavior of this reader is + * entirely independent of and in no way coupled to an {@link com.azure.core.http.HttpPipeline}'s retry mechanism. + */ +public final class DownloadAsyncResponse { + private final HTTPGetterInfo info; + + private final ResponseBase> rawResponse; + + private final Function> getter; + + + // The constructor is package-private because customers should not be creating their own responses. + // TODO (unknown): resolve comment vs code mismatch + DownloadAsyncResponse(ResponseBase> response, + HTTPGetterInfo info, Function> getter) { + Utility.assertNotNull("getter", getter); + Utility.assertNotNull("info", info); + Utility.assertNotNull("info.eTag", info.eTag()); + this.rawResponse = response; + this.info = info; + this.getter = getter; + } + + /** + * Returns the response body which has been modified to enable reliably reading data if desired (if + * {@code options.maxRetryRequests > 0}. If retries are enabled, if a connection fails while reading, the stream + * will make additional requests to reestablish a connection and continue reading. + * + * @param options + * {@link ReliableDownloadOptions} + * + * @return A {@code Flux} which emits the data as {@code ByteBuffer}s. + */ + public Flux body(ReliableDownloadOptions options) { + ReliableDownloadOptions optionsReal = options == null ? new ReliableDownloadOptions() : options; + if (optionsReal.maxRetryRequests() == 0) { + return this.rawResponse.value(); + } + + /* + We pass -1 for currentRetryCount because we want tryContinueFlux to receive a value of 0 for number of + retries as we have not actually retried yet, only made the initial try. Because applyReliableDownload() will + add 1 before calling into tryContinueFlux, we set the initial value to -1. + */ + return this.applyReliableDownload(this.rawResponse.value(), -1, optionsReal); + } + + private Flux tryContinueFlux(Throwable t, int retryCount, ReliableDownloadOptions options) { + // If all the errors are exhausted, return this error to the user. + if (retryCount > options.maxRetryRequests() || !(t instanceof IOException)) { + return Flux.error(t); + } else { + /* + We wrap this in a try catch because we don't know the behavior of the getter. Most errors would probably + come from an unsuccessful request, which would be propagated through the onError methods. However, it is + possible the method call that returns a Single is what throws (like how our apis throw some exceptions at + call time rather than at subscription time. + */ + try { + // Get a new response and try reading from it. + return getter.apply(this.info) + .flatMapMany(response -> + /* + Do not compound the number of retries by passing in another set of downloadOptions; just get + the raw body. + */ + this.applyReliableDownload(this.rawResponse.value(), retryCount, options)); + } catch (Exception e) { + // If the getter fails, return the getter failure to the user. + return Flux.error(e); + } + } + } + + private Flux applyReliableDownload(Flux data, + int currentRetryCount, ReliableDownloadOptions options) { + return data + .doOnNext(buffer -> { + /* + Update how much data we have received in case we need to retry and propagate to the user the data we + have received. + */ + this.info.offset(this.info.offset() + buffer.readableBytes()); // was `remaining()` in Rx world + if (this.info.count() != null) { + this.info.count(this.info.count() - buffer.readableBytes()); // was `remaining()` in Rx world + } + }) + .onErrorResume(t2 -> { + // Increment the retry count and try again with the new exception. + return tryContinueFlux(t2, currentRetryCount + 1, options); + }); + } + + /** + * @return HTTP status of the download + */ + public int statusCode() { + return this.rawResponse.statusCode(); + } + + /** + * @return HTTP headers associated to the download + */ + public BlobDownloadHeaders headers() { + return this.rawResponse.deserializedHeaders(); + } + + /** + * @return all HTTP headers from the response + */ + public Map rawHeaders() { + return this.rawResponse.headers().toMap(); + } + + /** + * @return the raw response + */ + public ResponseBase> rawResponse() { + return this.rawResponse; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadResponse.java new file mode 100644 index 0000000000000..7acc6427dcf87 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/DownloadResponse.java @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.blob.models.ReliableDownloadOptions; +import io.netty.buffer.ByteBuf; + +import java.io.IOException; +import java.io.OutputStream; + +public class DownloadResponse { + private final DownloadAsyncResponse asyncResponse; + + DownloadResponse(DownloadAsyncResponse asyncResponse) { + this.asyncResponse = asyncResponse; + } + + /** + * Gets the body of the download response. + * + * @param outputStream Stream that has the response body read into it + * @param options Options for the download + * @throws IOException If an I/O error occurs + */ + public void body(OutputStream outputStream, ReliableDownloadOptions options) throws IOException { + for (ByteBuf buffer : this.asyncResponse.body(options).toIterable()) { + buffer.readBytes(outputStream, buffer.readableBytes()); + buffer.release(); + } + } + + //TODO (unknown): determine signature(s) to use + /*public InputStream body(ReliableDownloadOptions options) { + return new InputStream() { + + DownloadAsyncResponse response = asyncResponse; + @Override + public int read() throws IOException { + return 0; + } + }; + }*/ +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/HTTPGetterInfo.java b/storage/client/blob/src/main/java/com/azure/storage/blob/HTTPGetterInfo.java new file mode 100644 index 0000000000000..f868d8061d8df --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/HTTPGetterInfo.java @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.blob.models.BlobAccessConditions; + +import java.time.Duration; + +/** + * HTTPGetterInfo is a passed to the getter function of a reliable download to specify parameters needed for the GET + * request. + */ +final class HTTPGetterInfo { + private long offset = 0; + + private Long count = null; + + private String eTag = null; + + /** + * The start offset that should be used when creating the HTTP GET request's Range header. Defaults to 0. + */ + public long offset() { + return offset; + } + + /** + * The start offset that should be used when creating the HTTP GET request's Range header. Defaults to 0. + */ + public HTTPGetterInfo offset(long offset) { + this.offset = offset; + return this; + } + + /** + * The count of bytes that should be used to calculate the end offset when creating the HTTP GET request's Range + * header. {@code} null is the default and indicates that the entire rest of the blob should be retrieved. + */ + public Long count() { + return count; + } + + /** + * The count of bytes that should be used to calculate the end offset when creating the HTTP GET request's Range + * header. {@code} null is the default and indicates that the entire rest of the blob should be retrieved. + */ + public HTTPGetterInfo count(Long count) { + if (count != null) { + Utility.assertInBounds("count", count, 0, Long.MAX_VALUE); + } + this.count = count; + return this; + } + + /** + * The resource's etag that should be used when creating the HTTP GET request's If-Match header. Note that the + * Etag is returned with any operation that modifies the resource and by a call to {@link + * BlobClient#getProperties(BlobAccessConditions, Duration)}. Defaults to null. + */ + public String eTag() { + return eTag; + } + + /** + * The resource's etag that should be used when creating the HTTP GET request's If-Match header. Note that the + * Etag is returned with any operation that modifies the resource and by a call to {@link + * BlobClient#getProperties(BlobAccessConditions, Duration)}. Defaults to null. + */ + public HTTPGetterInfo eTag(String eTag) { + this.eTag = eTag; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/IPRange.java b/storage/client/blob/src/main/java/com/azure/storage/blob/IPRange.java new file mode 100644 index 0000000000000..24665c7aaedda --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/IPRange.java @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +/** + * This type specifies a continuous range of IP addresses. It is used to limit permissions on SAS tokens. Null may be + * set if it is not desired to confine the sas permissions to an IP range. Please refer to + * {@link AccountSASSignatureValues} or {@link ServiceSASSignatureValues} for more information. + */ +final class IPRange { + + private String ipMin; + + private String ipMax; + + IPRange() { + } + + /** + * Creates a {@code IPRange} from the specified string. + * + * @param rangeStr + * The {@code String} representation of the {@code IPRange}. + * + * @return The {@code IPRange} generated from the {@code String}. + */ + public static IPRange parse(String rangeStr) { + String[] addrs = rangeStr.split("-"); + IPRange range = new IPRange(); + range.ipMin = addrs[0]; + if (addrs.length > 1) { + range.ipMax = addrs[1]; + } + return range; + } + + /** + * The minimum IP address of the range. + */ + public String ipMin() { + return ipMin; + } + + /** + * The minimum IP address of the range. + */ + public IPRange ipMin(String ipMin) { + this.ipMin = ipMin; + return this; + } + + /** + * The maximum IP address of the range. + */ + public String ipMax() { + return ipMax; + } + + /** + * The maximum IP address of the range. + */ + public IPRange ipMax(String ipMax) { + this.ipMax = ipMax; + return this; + } + + /** + * Output the single IP address or range of IP addresses for. + * + * @return The single IP address or range of IP addresses formatted as a {@code String}. + */ + @Override + public String toString() { + if (this.ipMin == null) { + return ""; + } + this.ipMax = this.ipMax == null ? this.ipMin : this.ipMax; + StringBuilder str = new StringBuilder(this.ipMin); + if (!this.ipMin.equals(this.ipMax)) { + str.append('-'); + str.append(this.ipMax); + } + + return str.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/IProgressReceiver.java b/storage/client/blob/src/main/java/com/azure/storage/blob/IProgressReceiver.java new file mode 100644 index 0000000000000..ab336e1862892 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/IProgressReceiver.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +/** + * An {@code IProgressReceiver} is an object that can be used to report progress on network transfers. When specified on + * transfer operations, the {@code reportProgress} method will be called periodically with the total number of bytes + * transferred. The user may configure this method to report progress in whatever format desired. It is recommended + * that this type be used in conjunction with + * {@link ProgressReporter#addProgressReporting(reactor.core.publisher.Flux, IProgressReceiver)}. + */ +interface IProgressReceiver { + + /** + * The callback function invoked as progress is reported. + * + * @param bytesTransferred + * The total number of bytes transferred during this transaction. + */ + void reportProgress(long bytesTransferred); +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java new file mode 100644 index 0000000000000..073df29744582 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncClient.java @@ -0,0 +1,466 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.CopyStatusType; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PageBlobAccessConditions; +import com.azure.storage.blob.models.PageBlobItem; +import com.azure.storage.blob.models.PageRange; +import com.azure.storage.blob.models.SequenceNumberActionType; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.Unpooled; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.nio.ByteBuffer; + +/** + * Client to a page blob. It may only be instantiated through a {@link PageBlobClientBuilder}, via + * the method {@link BlobAsyncClient#asPageBlobAsyncClient()}, or via the method + * {@link ContainerAsyncClient#getPageBlobAsyncClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient}, + * and operations on the service are available on {@link StorageAsyncClient}. + * + *

    + * Please refer + * to the Azure Docs + * for more information. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public final class PageBlobAsyncClient extends BlobAsyncClient { + + final PageBlobAsyncRawClient pageBlobAsyncRawClient; + + /** + * Indicates the number of bytes in a page. + */ + public static final int PAGE_BYTES = 512; + + /** + * Indicates the maximum number of bytes that may be sent in a call to putPage. + */ + public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB; + + /** + * Package-private constructor for use by {@link PageBlobClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + PageBlobAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder, String snapshot) { + super(azureBlobStorageBuilder, snapshot); + this.pageBlobAsyncRawClient = new PageBlobAsyncRawClient(azureBlobStorageBuilder.build(), snapshot); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * + * @return + * A reactive response containing the information of the created page blob. + */ + public Mono> create(long size) { + return this.create(size, null, null, null, null); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * @param sequenceNumber + * A user-controlled value that you can use to track requests. The value of the sequence number must be + * between 0 and 2^63 - 1.The default value is 0. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response containing the information of the created page blob. + */ + public Mono> create(long size, Long sequenceNumber, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions) { + return pageBlobAsyncRawClient + .create(size, sequenceNumber, headers, metadata, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset must + * be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges are + * 0-511, 512-1023, etc. + * @param body + * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * + * @return + * A reactive response containing the information of the uploaded pages. + */ + public Mono> uploadPages(PageRange pageRange, Flux body) { + return this.uploadPages(pageRange, body, null); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param body + * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * + * @return + * A reactive response containing the information of the uploaded pages. + */ + public Mono> uploadPages(PageRange pageRange, Flux body, + PageBlobAccessConditions pageBlobAccessConditions) { + return pageBlobAsyncRawClient + .uploadPages(pageRange, body.map(Unpooled::wrappedBuffer), pageBlobAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source page blob. + * + * @return + * A reactive response containing the information of the uploaded pages. + */ + public Mono> uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset) { + return this.uploadPagesFromURL(range, sourceURL, sourceOffset, null, null, + null); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source blob. + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions + * {@link PageBlobAccessConditions} + * @param sourceAccessConditions + * {@link SourceModifiedAccessConditions} + * + * @return + * A reactive response containing the information of the uploaded pages. + */ + public Mono> uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset, + byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions) { + + return pageBlobAsyncRawClient + .uploadPagesFromURL(range, sourceURL, sourceOffset, sourceContentMD5, destAccessConditions, sourceAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * + * @return + * A reactive response containing the information of the cleared pages. + */ + public Mono> clearPages(PageRange pageRange) { + return this.clearPages(pageRange, null); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * + * @return + * A reactive response containing the information of the cleared pages. + */ + public Mono> clearPages(PageRange pageRange, + PageBlobAccessConditions pageBlobAccessConditions) { + return pageBlobAsyncRawClient + .clearPages(pageRange, pageBlobAccessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * + * @return + * A reactive response containing the information of the cleared pages. + */ + public Flux getPageRanges(BlobRange blobRange) { + return this.getPageRanges(blobRange, null); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response emitting all the page ranges. + */ + public Flux getPageRanges(BlobRange blobRange, + BlobAccessConditions accessConditions) { + return pageBlobAsyncRawClient + .getPageRanges(blobRange, accessConditions) + .flatMapMany(response -> Flux.fromIterable(response.value().pageRange())); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * + * @return + * A reactive response emitting all the different page ranges. + */ + public Flux getPageRangesDiff(BlobRange blobRange, String prevSnapshot) { + return this.getPageRangesDiff(blobRange, prevSnapshot, null); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response emitting all the different page ranges. + */ + public Flux getPageRangesDiff(BlobRange blobRange, String prevSnapshot, + BlobAccessConditions accessConditions) { + return pageBlobAsyncRawClient + .getPageRangesDiff(blobRange, prevSnapshot, accessConditions) + .flatMapMany(response -> Flux.fromIterable(response.value().pageRange())); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * + * @return + * A reactive response emitting the resized page blob. + */ + public Mono> resize(long size) { + return this.resize(size, null); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response emitting the resized page blob. + */ + public Mono> resize(long size, BlobAccessConditions accessConditions) { + return pageBlobAsyncRawClient + .resize(size, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * + * @return + * A reactive response emitting the updated page blob. + */ + public Mono> updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber) { + return this.updateSequenceNumber(action, sequenceNumber, null); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return + * A reactive response emitting the updated page blob. + */ + public Mono> updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber, BlobAccessConditions accessConditions) { + return pageBlobAsyncRawClient + .updateSequenceNumber(action, sequenceNumber, accessConditions) + .map(rb -> new SimpleResponse<>(rb, new PageBlobItem(rb.deserializedHeaders()))); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * + * @return + * A reactive response emitting the copy status. + */ + public Mono> copyIncremental(URL source, String snapshot) { + return this.copyIncremental(source, snapshot, null); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return + * A reactive response emitting the copy status. + */ + public Mono> copyIncremental(URL source, String snapshot, + ModifiedAccessConditions modifiedAccessConditions) { + return pageBlobAsyncRawClient + .copyIncremental(source, snapshot, modifiedAccessConditions) + .map(rb -> new SimpleResponse<>(rb, rb.deserializedHeaders().copyStatus())); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java new file mode 100644 index 0000000000000..fba55bd8d7455 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobAsyncRawClient.java @@ -0,0 +1,620 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.implementation.http.UrlBuilder; +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PageBlobAccessConditions; +import com.azure.storage.blob.models.PageBlobsClearPagesResponse; +import com.azure.storage.blob.models.PageBlobsCopyIncrementalResponse; +import com.azure.storage.blob.models.PageBlobsCreateResponse; +import com.azure.storage.blob.models.PageBlobsGetPageRangesDiffResponse; +import com.azure.storage.blob.models.PageBlobsGetPageRangesResponse; +import com.azure.storage.blob.models.PageBlobsResizeResponse; +import com.azure.storage.blob.models.PageBlobsUpdateSequenceNumberResponse; +import com.azure.storage.blob.models.PageBlobsUploadPagesFromURLResponse; +import com.azure.storage.blob.models.PageBlobsUploadPagesResponse; +import com.azure.storage.blob.models.PageRange; +import com.azure.storage.blob.models.SequenceNumberActionType; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; + +import static com.azure.storage.blob.Utility.postProcessResponse; + +/** + * Represents a URL to a page blob. It may be obtained by direct construction or via the create method on a + * {@link ContainerAsyncClient} object. This class does not hold any state about a particular blob but is instead a convenient + * way of sending off appropriate requests to the resource on the service. Please refer to the + * Azure Docs + * for more information. + */ +final class PageBlobAsyncRawClient extends BlobAsyncRawClient { + + /** + * Indicates the number of bytes in a page. + */ + public static final int PAGE_BYTES = 512; + + /** + * Indicates the maximum number of bytes that may be sent in a call to putPage. + */ + public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB; + + /** + * Creates a {@code PageBlobAsyncRawClient} object pointing to the account specified by the URL and using the provided + * pipeline to make HTTP requests. + * + */ + PageBlobAsyncRawClient(AzureBlobStorageImpl azureBlobStorage, String snapshot) { + super(azureBlobStorage, snapshot); + } + + private static String pageRangeToString(PageRange pageRange) { + if (pageRange.start() < 0 || pageRange.end() <= 0) { + throw new IllegalArgumentException("PageRange's start and end values must be greater than or equal to " + + "0 if specified."); + } + if (pageRange.start() % PageBlobAsyncRawClient.PAGE_BYTES != 0) { + throw new IllegalArgumentException("PageRange's start value must be a multiple of 512."); + } + if (pageRange.end() % PageBlobAsyncRawClient.PAGE_BYTES != PageBlobAsyncRawClient.PAGE_BYTES - 1) { + throw new IllegalArgumentException("PageRange's end value must be 1 less than a multiple of 512."); + } + if (pageRange.end() <= pageRange.start()) { + throw new IllegalArgumentException("PageRange's End value must be after the start."); + } + return new StringBuilder("bytes=").append(pageRange.start()).append('-').append(pageRange.end()).toString(); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create(long size) { + return this.create(size, null, null, null, null); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * @param sequenceNumber + * A user-controlled value that you can use to track requests. The value of the sequence number must be + * between 0 and 2^63 - 1.The default value is 0. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncRawClient#PAGE_BYTES} + * or {@code sequenceNumber} isn't null and is less than 0. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.create")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono create(long size, Long sequenceNumber, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions) { + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + if (size % PageBlobAsyncRawClient.PAGE_BYTES != 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncRawClient.PAGE_BYTES."); + } + if (sequenceNumber != null && sequenceNumber < 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); + } + metadata = metadata == null ? new Metadata() : metadata; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().createWithRestResponseAsync(null, + null, 0, size, null, metadata, null, null, + null, sequenceNumber, null, headers, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset must + * be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges are + * 0-511, 512-1023, etc. + * @param body + * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.uploadPages")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono uploadPages(PageRange pageRange, Flux body) { + return this.uploadPages(pageRange, body, null); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param body + * The data to upload. Note that this {@code Flux} must be replayable if retries are enabled + * (the default). In other words, the Flowable must produce the same data each time it is subscribed to. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code pageRange} is {@code null} + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.uploadPages")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono uploadPages(PageRange pageRange, Flux body, + PageBlobAccessConditions pageBlobAccessConditions) { + pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() + : pageBlobAccessConditions; + + if (pageRange == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("pageRange cannot be null."); + } + String pageRangeStr = pageRangeToString(pageRange); + + return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesWithRestResponseAsync(null, + null, body, pageRange.end() - pageRange.start() + 1, null, + null, pageRangeStr, null, null, null, null, + pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), + pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source page blob. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_from_url "Sample code for PageBlobAsyncRawClient.uploadPagesFromURL")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset) { + return this.uploadPagesFromURL(range, sourceURL, sourceOffset, null, null, + null); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source blob. + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions + * {@link PageBlobAccessConditions} + * @param sourceAccessConditions + * {@link SourceModifiedAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code range} is {@code null} + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_from_url "Sample code for PageBlobAsyncRawClient.uploadPagesFromURL")] + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset, + byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions) { + + if (range == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("range cannot be null."); + } + + String rangeString = pageRangeToString(range); + + if (sourceOffset == null) { + sourceOffset = 0L; + } + + String sourceRangeString = pageRangeToString(new PageRange().start(sourceOffset).end(sourceOffset + (range.end() - range.start()))); + + destAccessConditions = destAccessConditions == null ? new PageBlobAccessConditions() : destAccessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().uploadPagesFromURLWithRestResponseAsync( + null, null, sourceURL, sourceRangeString, 0, rangeString, sourceContentMD5, + null, null, destAccessConditions.leaseAccessConditions(), + destAccessConditions.sequenceNumberAccessConditions(), destAccessConditions.modifiedAccessConditions(), + sourceAccessConditions, Context.NONE)); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.clearPages")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono clearPages(PageRange pageRange) { + return this.clearPages(pageRange, null); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code pageRange} is {@code null} + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.clearPages")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono clearPages(PageRange pageRange, + PageBlobAccessConditions pageBlobAccessConditions) { + pageBlobAccessConditions = pageBlobAccessConditions == null ? new PageBlobAccessConditions() + : pageBlobAccessConditions; + if (pageRange == null) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("pageRange cannot be null."); + } + String pageRangeStr = pageRangeToString(pageRange); + + return postProcessResponse(this.azureBlobStorage.pageBlobs().clearPagesWithRestResponseAsync(null, + null, 0, null, pageRangeStr, null, + pageBlobAccessConditions.leaseAccessConditions(), pageBlobAccessConditions.sequenceNumberAccessConditions(), + pageBlobAccessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.getPageRanges")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getPageRanges(BlobRange blobRange) { + return this.getPageRanges(blobRange, null); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.getPageRanges")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getPageRanges(BlobRange blobRange, + BlobAccessConditions accessConditions) { + blobRange = blobRange == null ? new BlobRange(0) : blobRange; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesWithRestResponseAsync( + null, null, snapshot, null, null, blobRange.toHeaderValue(), + null, accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), + Context.NONE)); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_diff "Sample code for PageBlobAsyncRawClient.getPageRangesDiff")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getPageRangesDiff(BlobRange blobRange, String prevSnapshot) { + return this.getPageRangesDiff(blobRange, prevSnapshot, null); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code prevSnapshot} is {@code null} + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_diff "Sample code for PageBlobAsyncRawClient.getPageRangesDiff")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getPageRangesDiff(BlobRange blobRange, String prevSnapshot, + BlobAccessConditions accessConditions) { + blobRange = blobRange == null ? new BlobRange(0) : blobRange; + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + if (prevSnapshot == null) { + throw new IllegalArgumentException("prevSnapshot cannot be null"); + } + + return postProcessResponse(this.azureBlobStorage.pageBlobs().getPageRangesDiffWithRestResponseAsync( + null, null, snapshot, null, null, prevSnapshot, + blobRange.toHeaderValue(), null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.resize")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono resize(long size) { + return this.resize(size, null); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code size} isn't a multiple of {@link PageBlobAsyncRawClient#PAGE_BYTES} + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.resize")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono resize(long size, BlobAccessConditions accessConditions) { + if (size % PageBlobAsyncRawClient.PAGE_BYTES != 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("size must be a multiple of PageBlobAsyncRawClient.PAGE_BYTES."); + } + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + + return postProcessResponse(this.azureBlobStorage.pageBlobs().resizeWithRestResponseAsync(null, + null, size, null, null, accessConditions.leaseAccessConditions(), + accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.updateSequenceNumber")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber) { + return this.updateSequenceNumber(action, sequenceNumber, null); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * @param accessConditions + * {@link BlobAccessConditions} + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code sequenceNumber} isn't null and is less than 0 + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=page_blob_basic "Sample code for PageBlobAsyncRawClient.updateSequenceNumber")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber, BlobAccessConditions accessConditions) { + if (sequenceNumber != null && sequenceNumber < 0) { + // Throwing is preferred to Single.error because this will error out immediately instead of waiting until + // subscription. + throw new IllegalArgumentException("SequenceNumber must be greater than or equal to 0."); + } + accessConditions = accessConditions == null ? new BlobAccessConditions() : accessConditions; + sequenceNumber = action == SequenceNumberActionType.INCREMENT ? null : sequenceNumber; + + return postProcessResponse( + this.azureBlobStorage.pageBlobs().updateSequenceNumberWithRestResponseAsync(null, + null, action, null, sequenceNumber, null, + accessConditions.leaseAccessConditions(), accessConditions.modifiedAccessConditions(), Context.NONE)); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * + * @return Emits the successful response. + */ + public Mono copyIncremental(URL source, String snapshot) { + return this.copyIncremental(source, snapshot, null); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return Emits the successful response. + * @throws Error If {@code source} and {@code snapshot} form a malformed URL. + */ + public Mono copyIncremental(URL source, String snapshot, + ModifiedAccessConditions modifiedAccessConditions) { + + UrlBuilder builder = UrlBuilder.parse(source); + builder.setQueryParameter(Constants.SNAPSHOT_QUERY_PARAMETER, snapshot); + try { + source = builder.toURL(); + } catch (MalformedURLException e) { + // We are parsing a valid url and adding a query parameter. If this fails, we can't recover. + throw new Error(e); + } + return postProcessResponse(this.azureBlobStorage.pageBlobs().copyIncrementalWithRestResponseAsync( + null, null, source, null, null, modifiedAccessConditions, Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java new file mode 100644 index 0000000000000..284f74d0216ac --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClient.java @@ -0,0 +1,515 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.rest.Response; +import com.azure.storage.blob.models.BlobAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobRange; +import com.azure.storage.blob.models.CopyStatusType; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PageBlobAccessConditions; +import com.azure.storage.blob.models.PageBlobItem; +import com.azure.storage.blob.models.PageRange; +import com.azure.storage.blob.models.SequenceNumberActionType; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + +import java.io.InputStream; +import java.net.URL; +import java.nio.ByteBuffer; +import java.time.Duration; + +/** + * Client to a page blob. It may only be instantiated through a {@link PageBlobClientBuilder}, via + * the method {@link BlobClient#asPageBlobClient()}, or via the method + * {@link ContainerClient#getPageBlobClient(String)}. This class does not hold + * any state about a particular blob, but is instead a convenient way of sending appropriate + * requests to the resource on the service. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient}, + * and operations on the service are available on {@link StorageClient}. + * + *

    + * Please refer to the Azure Docs + * for more information. + */ +public final class PageBlobClient extends BlobClient { + private final PageBlobAsyncClient pageBlobAsyncClient; + + /** + * Indicates the number of bytes in a page. + */ + public static final int PAGE_BYTES = 512; + + /** + * Indicates the maximum number of bytes that may be sent in a call to putPage. + */ + public static final int MAX_PUT_PAGES_BYTES = 4 * Constants.MB; + + /** + * Package-private constructor for use by {@link PageBlobClientBuilder}. + * @param pageBlobAsyncClient the async page blob client + */ + PageBlobClient(PageBlobAsyncClient pageBlobAsyncClient) { + super(pageBlobAsyncClient); + this.pageBlobAsyncClient = pageBlobAsyncClient; + } + + /** + * Creates and opens an output stream to write data to the page blob. If the blob already exists on the service, + * it will be overwritten. + * + * @param length + * A long which represents the length, in bytes, of the stream to create. This value must be + * a multiple of 512. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream(long length) { + return getBlobOutputStream(length, null); + } + + /** + * Creates and opens an output stream to write data to the page blob. If the blob already exists on the service, + * it will be overwritten. + * + * @param length + * A long which represents the length, in bytes, of the stream to create. This value must be + * a multiple of 512. + * @param accessConditions + * A {@link BlobAccessConditions} object that represents the access conditions for the blob. + * + * @return A {@link BlobOutputStream} object used to write data to the blob. + * + * @throws StorageException + * If a storage service error occurred. + */ + public BlobOutputStream getBlobOutputStream(long length, BlobAccessConditions accessConditions) { + return new BlobOutputStream(pageBlobAsyncClient, length, accessConditions); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * + * @return + * The information of the created page blob. + */ + public Response create(long size) { + return this.create(size, null, null, null, null, null); + } + + /** + * Creates a page blob of the specified length. Call PutPage to upload data data to a page blob. + * For more information, see the + * Azure Docs. + * + * @param size + * Specifies the maximum size for the page blob, up to 8 TB. The page blob size must be aligned to a + * 512-byte boundary. + * @param sequenceNumber + * A user-controlled value that you can use to track requests. The value of the sequence number must be + * between 0 and 2^63 - 1.The default value is 0. + * @param headers + * {@link BlobHTTPHeaders} + * @param metadata + * {@link Metadata} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the created page blob. + */ + public Response create(long size, Long sequenceNumber, BlobHTTPHeaders headers, + Metadata metadata, BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = pageBlobAsyncClient.create(size, sequenceNumber, headers, metadata, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset must + * be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges are + * 0-511, 512-1023, etc. + * @param body + * The data to upload. + * + * @return + * The information of the uploaded pages. + */ + public Response uploadPages(PageRange pageRange, InputStream body) { + return this.uploadPages(pageRange, body, null, null); + } + + /** + * Writes 1 or more pages to the page blob. The start and end offsets must be a multiple of 512. + * For more information, see the + * Azure Docs. + *

    + * Note that the data passed must be replayable if retries are enabled (the default). In other words, the + * {@code Flux} must produce the same data each time it is subscribed to. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param body + * The data to upload. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the uploaded pages. + */ + public Response uploadPages(PageRange pageRange, InputStream body, + PageBlobAccessConditions pageBlobAccessConditions, Duration timeout) { + long length = pageRange.end() - pageRange.start(); + Flux fbb = Flux.range(0, (int) Math.ceil((double) length / (double) PAGE_BYTES)) + .map(i -> i * PAGE_BYTES) + .concatMap(pos -> Mono.fromCallable(() -> { + byte[] cache = new byte[PAGE_BYTES]; + int read = 0; + while (read < PAGE_BYTES) { + read += body.read(cache, read, PAGE_BYTES - read); + } + return ByteBuffer.wrap(cache); + })); + + Mono> response = pageBlobAsyncClient.uploadPages(pageRange, + fbb.subscribeOn(Schedulers.elastic()), + pageBlobAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source page blob. + * + * @return + * The information of the uploaded pages. + */ + public Response uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset) { + return this.uploadPagesFromURL(range, sourceURL, sourceOffset, null, null, + null, null); + } + + /** + * Writes 1 or more pages from the source page blob to this page blob. The start and end offsets must be a multiple + * of 512. + * For more information, see the + * Azure Docs. + *

    + * + * @param range + * The destination {@link PageRange} range. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param sourceURL + * The url to the blob that will be the source of the copy. A source blob in the same storage account can be + * authenticated via Shared Key. However, if the source is a blob in another account, the source blob must + * either be public or must be authenticated via a shared access signature. If the source blob is public, no + * authentication is required to perform the operation. + * @param sourceOffset + * The source offset to copy from. Pass null or 0 to copy from the beginning of source blob. + * @param sourceContentMD5 + * An MD5 hash of the block content from the source blob. If specified, the service will calculate the MD5 + * of the received data and fail the request if it does not match the provided MD5. + * @param destAccessConditions + * {@link PageBlobAccessConditions} + * @param sourceAccessConditions + * {@link SourceModifiedAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The information of the uploaded pages. + */ + public Response uploadPagesFromURL(PageRange range, URL sourceURL, Long sourceOffset, + byte[] sourceContentMD5, PageBlobAccessConditions destAccessConditions, + SourceModifiedAccessConditions sourceAccessConditions, Duration timeout) { + + Mono> response = pageBlobAsyncClient.uploadPagesFromURL(range, sourceURL, sourceOffset, sourceContentMD5, destAccessConditions, sourceAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * + * @return + * The information of the cleared pages. + */ + public Response clearPages(PageRange pageRange) { + return this.clearPages(pageRange, null, null); + } + + /** + * Frees the specified pages from the page blob. + * For more information, see the + * Azure Docs. + * + * @param pageRange + * A {@link PageRange} object. Given that pages must be aligned with 512-byte boundaries, the start offset + * must be a modulus of 512 and the end offset must be a modulus of 512 - 1. Examples of valid byte ranges + * are 0-511, 512-1023, etc. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * @param pageBlobAccessConditions + * {@link PageBlobAccessConditions} + * + * @return + * The information of the cleared pages. + */ + public Response clearPages(PageRange pageRange, + PageBlobAccessConditions pageBlobAccessConditions, Duration timeout) { + Mono> response = pageBlobAsyncClient.clearPages(pageRange, pageBlobAccessConditions); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * + * @return + * The information of the cleared pages. + */ + public Iterable getPageRanges(BlobRange blobRange) { + return this.getPageRanges(blobRange, null, null); + } + + /** + * Returns the list of valid page ranges for a page blob or snapshot of a page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * All the page ranges. + */ + public Iterable getPageRanges(BlobRange blobRange, + BlobAccessConditions accessConditions, Duration timeout) { + Flux response = pageBlobAsyncClient.getPageRanges(blobRange, accessConditions); + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * + * @return + * All the different page ranges. + */ + public Iterable getPageRangesDiff(BlobRange blobRange, String prevSnapshot) { + return this.getPageRangesDiff(blobRange, prevSnapshot, null, null); + } + + /** + * Gets the collection of page ranges that differ between a specified snapshot and this page blob. + * For more information, see the Azure Docs. + * + * @param blobRange + * {@link BlobRange} + * @param prevSnapshot + * Specifies that the response will contain only pages that were changed between target blob and previous + * snapshot. Changed pages include both updated and cleared pages. The target + * blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * All the different page ranges. + */ + public Iterable getPageRangesDiff(BlobRange blobRange, String prevSnapshot, + BlobAccessConditions accessConditions, Duration timeout) { + Flux response = pageBlobAsyncClient.getPageRangesDiff(blobRange, prevSnapshot, accessConditions); + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * + * @return + * The resized page blob. + */ + public Response resize(long size) { + return this.resize(size, null, null); + } + + /** + * Resizes the page blob to the specified size (which must be a multiple of 512). + * For more information, see the Azure Docs. + * + * @param size + * Resizes a page blob to the specified size. If the specified value is less than the current size of the + * blob, then all pages above the specified value are cleared. + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The resized page blob. + */ + public Response resize(long size, BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = pageBlobAsyncClient.resize(size, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * + * @return + * The updated page blob. + */ + public Response updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber) { + return this.updateSequenceNumber(action, sequenceNumber, null, null); + } + + /** + * Sets the page blob's sequence number. + * For more information, see the Azure Docs. + * + * @param action + * Indicates how the service should modify the blob's sequence number. + * @param sequenceNumber + * The blob's sequence number. The sequence number is a user-controlled property that you can use to track + * requests and manage concurrency issues. + * @param accessConditions + * {@link BlobAccessConditions} + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The updated page blob. + */ + public Response updateSequenceNumber(SequenceNumberActionType action, + Long sequenceNumber, BlobAccessConditions accessConditions, Duration timeout) { + Mono> response = pageBlobAsyncClient.updateSequenceNumber(action, sequenceNumber, accessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * + * @return + * The copy status. + */ + public Response copyIncremental(URL source, String snapshot) { + return this.copyIncremental(source, snapshot, null, null); + } + + /** + * Begins an operation to start an incremental copy from one page blob's snapshot to this page + * blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are + * transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read + * or copied from as usual. For more information, see + * the Azure Docs here and + * here. + * + * @param source + * The source page blob. + * @param snapshot + * The snapshot on the copy source. + * @param modifiedAccessConditions + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used + * to construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The copy status. + */ + public Response copyIncremental(URL source, String snapshot, + ModifiedAccessConditions modifiedAccessConditions, Duration timeout) { + Mono> response = pageBlobAsyncClient.copyIncremental(source, snapshot, modifiedAccessConditions); + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClientBuilder.java new file mode 100644 index 0000000000000..77010e0607f84 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/PageBlobClientBuilder.java @@ -0,0 +1,333 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent PageBlobClientBuilder for instantiating a {@link PageBlobClient} or {@link PageBlobAsyncClient} + * using {@link PageBlobClientBuilder#buildClient()} or {@link PageBlobClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, including the container name and blob name, in the format of {@code https://{accountName}.blob.core.windows.net/{containerName}/{blobName}}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link PageBlobClient} or {@code .buildAsyncClient()} to create a {@link PageBlobAsyncClient}. + */ +public final class PageBlobClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private String containerName; + private String blobName; + private String snapshot; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link PageBlobClient PageBlobClients} + * and {@link PageBlobAsyncClient PageBlobAsyncClients}. + */ + public PageBlobClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + Objects.requireNonNull(containerName); + Objects.requireNonNull(blobName); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(String.format("%s/%s/%s", endpoint, containerName, blobName)) + .pipeline(pipeline); + } + + /** + * @return a {@link PageBlobClient} created from the configurations in this builder. + */ + public PageBlobClient buildClient() { + return new PageBlobClient(buildAsyncClient()); + } + + /** + * @return a {@link PageBlobAsyncClient} created from the configurations in this builder. + */ + public PageBlobAsyncClient buildAsyncClient() { + return new PageBlobAsyncClient(buildImpl(), snapshot); + } + + /** + * Sets the service endpoint, additionally parses it for information (SAS token, container name, blob name) + * @param endpoint URL of the service + * @return the updated PageBlobClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL. + */ + public PageBlobClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + BlobURLParts parts = URLParser.parse(url); + this.endpoint = parts.scheme() + "://" + parts.host(); + + if (parts.containerName() != null) { + this.containerName = parts.containerName(); + } + + if (parts.blobName() != null) { + this.blobName = parts.blobName(); + } + + if (parts.snapshot() != null) { + this.snapshot = parts.snapshot(); + } + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage Blob endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + /** + * Sets the name of the container this client is connecting to. + * @param containerName the name of the container + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Sets the name of the blob this client is connecting to. + * @param blobName the name of the blob + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * Sets the snapshot of the blob this client is connecting to. + * @param snapshot the snapshot identifier for the blob + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated PageBlobClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey + */ + public PageBlobClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated PageBlobClientBuilder object + */ + public PageBlobClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ProgressReporter.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ProgressReporter.java new file mode 100644 index 0000000000000..fc882d4c30aa4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ProgressReporter.java @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; + +/** + * {@code ProgressReporterImpl} offers a convenient way to add progress tracking to a given Flowable. + */ +final class ProgressReporter { + + private abstract static class ProgressReporterImpl implements IProgressReceiver { + long blockProgress; + + final IProgressReceiver progressReceiver; + + ProgressReporterImpl(IProgressReceiver progressReceiver) { + this.blockProgress = 0; + this.progressReceiver = progressReceiver; + } + + @Override + public void reportProgress(long bytesTransferred) { + this.blockProgress += bytesTransferred; + } + + void rewindProgress() { + this.blockProgress = 0; + } + + Flux addProgressReporting(Flux data) { + return Mono.just(this) + .flatMapMany(progressReporter -> { + /* + Each time there is a new subscription, we will rewind the progress. This is desirable specifically + for retries, which resubscribe on each try. The first time this flowable is subscribed to, the + rewind will be a noop as there will have been no progress made. Subsequent rewinds will work as + expected. + */ + progressReporter.rewindProgress(); + /* + Every time we emit some data, report it to the Tracker, which will pass it on to the end user. + */ + return data.doOnNext(buffer -> + progressReporter.reportProgress(buffer.remaining())); + }); + } + } + + /** + * This type is used to keep track of the total amount of data transferred for a single request. This is the type + * we will use when the customer uses the factory to add progress reporting to their Flowable. We need this + * additional type because we can't keep local state directly as lambdas require captured local variables to be + * effectively final. + */ + private static class SequentialProgressReporter extends ProgressReporterImpl { + SequentialProgressReporter(IProgressReceiver progressReceiver) { + super(progressReceiver); + } + + @Override + public void reportProgress(long bytesTransferred) { + super.reportProgress(bytesTransferred); + this.progressReceiver.reportProgress(this.blockProgress); + } + } + + /** + * This type is used to keep track of the total amount of data transferred as a part of a parallel upload in order + * to coordinate progress reporting to the end user. We need this additional type because we can't keep local state + * directly as lambdas require captured local variables to be effectively final. + */ + private static class ParallelProgressReporter extends ProgressReporterImpl { + /* + This lock will be instantiated by the operation initiating the whole transfer to coordinate each + ProgressReporterImpl. + */ + private final Lock transferLock; + + /* + We need an AtomicLong to be able to update the value referenced. Because we are already synchronizing with the + lock, we don't incur any additional performance hit here by the synchronization. + */ + private AtomicLong totalProgress; + + ParallelProgressReporter(IProgressReceiver progressReceiver, Lock lock, AtomicLong totalProgress) { + super(progressReceiver); + this.transferLock = lock; + this.totalProgress = totalProgress; + } + + @Override + public void reportProgress(long bytesTransferred) { + super.reportProgress(bytesTransferred); + + /* + It is typically a bad idea to lock around customer code (which the progressReceiver is) because they could + never release the lock. However, we have decided that it is sufficiently difficult for them to make their + progressReporting code threadsafe that we will take that burden and the ensuing risks. Although it is the + case that only one thread is allowed to be in onNext at once, however there are multiple independent + requests happening at once to stage/download separate chunks, so we still need to lock either way. + */ + transferLock.lock(); + this.progressReceiver.reportProgress(this.totalProgress.addAndGet(bytesTransferred)); + transferLock.unlock(); + } + + /* + This is used in the case of retries to rewind the amount of progress reported so as not to over-report at the + end. + */ + @Override + public void rewindProgress() { + /* + Blocks do not interfere with each other's block progress and there is no way that, for a single block, one + thread will be trying to add to the progress while the other is trying to zero it. The updates are strictly + sequential. Avoiding using the lock is ideal. + */ + this.totalProgress.addAndGet(-1 * this.blockProgress); + super.rewindProgress(); + } + + } + + /** + * Adds progress reporting functionality to the given {@code Flux}. Each subscription (and therefore each + * retry) will rewind the progress reported so as not to over-report. The data reported will be the total amount + * of data emitted so far, or the "current position" of the Flowable. + * + * @param data + * The data whose transfer progress is to be tracked. + * @param progressReceiver + * {@link IProgressReceiver} + * + * @return A {@code Flux} that emits the same data as the source but calls a callback to report the total amount + * of data emitted so far. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=progress "Sample code for ProgressReporterFactor.addProgressReporting")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public static Flux addProgressReporting(Flux data, + IProgressReceiver progressReceiver) { + if (progressReceiver == null) { + return data; + } else { + ProgressReporterImpl tracker = new SequentialProgressReporter(progressReceiver); + return tracker.addProgressReporting(data); + } + } + + static Flux addParallelProgressReporting(Flux data, + IProgressReceiver progressReceiver, Lock lock, AtomicLong totalProgress) { + if (progressReceiver == null) { + return data; + } else { + ParallelProgressReporter tracker = new ParallelProgressReporter(progressReceiver, lock, totalProgress); + return tracker.addProgressReporting(data); + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/SASProtocol.java b/storage/client/blob/src/main/java/com/azure/storage/blob/SASProtocol.java new file mode 100644 index 0000000000000..64df03714ecb5 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/SASProtocol.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.util.Locale; + +/** + * Specifies the set of possible permissions for a shared access signature protocol. Values of this type can be used + * to set the fields on the {@link AccountSASSignatureValues} and {@link ServiceSASSignatureValues} types. + */ +enum SASProtocol { + /** + * Permission to use SAS only through https granted. + */ + HTTPS_ONLY(Constants.HTTPS), + + /** + * Permission to use SAS only through https or http granted. + */ + HTTPS_HTTP(Constants.HTTPS_HTTP); + + private final String protocols; + + SASProtocol(String p) { + this.protocols = p; + } + + /** + * Parses a {@code String} into a {@code SASProtocl} value if possible. + * + * @param str + * The value to try to parse. + * + * @return A {@code SASProtocol} value that represents the string if possible. + * @throws IllegalArgumentException If {@code str} doesn't equal "https" or "https,http" + */ + public static SASProtocol parse(String str) { + if (str.equals(Constants.HTTPS)) { + return SASProtocol.HTTPS_ONLY; + } else if (str.equals(Constants.HTTPS_HTTP)) { + return SASProtocol.HTTPS_HTTP; + } + throw new IllegalArgumentException(String.format(Locale.ROOT, + "%s could not be parsed into a SASProtocl value.", str)); + } + + @Override + public String toString() { + return this.protocols; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java b/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java new file mode 100644 index 0000000000000..b6afd82addcab --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/SASQueryParameters.java @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.blob.models.UserDelegationKey; + +import java.time.OffsetDateTime; +import java.util.Map; +import java.util.function.Function; + +import static com.azure.storage.blob.Utility.safeURLEncode; + +/** + * Represents the components that make up an Azure Storage SAS' query parameters. This type is not constructed directly + * by the user; it is only generated by the {@link AccountSASSignatureValues} and {@link ServiceSASSignatureValues} + * types. Once generated, it can be set on a {@link BlobURLParts} object to be constructed as part of a URL or it can + * be encoded into a {@code String} and appended to a URL directly (though caution should be taken here in case there + * are existing query parameters, which might affect the appropriate means of appending these query parameters). + * NOTE: Instances of this class are immutable to ensure thread safety. + */ +final class SASQueryParameters { + + private final String version; + + private final String services; + + private final String resourceTypes; + + private final SASProtocol protocol; + + private final OffsetDateTime startTime; + + private final OffsetDateTime expiryTime; + + private final IPRange ipRange; + + private final String identifier; + + private final String keyOid; + + private final String keyTid; + + private final OffsetDateTime keyStart; + + private final OffsetDateTime keyExpiry; + + private final String keyService; + + private final String keyVersion; + + private final String resource; + + private final String permissions; + + private final String signature; + + private final String cacheControl; + + private final String contentDisposition; + + private final String contentEncoding; + + private final String contentLanguage; + + private final String contentType; + + /** + * Creates a new {@link SASQueryParameters} object. + * + * @param queryParamsMap All query parameters for the request as key-value pairs + * @param removeSASParametersFromMap When {@code true}, the SAS query parameters will be removed from queryParamsMap + */ + SASQueryParameters(Map queryParamsMap, boolean removeSASParametersFromMap) { + this.version = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SERVICE_VERSION, removeSASParametersFromMap); + this.services = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SERVICES, removeSASParametersFromMap); + this.resourceTypes = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_RESOURCES_TYPES, removeSASParametersFromMap); + this.protocol = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_PROTOCOL, removeSASParametersFromMap, SASProtocol::parse); + this.startTime = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_START_TIME, removeSASParametersFromMap, Utility::parseDate); + this.expiryTime = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_EXPIRY_TIME, removeSASParametersFromMap, Utility::parseDate); + this.ipRange = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_IP_RANGE, removeSASParametersFromMap, IPRange::parse); + this.identifier = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_IDENTIFIER, removeSASParametersFromMap); + this.keyOid = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_OBJECT_ID, removeSASParametersFromMap); + this.keyTid = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_TENANT_ID, removeSASParametersFromMap); + this.keyStart = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_KEY_START, removeSASParametersFromMap, Utility::parseDate); + this.keyExpiry = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_KEY_EXPIRY, removeSASParametersFromMap, Utility::parseDate); + this.keyService = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_KEY_SERVICE, removeSASParametersFromMap); + this.keyVersion = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_KEY_VERSION, removeSASParametersFromMap); + this.resource = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_RESOURCE, removeSASParametersFromMap); + this.permissions = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNED_PERMISSIONS, removeSASParametersFromMap); + this.signature = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_SIGNATURE, removeSASParametersFromMap); + this.cacheControl = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_CACHE_CONTROL, removeSASParametersFromMap); + this.contentDisposition = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, removeSASParametersFromMap); + this.contentEncoding = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_CONTENT_ENCODING, removeSASParametersFromMap); + this.contentLanguage = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_CONTENT_LANGUAGE, removeSASParametersFromMap); + this.contentType = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_CONTENT_TYPE, removeSASParametersFromMap); + } + + private String getQueryParameter(Map parameters, String name, boolean remove) { + return getQueryParameter(parameters, name, remove, value -> value); + } + + private T getQueryParameter(Map parameters, String name, Boolean remove, Function converter) { + String[] parameterValue = parameters.get(name); + if (parameterValue == null) { + return null; + } + + if (remove) { + parameters.remove(name); + } + + return converter.apply(parameterValue[0]); + } + + + /** + * Creates a new {@link SASQueryParameters} object. These objects are only created internally by + * *SASSignatureValues classes. + * + * @param version + * A {@code String} representing the storage version. + * @param services + * A {@code String} representing the storage services being accessed (only for Account SAS). + * @param resourceTypes + * A {@code String} representing the storage resource types being accessed (only for Account SAS). + * @param protocol + * A {@code String} representing the allowed HTTP protocol(s) or {@code null}. + * @param startTime + * A {@code java.util.Date} representing the start time for this SAS token or {@code null}. + * @param expiryTime + * A {@code java.util.Date} representing the expiry time for this SAS token. + * @param ipRange + * A {@link IPRange} representing the range of valid IP addresses for this SAS token or {@code null}. + * @param identifier + * A {@code String} representing the signed identifier (only for Service SAS) or {@code null}. + * @param resource + * A {@code String} representing the storage container or blob (only for Service SAS). + * @param permissions + * A {@code String} representing the storage permissions or {@code null}. + * @param signature + * A {@code String} representing the signature for the SAS token. + */ + SASQueryParameters(String version, String services, String resourceTypes, SASProtocol protocol, + OffsetDateTime startTime, OffsetDateTime expiryTime, IPRange ipRange, String identifier, + String resource, String permissions, String signature, String cacheControl, String contentDisposition, + String contentEncoding, String contentLanguage, String contentType, UserDelegationKey key) { + + this.version = version; + this.services = services; + this.resourceTypes = resourceTypes; + this.protocol = protocol; + this.startTime = startTime; + this.expiryTime = expiryTime; + this.ipRange = ipRange; + this.identifier = identifier; + this.resource = resource; + this.permissions = permissions; + this.signature = signature; + this.cacheControl = cacheControl; + this.contentDisposition = contentDisposition; + this.contentEncoding = contentEncoding; + this.contentLanguage = contentLanguage; + this.contentType = contentType; + + if (key != null) { + this.keyOid = key.signedOid(); + this.keyTid = key.signedTid(); + this.keyStart = key.signedStart(); + this.keyExpiry = key.signedExpiry(); + this.keyService = key.signedService(); + this.keyVersion = key.signedVersion(); + } else { + this.keyOid = null; + this.keyTid = null; + this.keyStart = null; + this.keyExpiry = null; + this.keyService = null; + this.keyVersion = null; + } + } + + /** + * @return The storage version + */ + public String version() { + return version; + } + + /** + * @return The storage services being accessed (only for Account SAS). Please refer to {@link AccountSASService} for + * more details. + */ + public String services() { + return services; + } + + /** + * @return The storage resource types being accessed (only for Account SAS). Please refer to + * {@link AccountSASResourceType} for more details. + */ + public String resourceTypes() { + return resourceTypes; + } + + /** + * @return The allowed HTTP protocol(s) or {@code null}. Please refer to {@link SASProtocol} for more details. + */ + public SASProtocol protocol() { + return protocol; + } + + /** + * @return The start time for this SAS token or {@code null}. + */ + public OffsetDateTime startTime() { + return startTime; + } + + /** + * @return The expiry time for this SAS token. + */ + public OffsetDateTime expiryTime() { + return expiryTime; + } + + /** + * @return {@link IPRange} + */ + public IPRange ipRange() { + return ipRange; + } + + /** + * @return The signed identifier (only for {@link ServiceSASSignatureValues}) or {@code null}. Please see + * here + * for more information. + */ + public String identifier() { + return identifier; + } + + /** + * @return The storage container or blob (only for {@link ServiceSASSignatureValues}). + */ + public String resource() { + return resource; + } + + /** + * @return Please refer to {@link AccountSASPermission}, {@link BlobSASPermission}, or {@link ContainerSASPermission} + * for more details. + */ + public String permissions() { + return permissions; + } + + /** + * @return The signature for the SAS token. + */ + public String signature() { + return signature; + } + + /** + * @return The Cache-Control header value when a client accesses the resource with this sas token. + */ + public String cacheControl() { + return cacheControl; + } + + /** + * @return The Content-Disposition header value when a client accesses the resource with this sas token. + */ + public String contentDisposition() { + return contentDisposition; + } + + /** + * @return The Content-Encoding header value when a client accesses the resource with this sas token. + */ + public String contentEncoding() { + return contentEncoding; + } + + /** + * @return The Content-Language header value when a client accesses the resource with this sas token. + */ + public String contentLanguage() { + return contentLanguage; + } + + /** + * @return The Content-Type header value when a client accesses the resource with this sas token. + */ + public String contentType() { + return contentType; + } + + public String keyOid() { + return keyOid; + } + + public String keyTid() { + return keyTid; + } + + public OffsetDateTime keyStart() { + return keyStart; + } + + public OffsetDateTime keyExpiry() { + return keyExpiry; + } + + public String keyService() { + return keyService; + } + + public String keyVersion() { + return keyVersion; + } + + UserDelegationKey userDelegationKey() { + return new UserDelegationKey() + .signedExpiry(this.keyExpiry) + .signedOid(this.keyOid) + .signedService(this.keyService) + .signedStart(this.keyStart) + .signedTid(this.keyTid) + .signedVersion(this.keyVersion); + } + + private void tryAppendQueryParameter(StringBuilder sb, String param, Object value) { + if (value != null) { + if (sb.length() == 0) { + sb.append('?'); + } else { + sb.append('&'); + } + sb.append(safeURLEncode(param)).append('=').append(safeURLEncode(value.toString())); + } + } + + private String formatQueryParameterDate(OffsetDateTime dateTime) { + if (dateTime == null) { + return null; + } else { + return Utility.ISO_8601_UTC_DATE_FORMATTER.format(dateTime); + } + } + + /** + * Encodes all SAS query parameters into a string that can be appended to a URL. + * + * @return A {@code String} representing all SAS query parameters. + */ + public String encode() { + /* + We should be url-encoding each key and each value, but because we know all the keys and values will encode to + themselves, we cheat except for the signature value. + */ + StringBuilder sb = new StringBuilder(); + + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SERVICE_VERSION, this.version); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SERVICES, this.services); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_RESOURCES_TYPES, this.resourceTypes); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_PROTOCOL, this.protocol); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_START_TIME, formatQueryParameterDate(this.startTime)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_EXPIRY_TIME, formatQueryParameterDate(this.expiryTime)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_IP_RANGE, this.ipRange); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_IDENTIFIER, this.identifier); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_OBJECT_ID, this.keyOid); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_TENANT_ID, this.keyTid); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_START, formatQueryParameterDate(this.keyStart)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_EXPIRY, formatQueryParameterDate(this.keyExpiry)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_SERVICE, this.keyService); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_VERSION, this.keyVersion); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_RESOURCE, this.resource); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_PERMISSIONS, this.permissions); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, this.signature); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_LANGUAGE, this.contentLanguage); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_TYPE, this.contentType); + + return sb.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/SR.java b/storage/client/blob/src/main/java/com/azure/storage/blob/SR.java new file mode 100644 index 0000000000000..6806fbc87c799 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/SR.java @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +/** + * RESERVED FOR INTERNAL USE. Provides a standard set of errors that could be thrown from the client library. + */ +final class SR { + // TODO: Do we want to keep any of what's left? + public static final String ACCOUNT_NAME_NULL_OR_EMPTY = "The account name is null or empty."; + public static final String ACCOUNT_NAME_MISMATCH = "The account name does not match the existing account name on the credentials."; + public static final String ARGUMENT_NULL_OR_EMPTY = "The argument must not be null or an empty string. Argument name: %s."; + public static final String ARGUMENT_OUT_OF_RANGE_ERROR = "The argument is out of range. Argument name: %s, Value passed: %s."; + public static final String BLOB_OVER_MAX_BLOCK_LIMIT = "The total blocks for this upload exceeds the maximum allowable limit."; + public static final String BLOB_DATA_CORRUPTED = "Blob data corrupted (integrity check failed), Expected value is %s, retrieved %s"; + public static final String BLOB_ENDPOINT_NOT_CONFIGURED = "No blob endpoint configured."; + public static final String BLOB_HASH_MISMATCH = "Blob hash mismatch (integrity check failed), Expected value is %s, retrieved %s."; + public static final String BLOB_MD5_NOT_SUPPORTED_FOR_PAGE_BLOBS = "Blob level MD5 is not supported for page blobs."; + public static final String CANNOT_CREATE_SAS_FOR_GIVEN_CREDENTIALS = "Cannot create Shared Access Signature as the credentials does not have account name information. Please check that the credentials provided support creating Shared Access Signature."; + public static final String CANNOT_CREATE_SAS_WITHOUT_ACCOUNT_KEY = "Cannot create Shared Access Signature unless the Account Key credentials are used by the ServiceClient."; + public static final String CANNOT_TRANSFORM_NON_HTTPS_URI_WITH_HTTPS_ONLY_CREDENTIALS = "Cannot use HTTP with credentials that only support HTTPS."; + public static final String CONTAINER = "container"; + public static final String CONTENT_LENGTH_MISMATCH = "An incorrect number of bytes was read from the connection. The connection may have been closed."; + public static final String CREATING_NETWORK_STREAM = "Creating a NetworkInputStream and expecting to read %s bytes."; + public static final String CREDENTIALS_CANNOT_SIGN_REQUEST = "CloudBlobClient, CloudQueueClient and CloudTableClient require credentials that can sign a request."; + public static final String DEFAULT_SERVICE_VERSION_ONLY_SET_FOR_BLOB_SERVICE = "DefaultServiceVersion can only be set for the Blob service."; + public static final String DELETE_SNAPSHOT_NOT_VALID_ERROR = "The option '%s' must be 'None' to delete a specific snapshot specified by '%s'."; + public static final String ENUMERATION_ERROR = "An error occurred while enumerating the result, check the original exception for details."; + public static final String ENDPOINT_INFORMATION_UNAVAILABLE = "Endpoint information not available for Account using Shared Access Credentials."; + public static final String ETAG_INVALID_FOR_DELETE = "Delete requires a valid ETag (which may be the '*' wildcard)."; + public static final String ETAG_INVALID_FOR_MERGE = "Merge requires a valid ETag (which may be the '*' wildcard)."; + public static final String ETAG_INVALID_FOR_UPDATE = "Replace requires a valid ETag (which may be the '*' wildcard)."; + public static final String ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE = "%s could not be parsed from '%s' due to invalid value %s."; + public static final String INCORRECT_STREAM_LENGTH = "An incorrect stream length was specified, resulting in an authentication failure. Please specify correct length, or -1."; + public static final String INPUT_STREAM_SHOULD_BE_MARKABLE = "Input stream must be markable."; + public static final String INVALID_ACCOUNT_NAME = "Invalid account name."; + public static final String INVALID_ACL_ACCESS_TYPE = "Invalid acl public access type returned '%s'. Expected blob or container."; + public static final String INVALID_BLOB_TYPE = "Incorrect Blob type, please use the correct Blob type to access a blob on the server. Expected %s, actual %s."; + public static final String INVALID_BLOCK_ID = "Invalid blockID, blockID must be a valid Base64 String."; + public static final String INVALID_BLOCK_SIZE = "Block data should not exceed BlockBlobURL.MAX_STAGE_BLOCK_BYTES"; + public static final String INVALID_CONDITIONAL_HEADERS = "The conditionals specified for this operation did not match server."; + public static final String INVALID_CONNECTION_STRING = "Invalid connection string."; + public static final String INVALID_CONNECTION_STRING_DEV_STORE_NOT_TRUE = "Invalid connection string, the UseDevelopmentStorage key must always be paired with 'true'. Remove the flag entirely otherwise."; + public static final String INVALID_CONTENT_LENGTH = "ContentLength must be set to -1 or positive Long value."; + public static final String INVALID_CONTENT_TYPE = "An incorrect Content-Type was returned from the server."; + public static final String INVALID_CORS_RULE = "A CORS rule must contain at least one allowed origin and allowed method, and MaxAgeInSeconds cannot have a value less than zero."; + public static final String INVALID_DATE_STRING = "Invalid Date String: %s."; + public static final String INVALID_EDMTYPE_VALUE = "Invalid value '%s' for EdmType."; + public static final String INVALID_FILE_LENGTH = "File length must be greater than or equal to 0 bytes."; + public static final String INVALID_GEO_REPLICATION_STATUS = "Null or Invalid geo-replication status in response: %s."; + public static final String INVALID_IP_ADDRESS = "Error when parsing IPv4 address: IP address '%s' is invalid."; + public static final String INVALID_KEY = "Storage Key is not a valid base64 encoded string."; + public static final String INVALID_LISTING_DETAILS = "Invalid blob listing details specified."; + public static final String INVALID_LOGGING_LEVEL = "Invalid logging operations specified."; + public static final String INVALID_MAX_WRITE_SIZE = "Max write size is 4MB. Please specify a smaller range."; + public static final String INVALID_MESSAGE_LENGTH = "The message size cannot be larger than %s bytes."; + public static final String INVALID_MIME_RESPONSE = "Invalid MIME response received."; + public static final String INVALID_NUMBER_OF_BYTES_IN_THE_BUFFER = "Page data must be a multiple of 512 bytes. Buffer currently contains %d bytes."; + public static final String INVALID_OPERATION_FOR_A_SNAPSHOT = "Cannot perform this operation on a blob representing a snapshot."; + public static final String INVALID_PAGE_BLOB_LENGTH = "Page blob length must be multiple of 512."; + public static final String INVALID_PAGE_START_OFFSET = "Page start offset must be multiple of 512."; + public static final String INVALID_RANGE_CONTENT_MD5_HEADER = "Cannot specify x-ms-range-get-content-md5 header on ranges larger than 4 MB. Either use a BlobReadStream via openRead, or disable TransactionalMD5 via the BlobRequestOptions."; + public static final String INVALID_RESOURCE_NAME = "Invalid %s name. Check MSDN for more information about valid naming."; + public static final String INVALID_RESOURCE_NAME_LENGTH = "Invalid %s name length. The name must be between %s and %s characters long."; + public static final String INVALID_RESOURCE_RESERVED_NAME = "Invalid %s name. This name is reserved."; + public static final String INVALID_RESPONSE_RECEIVED = "The response received is invalid or improperly formatted."; + public static final String INVALID_STORAGE_PROTOCOL_VERSION = "Storage protocol version prior to 2009-09-19 do not support shared key authentication."; + public static final String INVALID_STORAGE_SERVICE = "Invalid storage service specified."; + public static final String INVALID_STREAM_LENGTH = "Invalid stream length; stream must be between 0 and %s MB in length."; + public static final String ITERATOR_EMPTY = "There are no more elements in this enumeration."; + public static final String KEY_AND_RESOLVER_MISSING = "Key and Resolver are not initialized. Decryption requires either of them to be initialized."; + public static final String LEASE_CONDITION_ON_SOURCE = "A lease condition cannot be specified on the source of a copy."; + public static final String LOG_STREAM_END_ERROR = "Error parsing log record: unexpected end of stream."; + public static final String LOG_STREAM_DELIMITER_ERROR = "Error parsing log record: unexpected delimiter encountered."; + public static final String LOG_STREAM_QUOTE_ERROR = "Error parsing log record: unexpected quote character encountered."; + public static final String LOG_VERSION_UNSUPPORTED = "A storage log version of %s is unsupported."; + public static final String MARK_EXPIRED = "Stream mark expired."; + public static final String MAXIMUM_EXECUTION_TIMEOUT_EXCEPTION = "The client could not finish the operation within specified maximum execution timeout."; + public static final String MISSING_CREDENTIALS = "No credentials provided."; + public static final String MISSING_MANDATORY_DATE_HEADER = "Canonicalization did not find a non-empty x-ms-date header in the request. Please use a request with a valid x-ms-date header in RFC 123 format."; + public static final String MISSING_MANDATORY_PARAMETER_FOR_SAS = "Missing mandatory parameters for valid Shared Access Signature."; + public static final String MISSING_MD5 = "ContentMD5 header is missing in the response."; + public static final String MISSING_NULLARY_CONSTRUCTOR = "Class type must contain contain a nullary constructor."; + public static final String MULTIPLE_CREDENTIALS_PROVIDED = "Cannot provide credentials as part of the address and as constructor parameter. Either pass in the address or use a different constructor."; + public static final String PARAMETER_NOT_IN_RANGE = "The value of the parameter '%s' should be between %s and %s."; + public static final String PARAMETER_SHOULD_BE_GREATER = "The value of the parameter '%s' should be greater than %s."; + public static final String PARAMETER_SHOULD_BE_GREATER_OR_EQUAL = "The value of the parameter '%s' should be greater than or equal to %s."; + public static final String PATH_STYLE_URI_MISSING_ACCOUNT_INFORMATION = "Missing account name information inside path style URI. Path style URIs should be of the form http:///"; + public static final String PRIMARY_ONLY_COMMAND = "This operation can only be executed against the primary storage location."; + public static final String PROPERTY_CANNOT_BE_SERIALIZED_AS_GIVEN_EDMTYPE = "Property %s with Edm Type %s cannot be de-serialized."; + public static final String PRECONDITION_FAILURE_IGNORED = "Pre-condition failure on a retry is being ignored since the request should have succeeded in the first attempt."; + public static final String RELATIVE_ADDRESS_NOT_PERMITTED = "Address %s is a relative address. Only absolute addresses are permitted."; + public static final String RESOURCE_NAME_EMPTY = "Invalid %s name. The name may not be null, empty, or whitespace only."; + public static final String RESPONSE_RECEIVED_IS_INVALID = "The response received is invalid or improperly formatted."; + public static final String SCHEME_NULL_OR_EMPTY = "The protocol to use is null. Please specify whether to use http or https."; + public static final String SECONDARY_ONLY_COMMAND = "This operation can only be executed against the secondary storage location."; + public static final String SNAPSHOT_LISTING_ERROR = "Listing snapshots is only supported in flat mode (no delimiter). Consider setting useFlatBlobListing to true."; + public static final String SNAPSHOT_QUERY_OPTION_ALREADY_DEFINED = "Snapshot query parameter is already defined in the blob URI. Either pass in a snapshotTime parameter or use a full URL with a snapshot query parameter."; + public static final String STORAGE_CREDENTIALS_NULL_OR_ANONYMOUS = "StorageCredentials cannot be null or anonymous for this service."; + public static final String STORAGE_CLIENT_OR_SAS_REQUIRED = "Either a SAS token or a service client must be specified."; + public static final String STORAGE_URI_MISSING_LOCATION = "The URI for the target storage location is not specified. Please consider changing the request's location mode."; + public static final String STORAGE_URI_MUST_MATCH = "Primary and secondary location URIs in a StorageUri must point to the same resource."; + public static final String STORAGE_URI_NOT_NULL = "Primary and secondary location URIs in a StorageUri must not both be null."; + public static final String STREAM_CLOSED = "Stream is already closed."; + public static final String STREAM_SKIP_FAILED = "The supplied stream has failed to skip to the correct position after successive attempts. Please ensure there are bytes available and try your upload again."; + public static final String STREAM_LENGTH_GREATER_THAN_4MB = "Invalid stream length, length must be less than or equal to 4 MB in size."; + public static final String STREAM_LENGTH_GREATER_THAN_100MB = "Invalid stream length, length must be less than or equal to 100 MB in size."; + public static final String STREAM_LENGTH_NEGATIVE = "Invalid stream length, specify -1 for unknown length stream, or a positive number of bytes."; + public static final String STRING_NOT_VALID = "The String is not a valid Base64-encoded string."; + public static final String TAKE_COUNT_ZERO_OR_NEGATIVE = "Take count must be positive and greater than 0."; + public static final String TOO_MANY_PATH_SEGMENTS = "The count of URL path segments (strings between '/' characters) as part of the blob name cannot exceed 254."; + public static final String TOO_MANY_SHARED_ACCESS_POLICY_IDENTIFIERS = "Too many %d shared access policy identifiers provided. Server does not support setting more than %d on a single container, queue, or table."; + public static final String TOO_MANY_SHARED_ACCESS_POLICY_IDS = "Too many %d shared access policy identifiers provided. Server does not support setting more than %d on a single container."; + public static final String UNEXPECTED_CONTINUATION_TYPE = "The continuation type passed in is unexpected. Please verify that the correct continuation type is passed in. Expected {%s}, found {%s}."; + public static final String UNEXPECTED_FIELD_NAME = "Unexpected field name. Expected: '%s'. Actual: '%s'."; + public static final String UNEXPECTED_STATUS_CODE_RECEIVED = "Unexpected http status code received."; + public static final String UNEXPECTED_STREAM_READ_ERROR = "Unexpected error. Stream returned unexpected number of bytes."; +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java new file mode 100644 index 0000000000000..7450ae699f5a4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/ServiceSASSignatureValues.java @@ -0,0 +1,470 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.blob.models.UserDelegationKey; +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.security.InvalidKeyException; +import java.time.OffsetDateTime; + +/** + * ServiceSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage service. Once + * all the values here are set appropriately, call generateSASQueryParameters to obtain a representation of the SAS + * which can actually be applied to blob urls. Note: that both this class and {@link SASQueryParameters} exist because + * the former is mutable and a logical representation while the latter is immutable and used to generate actual REST + * requests. + *

    + * Please see here + * for more conceptual information on SAS. + *

    + * Please see here for + * more details on each value, including which are required. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_sas "Sample code for ServiceSASSignatureValues")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ +final class ServiceSASSignatureValues { + + private String version = Constants.HeaderConstants.TARGET_STORAGE_VERSION; + + private SASProtocol protocol; + + private OffsetDateTime startTime; + + private OffsetDateTime expiryTime; + + private String permissions; + + private IPRange ipRange; + + private String containerName; + + private String blobName; + + private String snapshotId; + + private String identifier; + + private String cacheControl; + + private String contentDisposition; + + private String contentEncoding; + + private String contentLanguage; + + private String contentType; + + /** + * Creates an object with empty values for all fields. + */ + ServiceSASSignatureValues() { + } + + /** + * The version of the service this SAS will target. If not specified, it will default to the version targeted by the + * library. + */ + public String version() { + return version; + } + + /** + * The version of the service this SAS will target. If not specified, it will default to the version targeted by the + * library. + */ + public ServiceSASSignatureValues version(String version) { + this.version = version; + return this; + } + + /** + * {@link SASProtocol} + */ + public SASProtocol protocol() { + return protocol; + } + + /** + * {@link SASProtocol} + */ + public ServiceSASSignatureValues protocol(SASProtocol protocol) { + this.protocol = protocol; + return this; + } + + /** + * When the SAS will take effect. + */ + public OffsetDateTime startTime() { + return startTime; + } + + /** + * When the SAS will take effect. + */ + public ServiceSASSignatureValues startTime(OffsetDateTime startTime) { + this.startTime = startTime; + return this; + } + + /** + * The time after which the SAS will no longer work. + */ + public OffsetDateTime expiryTime() { + return expiryTime; + } + + /** + * The time after which the SAS will no longer work. + */ + public ServiceSASSignatureValues expiryTime(OffsetDateTime expiryTime) { + this.expiryTime = expiryTime; + return this; + } + + /** + * Please refer to either {@link ContainerSASPermission} or {@link BlobSASPermission} depending on the resource + * being accessed for help constructing the permissions string. + */ + public String permissions() { + return permissions; + } + + /** + * Please refer to either {@link ContainerSASPermission} or {@link BlobSASPermission} depending on the resource + * being accessed for help constructing the permissions string. + */ + public ServiceSASSignatureValues permissions(String permissions) { + this.permissions = permissions; + return this; + } + + /** + * {@link IPRange} + */ + public IPRange ipRange() { + return ipRange; + } + + /** + * {@link IPRange} + */ + public ServiceSASSignatureValues ipRange(IPRange ipRange) { + this.ipRange = ipRange; + return this; + } + + /** + * The name of the container the SAS user may access. + */ + public String containerName() { + return containerName; + } + + /** + * The name of the container the SAS user may access. + */ + public ServiceSASSignatureValues containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * The name of the blob the SAS user may access. + */ + public String blobName() { + return blobName; + } + + /** + * The name of the blob the SAS user may access. + */ + public ServiceSASSignatureValues blobName(String blobName) { + this.blobName = blobName; + return this; + } + + /** + * The specific snapshot the SAS user may access. + */ + public String snapshotId() { + return snapshotId; + } + + /** + * The specific snapshot the SAS user may access. + */ + public ServiceSASSignatureValues snapshotId(String snapshotId) { + this.snapshotId = snapshotId; + return this; + } + + /** + * The name of the access policy on the container this SAS references if any. Please see + * here + * for more information. + */ + public String identifier() { + return identifier; + } + + /** + * The name of the access policy on the container this SAS references if any. Please see + * here + * for more information. + */ + public ServiceSASSignatureValues identifier(String identifier) { + this.identifier = identifier; + return this; + } + + /** + * The cache-control header for the SAS. + */ + public String cacheControl() { + return cacheControl; + } + + /** + * The cache-control header for the SAS. + */ + public ServiceSASSignatureValues cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * The content-disposition header for the SAS. + */ + public String contentDisposition() { + return contentDisposition; + } + + /** + * The content-disposition header for the SAS. + */ + public ServiceSASSignatureValues contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * The content-encoding header for the SAS. + */ + public String contentEncoding() { + return contentEncoding; + } + + /** + * The content-encoding header for the SAS. + */ + public ServiceSASSignatureValues contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * The content-language header for the SAS. + */ + public String contentLanguage() { + return contentLanguage; + } + + /** + * The content-language header for the SAS. + */ + public ServiceSASSignatureValues contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * The content-type header for the SAS. + */ + public String contentType() { + return contentType; + } + + /** + * The content-type header for the SAS. + */ + public ServiceSASSignatureValues contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Uses an account's shared key credential to sign these signature values to produce the proper SAS query + * parameters. + * + * @param sharedKeyCredentials + * A {@link SharedKeyCredential} object used to sign the SAS values. + * + * @return {@link SASQueryParameters} + * @throws Error If the accountKey is not a valid Base64-encoded string. + */ + public SASQueryParameters generateSASQueryParameters(SharedKeyCredential sharedKeyCredentials) { + Utility.assertNotNull("sharedKeyCredentials", sharedKeyCredentials); + assertGenerateOK(); + + String resource = getResource(); + String verifiedPermissions = getVerifiedPermissions(); + + // Signature is generated on the un-url-encoded values. + final String stringToSign = stringToSign(verifiedPermissions, resource, sharedKeyCredentials); + + String signature = null; + try { + signature = sharedKeyCredentials.computeHmac256(stringToSign); + } catch (InvalidKeyException e) { + throw new Error(e); // The key should have been validated by now. If it is no longer valid here, we fail. + } + + return new SASQueryParameters(this.version, null, null, + this.protocol, this.startTime, this.expiryTime, this.ipRange, this.identifier, resource, + this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, + this.contentLanguage, this.contentType, null /* delegate */); + } + + /** + * Uses a user delegation key to sign these signature values to produce the proper SAS query parameters. + * + * @param delegationKey + * A {@link UserDelegationKey} object used to sign the SAS values. + * + * @param accountName + * Name of the account holding the resource this SAS is authorizing. + * + * @return {@link SASQueryParameters} + * @throws Error If the accountKey is not a valid Base64-encoded string. + */ + public SASQueryParameters generateSASQueryParameters(UserDelegationKey delegationKey, String accountName) { + Utility.assertNotNull("delegationKey", delegationKey); + Utility.assertNotNull("accountName", accountName); + assertGenerateOK(); + + String resource = getResource(); + String verifiedPermissions = getVerifiedPermissions(); + + // Signature is generated on the un-url-encoded values. + final String stringToSign = stringToSign(verifiedPermissions, resource, delegationKey, accountName); + + String signature = null; + try { + signature = Utility.delegateComputeHmac256(delegationKey, stringToSign); + } catch (InvalidKeyException e) { + throw new Error(e); // The key should have been validated by now. If it is no longer valid here, we fail. + } + + return new SASQueryParameters(this.version, null, null, + this.protocol, this.startTime, this.expiryTime, this.ipRange, null /* identifier */, resource, + this.permissions, signature, this.cacheControl, this.contentDisposition, this.contentEncoding, + this.contentLanguage, this.contentType, delegationKey); + } + + /** + * Common assertions for generateSASQueryParameters overloads. + */ + private void assertGenerateOK() { + Utility.assertNotNull("version", this.version); + Utility.assertNotNull("containerName", this.containerName); + if (blobName == null && snapshotId != null) { + throw new IllegalArgumentException("Cannot set a snapshotId without a blobName."); + } + } + + /** + * Gets the resource string for SAS tokens based on object state. + */ + private String getResource() { + String resource = "c"; + if (!Utility.isNullOrEmpty(this.blobName)) { + resource = snapshotId != null && !snapshotId.isEmpty() ? "bs" : "b"; + } + + return resource; + } + + /** + * Gets the verified permissions string for SAS tokens based on object state. + */ + private String getVerifiedPermissions() { + String verifiedPermissions = null; + // Calling parse and toString guarantees the proper ordering and throws on invalid characters. + if (Utility.isNullOrEmpty(this.blobName)) { + if (this.permissions != null) { + verifiedPermissions = ContainerSASPermission.parse(this.permissions).toString(); + } + } else { + if (this.permissions != null) { + verifiedPermissions = BlobSASPermission.parse(this.permissions).toString(); + } + } + + return verifiedPermissions; + } + + private String getCanonicalName(String accountName) { + // Container: "/blob/account/containername" + // Blob: "/blob/account/containername/blobname" + StringBuilder canonicalName = new StringBuilder("/blob"); + canonicalName.append('/').append(accountName).append('/').append(this.containerName); + + if (!Utility.isNullOrEmpty(this.blobName)) { + canonicalName.append("/").append(this.blobName); + } + + return canonicalName.toString(); + } + + private String stringToSign(final String verifiedPermissions, final String resource, + final SharedKeyCredential sharedKeyCredentials) { + return String.join("\n", + verifiedPermissions == null ? "" : verifiedPermissions, + this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + getCanonicalName(sharedKeyCredentials.accountName()), + this.identifier == null ? "" : this.identifier, + this.ipRange == null ? (new IPRange()).toString() : this.ipRange.toString(), + this.protocol == null ? "" : protocol.toString(), + this.version == null ? "" : this.version, + resource == null ? "" : resource, + this.snapshotId == null ? "" : this.snapshotId, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType + ); + } + + private String stringToSign(final String verifiedPermissions, final String resource, + final UserDelegationKey key, final String accountName) { + return String.join("\n", + verifiedPermissions == null ? "" : verifiedPermissions, + this.startTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + getCanonicalName(accountName), + key.signedOid() == null ? "" : key.signedOid(), + key.signedTid() == null ? "" : key.signedTid(), + key.signedStart() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedStart()), + key.signedExpiry() == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(key.signedExpiry()), + key.signedService() == null ? "" : key.signedService(), + key.signedVersion() == null ? "" : key.signedVersion(), + this.ipRange == null ? new IPRange().toString() : this.ipRange.toString(), + this.protocol == null ? "" : this.protocol.toString(), + this.version == null ? "" : this.version, + resource == null ? "" : resource, + this.snapshotId == null ? "" : this.snapshotId, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType + ); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java new file mode 100644 index 0000000000000..d5b0aecc3a3f1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncClient.java @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.blob.models.ContainerItem; +import com.azure.storage.blob.models.ListContainersOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; +import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.StorageServiceProperties; +import com.azure.storage.blob.models.StorageServiceStats; +import com.azure.storage.blob.models.UserDelegationKey; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; +import java.time.OffsetDateTime; + +/** + * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. + * This class does not hold any state about a particular storage account but is + * instead a convenient way of sending off appropriate requests to the resource on the service. + * It may also be used to construct URLs to blobs and containers. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerAsyncClient} + * through {@link #getContainerAsyncClient(String)}, and operations on a blob are available on {@link BlobAsyncClient}. + * + *

    + * Please see here for more + * information on containers. + * + *

    + * Note this client is an async client that returns reactive responses from Spring Reactor Core + * project (https://projectreactor.io/). Calling the methods in this client will NOT + * start the actual network operation, until {@code .subscribe()} is called on the reactive response. + * You can simply convert one of these responses to a {@link java.util.concurrent.CompletableFuture} + * object through {@link Mono#toFuture()}. + */ +public final class StorageAsyncClient { + StorageAsyncRawClient storageAsyncRawClient; + + /** + * Package-private constructor for use by {@link StorageClientBuilder}. + * @param azureBlobStorageBuilder the API client builder for blob storage API + */ + StorageAsyncClient(AzureBlobStorageBuilder azureBlobStorageBuilder) { + this.storageAsyncRawClient = new StorageAsyncRawClient(azureBlobStorageBuilder.build()); + } + + /** + * Initializes a {@link ContainerAsyncClient} object pointing to the specified container. This method does not create a + * container. It simply constructs the URL to the container and offers access to methods relevant to containers. + * + * @param containerName + * The name of the container to point to. + * @return + * A {@link ContainerAsyncClient} object pointing to the specified container + */ + public ContainerAsyncClient getContainerAsyncClient(String containerName) { + return new ContainerAsyncClient(new AzureBlobStorageBuilder() + .url(Utility.appendToURLPath(getAccountUrl(), containerName).toString()) + .pipeline(storageAsyncRawClient.azureBlobStorage.httpPipeline())); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param containerName Name of the container to create + * @return A response containing a {@link ContainerAsyncClient} used to interact with the container created. + */ + public Mono> createContainer(String containerName) { + return createContainer(containerName, null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param containerName Name of the container to create + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @return A response containing a {@link ContainerAsyncClient} used to interact with the container created. + */ + public Mono> createContainer(String containerName, Metadata metadata, PublicAccessType accessType) { + ContainerAsyncClient containerAsyncClient = getContainerAsyncClient(containerName); + + return containerAsyncClient.create(metadata, accessType) + .map(response -> new SimpleResponse<>(response, containerAsyncClient)); + } + + /** + * Gets the URL of the storage account represented by this client. + * @return the URL. + * @throws RuntimeException If the account URL is malformed. + */ + public URL getAccountUrl() { + try { + return new URL(storageAsyncRawClient.azureBlobStorage.url()); + } catch (MalformedURLException e) { + throw new RuntimeException(String.format("Invalid URL on %s: %s" + getClass().getSimpleName(), storageAsyncRawClient.azureBlobStorage.url()), e); + } + } + + /** + * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, see + * the Azure Docs. + * + * @return + * A reactive response emitting the list of containers. + */ + public Flux listContainers() { + return this.listContainers(new ListContainersOptions()); + } + + /** + * Returns a reactive Publisher emitting all the containers in this account lazily as needed. For more information, see + * the Azure Docs. + * + * @param options + * A {@link ListContainersOptions} which specifies what data should be returned by the service. + * + * @return + * A reactive response emitting the list of containers. + */ + public Flux listContainers(ListContainersOptions options) { + return storageAsyncRawClient + .listContainersSegment(null, options) + .flatMapMany(response -> listContainersHelper(response.value().marker(), options, response)); + } + + private Flux listContainersHelper(String marker, ListContainersOptions options, + ServicesListContainersSegmentResponse response) { + Flux result = Flux.fromIterable(response.value().containerItems()); + if (response.value().nextMarker() != null) { + // Recursively add the continuation items to the observable. + result = result.concatWith(storageAsyncRawClient.listContainersSegment(marker, options) + .flatMapMany((r) -> + listContainersHelper(response.value().nextMarker(), options, r))); + } + + return result; + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @return + * A reactive response containing the storage account properties. + */ + public Mono> getProperties() { + return storageAsyncRawClient + .getProperties() + .map(rb -> new SimpleResponse<>(rb, rb.value())); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * + * @return + * A reactive response containing the storage account properties. + */ + public Mono setProperties(StorageServiceProperties properties) { + return storageAsyncRawClient + .setProperties(properties) + .map(VoidResponse::new); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * + * @return + * A reactive response containing the user delegation key. + */ + public Mono> getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { + return storageAsyncRawClient + .getUserDelegationKey(start, expiry) + .map(rb -> new SimpleResponse<>(rb, rb.value())); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @return + * A reactive response containing the storage account statistics. + */ + public Mono> getStatistics() { + return storageAsyncRawClient + .getStatistics() + .map(rb -> new SimpleResponse<>(rb, rb.value())); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return + * A reactive response containing the storage account info. + */ + public Mono> getAccountInfo() { + return storageAsyncRawClient + .getAccountInfo() + .map(rb -> new SimpleResponse<>(rb, new StorageAccountInfo(rb.deserializedHeaders()))); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java new file mode 100644 index 0000000000000..a2b6be965ed30 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageAsyncRawClient.java @@ -0,0 +1,172 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpPipeline; +import com.azure.core.util.Context; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.KeyInfo; +import com.azure.storage.blob.models.ListContainersOptions; +import com.azure.storage.blob.models.ServicesGetAccountInfoResponse; +import com.azure.storage.blob.models.ServicesGetPropertiesResponse; +import com.azure.storage.blob.models.ServicesGetStatisticsResponse; +import com.azure.storage.blob.models.ServicesGetUserDelegationKeyResponse; +import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; +import com.azure.storage.blob.models.ServicesSetPropertiesResponse; +import com.azure.storage.blob.models.StorageServiceProperties; +import reactor.core.publisher.Mono; + +import java.time.OffsetDateTime; + +import static com.azure.storage.blob.Utility.postProcessResponse; + +/** + * Represents a URL to a storage service. This class does not hold any state about a particular storage account but is + * instead a convenient way of sending off appropriate requests to the resource on the service. + * It may also be used to construct URLs to blobs and containers. + * Please see here for more + * information on containers. + */ +final class StorageAsyncRawClient { + + final AzureBlobStorageImpl azureBlobStorage; + + /** + * Creates a {@code ServiceURL} object pointing to the account specified by the URL and using the provided pipeline + * to make HTTP requests. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_url "Sample code for ServiceURL constructor")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + StorageAsyncRawClient(AzureBlobStorageImpl azureBlobStorage) { + this.azureBlobStorage = azureBlobStorage; + } + + /** + * Returns a Mono segment of containers starting from the specified Marker. + * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. + * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned + * Marker) to get the next segment. For more information, see + * the Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * A {@link ListContainersOptions} which specifies what data should be returned by the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono listContainersSegment(String marker, + ListContainersOptions options) { + options = options == null ? new ListContainersOptions() : options; + + return postProcessResponse( + this.azureBlobStorage.services().listContainersSegmentWithRestResponseAsync( + options.prefix(), marker, options.maxResults(), options.details().toIncludeType(), null, + null, Context.NONE)); + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getProperties() { + return postProcessResponse( + this.azureBlobStorage.services().getPropertiesWithRestResponseAsync(null, null, Context.NONE)); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono setProperties(StorageServiceProperties properties) { + return postProcessResponse( + this.azureBlobStorage.services().setPropertiesWithRestResponseAsync(properties, null, null, Context.NONE)); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * + * @return Emits the successful response. + * @throws IllegalArgumentException If {@code start} isn't null and is after {@code expiry}. + */ + public Mono getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { + Utility.assertNotNull("expiry", expiry); + if (start != null && !start.isBefore(expiry)) { + throw new IllegalArgumentException("`start` must be null or a datetime before `expiry`."); + } + + return postProcessResponse( + this.azureBlobStorage.services().getUserDelegationKeyWithRestResponseAsync( + new KeyInfo() + .start(start == null ? "" : Utility.ISO_8601_UTC_DATE_FORMATTER.format(start)) + .expiry(Utility.ISO_8601_UTC_DATE_FORMATTER.format(expiry)), + null, null, Context.NONE) + ); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getStatistics() { + return postProcessResponse( + this.azureBlobStorage.services().getStatisticsWithRestResponseAsync(null, null, Context.NONE)); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public Mono getAccountInfo() { + return postProcessResponse( + this.azureBlobStorage.services().getAccountInfoWithRestResponseAsync(Context.NONE)); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java new file mode 100644 index 0000000000000..f18cf0640fbd9 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClient.java @@ -0,0 +1,293 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.blob.models.ContainerItem; +import com.azure.storage.blob.models.ListContainersOptions; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.StorageAccountInfo; +import com.azure.storage.blob.models.StorageServiceProperties; +import com.azure.storage.blob.models.StorageServiceStats; +import com.azure.storage.blob.models.UserDelegationKey; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.Duration; +import java.time.OffsetDateTime; + +/** + * Client to a storage account. It may only be instantiated through a {@link StorageClientBuilder}. + * This class does not hold any state about a particular storage account but is + * instead a convenient way of sending off appropriate requests to the resource on the service. + * It may also be used to construct URLs to blobs and containers. + * + *

    + * This client contains operations on a blob. Operations on a container are available on {@link ContainerClient} + * through {@link #getContainerClient(String)}, and operations on a blob are available on {@link BlobClient}. + * + *

    + * Please see here for more + * information on containers. + */ +public final class StorageClient { + + private StorageAsyncClient storageAsyncClient; + + /** + * Package-private constructor for use by {@link StorageClientBuilder}. + * @param storageAsyncClient the async storage account client + */ + StorageClient(StorageAsyncClient storageAsyncClient) { + this.storageAsyncClient = storageAsyncClient; + } + + /** + * Initializes a {@link ContainerClient} object pointing to the specified container. This method does not create a + * container. It simply constructs the URL to the container and offers access to methods relevant to containers. + * + * @param containerName + * The name of the container to point to. + * @return + * A {@link ContainerClient} object pointing to the specified container + */ + public ContainerClient getContainerClient(String containerName) { + return new ContainerClient(storageAsyncClient.getContainerAsyncClient(containerName)); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param containerName Name of the container to create + * @return A response containing a {@link ContainerClient} used to interact with the container created. + */ + public Response createContainer(String containerName) { + return createContainer(containerName, null, null); + } + + /** + * Creates a new container within a storage account. If a container with the same name already exists, the operation + * fails. For more information, see the + * Azure Docs. + * + * @param containerName Name of the container to create + * @param metadata + * {@link Metadata} + * @param accessType + * Specifies how the data in this container is available to the public. See the x-ms-blob-public-access header + * in the Azure Docs for more information. Pass null for no public access. + * @return A response containing a {@link ContainerClient} used to interact with the container created. + */ + public Response createContainer(String containerName, Metadata metadata, PublicAccessType accessType) { + ContainerClient client = getContainerClient(containerName); + + return new SimpleResponse<>(client.create(metadata, accessType, null), client); + } + + /** + * Gets the URL of the storage account represented by this client. + * @return the URL. + */ + public URL getAccountUrl() { + return storageAsyncClient.getAccountUrl(); + } + + /** + * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated + * through while new items are automatically retrieved as needed. For more information, see + * the Azure Docs. + * + * @return + * The list of containers. + */ + public Iterable listContainers() { + return this.listContainers(new ListContainersOptions(), null); + } + + /** + * Returns a lazy loaded list of containers in this account. The returned {@link Iterable} can be iterated + * through while new items are automatically retrieved as needed. For more information, see + * the Azure Docs. + * + * @param options + * A {@link ListContainersOptions} which specifies what data should be returned by the service. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The list of containers. + */ + public Iterable listContainers(ListContainersOptions options, Duration timeout) { + Flux response = storageAsyncClient.listContainers(options); + + return timeout == null ? response.toIterable() : response.timeout(timeout).toIterable(); + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @return + * The storage account properties. + */ + public Response getProperties() { + return this.getProperties(null); + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The storage account properties. + */ + public Response getProperties(Duration timeout) { + + Mono> response = storageAsyncClient.getProperties(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * + * @return + * The storage account properties. + */ + public VoidResponse setProperties(StorageServiceProperties properties) { + return this.setProperties(properties, null); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The storage account properties. + */ + public VoidResponse setProperties(StorageServiceProperties properties, Duration timeout) { + Mono response = storageAsyncClient.setProperties(properties); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * + * @return + * The user delegation key. + */ + public Response getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { + return this.getUserDelegationKey(start, expiry, null); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link TokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The user delegation key. + */ + public Response getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry, + Duration timeout) { + Mono> response = storageAsyncClient.getUserDelegationKey(start, expiry); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @return + * The storage account statistics. + */ + public Response getStatistics() { + return this.getStatistics(null); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The storage account statistics. + */ + public Response getStatistics(Duration timeout) { + Mono> response = storageAsyncClient.getStatistics(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return + * The storage account info. + */ + public Response getAccountInfo() { + return this.getAccountInfo(null); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @param timeout + * An optional timeout value beyond which a {@link RuntimeException} will be raised. + * + * @return + * The storage account info. + */ + public Response getAccountInfo(Duration timeout) { + Mono> response = storageAsyncClient.getAccountInfo(); + + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClientBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClientBuilder.java new file mode 100644 index 0000000000000..0aff9d26aa029 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageClientBuilder.java @@ -0,0 +1,289 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.credentials.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.core.util.configuration.Configuration; +import com.azure.core.util.configuration.ConfigurationManager; +import com.azure.storage.blob.implementation.AzureBlobStorageBuilder; +import com.azure.storage.common.credentials.SASTokenCredential; +import com.azure.storage.common.credentials.SharedKeyCredential; +import com.azure.storage.common.policy.RequestRetryOptions; +import com.azure.storage.common.policy.RequestRetryPolicy; +import com.azure.storage.common.policy.SASTokenCredentialPolicy; +import com.azure.storage.common.policy.SharedKeyCredentialPolicy; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Fluent StorageClientBuilder for instantiating a {@link StorageClient} or {@link StorageAsyncClient} + * using {@link StorageClientBuilder#buildClient()} or {@link StorageClientBuilder#buildAsyncClient()} respectively. + * + *

    + * The following information must be provided on this builder: + * + *

      + *
    • the endpoint through {@code .endpoint()}, in the format of {@code https://{accountName}.blob.core.windows.net}. + *
    • the credential through {@code .credential()} or {@code .connectionString()} if the container is not publicly accessible. + *
    + * + *

    + * Once all the configurations are set on this builder, call {@code .buildClient()} to create a + * {@link StorageClient} or {@code .buildAsyncClient()} to create a {@link StorageAsyncClient}. + */ +public final class StorageClientBuilder { + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + private static final String ENDPOINT_PROTOCOL = "defaultendpointsprotocol"; + private static final String ENDPOINT_SUFFIX = "endpointsuffix"; + + private final List policies; + + private String endpoint; + private SharedKeyCredential sharedKeyCredential; + private TokenCredential tokenCredential; + private SASTokenCredential sasTokenCredential; + private HttpClient httpClient; + private HttpLogDetailLevel logLevel; + private RequestRetryOptions retryOptions; + private Configuration configuration; + + /** + * Creates a builder instance that is able to configure and construct {@link StorageClient StorageClients} + * and {@link StorageAsyncClient StorageAsyncClients}. + */ + public StorageClientBuilder() { + retryOptions = new RequestRetryOptions(); + logLevel = HttpLogDetailLevel.NONE; + policies = new ArrayList<>(); + } + + private AzureBlobStorageBuilder buildImpl() { + Objects.requireNonNull(endpoint); + + // Closest to API goes first, closest to wire goes last. + final List policies = new ArrayList<>(); + + if (configuration == null) { + configuration = ConfigurationManager.getConfiguration(); + } + policies.add(new UserAgentPolicy(BlobConfiguration.NAME, BlobConfiguration.VERSION, configuration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddDatePolicy()); + + if (sharedKeyCredential != null) { + policies.add(new SharedKeyCredentialPolicy(sharedKeyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, String.format("%s/.default", endpoint))); + } else if (sasTokenCredential != null) { + policies.add(new SASTokenCredentialPolicy(sasTokenCredential)); + } else { + policies.add(new AnonymousCredentialPolicy()); + } + + policies.add(new RequestRetryPolicy(retryOptions)); + + policies.addAll(this.policies); + policies.add(new HttpLoggingPolicy(logLevel)); + + HttpPipeline pipeline = HttpPipeline.builder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + + return new AzureBlobStorageBuilder() + .url(endpoint) + .pipeline(pipeline); + } + + /** + * @return a {@link StorageClient} created from the configurations in this builder. + */ + public StorageClient buildClient() { + return new StorageClient(buildAsyncClient()); + } + + /** + * @return a {@link StorageAsyncClient} created from the configurations in this builder. + */ + public StorageAsyncClient buildAsyncClient() { + return new StorageAsyncClient(buildImpl()); + } + + /** + * Sets the blob service endpoint, additionally parses it for information (SAS token, queue name) + * @param endpoint URL of the service + * @return the updated StorageClientBuilder object + * @throws IllegalArgumentException If {@code endpoint} is a malformed URL. + */ + public StorageClientBuilder endpoint(String endpoint) { + Objects.requireNonNull(endpoint); + URL url; + try { + url = new URL(endpoint); + this.endpoint = url.getProtocol() + "://" + url.getAuthority(); + } catch (MalformedURLException ex) { + throw new IllegalArgumentException("The Azure Storage endpoint url is malformed."); + } + + SASTokenCredential credential = SASTokenCredential.fromQuery(url.getQuery()); + if (credential != null) { + this.credential(credential); + } + + return this; + } + + String endpoint() { + return this.endpoint; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated ContainerClientBuilder object + */ + public StorageClientBuilder credential(SharedKeyCredential credential) { + this.sharedKeyCredential = credential; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder credential(TokenCredential credential) { + this.tokenCredential = credential; + this.sharedKeyCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the credential used to authorize requests sent to the service + * @param credential authorization credential + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder credential(SASTokenCredential credential) { + this.sasTokenCredential = credential; + this.sharedKeyCredential = null; + this.tokenCredential = null; + return this; + } + + /** + * Clears the credential used to authorize requests sent to the service + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder anonymousCredential() { + this.sharedKeyCredential = null; + this.tokenCredential = null; + this.sasTokenCredential = null; + return this; + } + + /** + * Sets the connection string for the service, parses it for authentication information (account name, account key) + * @param connectionString connection string from access keys section + * @return the updated StorageClientBuilder object + * @throws IllegalArgumentException If {@code connectionString} doesn't contain AccountName or AccountKey. + */ + public StorageClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString); + + Map connectionKVPs = new HashMap<>(); + for (String s : connectionString.split(";")) { + String[] kvp = s.split("=", 2); + connectionKVPs.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionKVPs.get(ACCOUNT_NAME); + String accountKey = connectionKVPs.get(ACCOUNT_KEY); + String endpointProtocol = connectionKVPs.get(ENDPOINT_PROTOCOL); + String endpointSuffix = connectionKVPs.get(ENDPOINT_SUFFIX); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + if (!ImplUtils.isNullOrEmpty(endpointProtocol) && !ImplUtils.isNullOrEmpty(endpointSuffix)) { + String endpoint = String.format("%s://%s.blob.%s", endpointProtocol, accountName, endpointSuffix.replaceFirst("^\\.", "")); + endpoint(endpoint); + } + + // Use accountName and accountKey to get the SAS token using the credential class. + return credential(new SharedKeyCredential(accountName, accountKey)); + } + + /** + * Sets the http client used to send service requests + * @param httpClient http client to send requests + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /** + * Adds a pipeline policy to apply on each request sent + * @param pipelinePolicy a pipeline policy + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder addPolicy(HttpPipelinePolicy pipelinePolicy) { + this.policies.add(pipelinePolicy); + return this; + } + + /** + * Sets the logging level for service requests + * @param logLevel logging level + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder httpLogDetailLevel(HttpLogDetailLevel logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration values used to buildClient the client with + * when they are not set in the appendBlobClientBuilder, defaults to Configuration.NONE + * @param configuration configuration store + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Sets the request retry options for all the requests made through the client. + * @param retryOptions the options to configure retry behaviors + * @return the updated StorageClientBuilder object + */ + public StorageClientBuilder retryOptions(RequestRetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageException.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageException.java new file mode 100644 index 0000000000000..8fb587be36115 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageException.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.exception.HttpResponseException; +import com.azure.storage.blob.models.StorageErrorCode; +import com.azure.storage.blob.models.StorageErrorException; + +/** + * A {@code StorageException} is thrown whenever Azure Storage successfully returns an error code that is not 200-level. + * Users can inspect the status code and error code to determine the cause of the error response. The exception message + * may also contain more detailed information depending on the type of error. The user may also inspect the raw HTTP + * response or call toString to get the full payload of the error response if present. + * Note that even some expected "errors" will be thrown as a {@code StorageException}. For example, some users may + * perform a getProperties request on an entity to determine whether it exists or not. If it does not exists, an + * exception will be thrown even though this may be considered an expected indication of absence in this case. + * + *

    Sample Code

    + *

    For more samples, please see the sample file

    + */ +public final class StorageException extends HttpResponseException { + + private final String message; + + StorageException(StorageErrorException e, String responseBody) { + super(e.getMessage(), e.response(), e); + this.message = responseBody; + } + + /** + * @return The error code returned by the service. + */ + public StorageErrorCode errorCode() { + return StorageErrorCode.fromString(super.response().headers().value(Constants.HeaderConstants.ERROR_CODE)); + } + + /** + * @return The message returned by the service. + */ + public String message() { + return this.message; + } + + /** + * @return The status code on the response. + */ + public int statusCode() { + return super.response().statusCode(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java new file mode 100644 index 0000000000000..cebfdc451ae67 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/StorageRawClient.java @@ -0,0 +1,259 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpPipeline; +import com.azure.storage.blob.implementation.AzureBlobStorageImpl; +import com.azure.storage.blob.models.ListContainersOptions; +import com.azure.storage.blob.models.ServicesGetAccountInfoResponse; +import com.azure.storage.blob.models.ServicesGetPropertiesResponse; +import com.azure.storage.blob.models.ServicesGetStatisticsResponse; +import com.azure.storage.blob.models.ServicesGetUserDelegationKeyResponse; +import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; +import com.azure.storage.blob.models.ServicesSetPropertiesResponse; +import com.azure.storage.blob.models.StorageServiceProperties; +import com.azure.storage.common.credentials.SASTokenCredential; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.OffsetDateTime; + +/** + * Represents a URL to a storage service. This class does not hold any state about a particular storage account but is + * instead a convenient way of sending off appropriate requests to the resource on the service. + * It may also be used to construct URLs to blobs and containers. + * Please see here for more + * information on containers. + */ +final class StorageRawClient { + + StorageAsyncRawClient storageAsyncRawClient; + + /** + * Creates a {@code ServiceURL} object pointing to the account specified by the URL and using the provided pipeline + * to make HTTP requests. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_url "Sample code for ServiceURL constructor")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + StorageRawClient(AzureBlobStorageImpl azureBlobStorage) { + this.storageAsyncRawClient = new StorageAsyncRawClient(azureBlobStorage); + } + + /** + * Returns a Mono segment of containers starting from the specified Marker. + * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. + * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned + * Marker) to get the next segment. For more information, see + * the Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * A {@link ListContainersOptions} which specifies what data should be returned by the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesListContainersSegmentResponse listContainersSegment(String marker, + ListContainersOptions options) { + return this.listContainersSegment(marker, options, null); + } + + /** + * Returns a Mono segment of containers starting from the specified Marker. + * Use an empty marker to start enumeration from the beginning. Container names are returned in lexicographic order. + * After getting a segment, process it, and then call ListContainers again (passing the the previously-returned + * Marker) to get the next segment. For more information, see + * the Azure Docs. + * + * @param marker + * Identifies the portion of the list to be returned with the next list operation. + * This value is returned in the response of a previous list operation as the + * ListContainersSegmentResponse.body().nextMarker(). Set to null to list the first segment. + * @param options + * A {@link ListContainersOptions} which specifies what data should be returned by the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list "Sample code for ServiceURL.listContainersSegment")] \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_list_helper "Helper code for ServiceURL.listContainersSegment")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesListContainersSegmentResponse listContainersSegment(String marker, + ListContainersOptions options, Duration timeout) { + Mono response = storageAsyncRawClient.listContainersSegment(marker, options); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetPropertiesResponse getProperties() { + return this.getProperties(null); + } + + /** + * Gets the properties of a storage account’s Blob service. For more information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.getProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetPropertiesResponse getProperties(Duration timeout) { + Mono response = storageAsyncRawClient.getProperties(); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesSetPropertiesResponse setProperties(StorageServiceProperties properties) { + return this.setProperties(properties, null); + } + + /** + * Sets properties for a storage account's Blob service endpoint. For more information, see the + * Azure Docs. + * Note that setting the default service version has no effect when using this client because this client explicitly + * sets the version header on each request, overriding the default. + * + * @param properties + * Configures the service. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_getsetprops "Sample code for ServiceURL.setProperties")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesSetPropertiesResponse setProperties(StorageServiceProperties properties, Duration timeout) { + Mono response = storageAsyncRawClient.setProperties(properties); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link SASTokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * + * @return Emits the successful response. + */ + public ServicesGetUserDelegationKeyResponse getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry) { + return this.getUserDelegationKey(start, expiry, null); + } + + /** + * Gets a user delegation key for use with this account's blob storage. + * Note: This method call is only valid when using {@link SASTokenCredential} in this object's {@link HttpPipeline}. + * + * @param start + * Start time for the key's validity. Null indicates immediate start. + * @param expiry + * Expiration of the key's validity. + * + * @return Emits the successful response. + */ + public ServicesGetUserDelegationKeyResponse getUserDelegationKey(OffsetDateTime start, OffsetDateTime expiry, + Duration timeout) { + Mono response = storageAsyncRawClient.getUserDelegationKey(start, expiry); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetStatisticsResponse getStatistics() { + return this.getStatistics(null); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary + * location endpoint when read-access geo-redundant replication is enabled for the storage account. For more + * information, see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=service_stats "Sample code for ServiceURL.getStats")] \n + * For more samples, please see the [Samples file](%https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetStatisticsResponse getStatistics(Duration timeout) { + Mono response = storageAsyncRawClient.getStatistics(); + return Utility.blockWithOptionalTimeout(response, timeout); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetAccountInfoResponse getAccountInfo() { + return this.getAccountInfo(null); + } + + /** + * Returns the sku name and account kind for the account. For more information, please see the + * Azure Docs. + * + * @return Emits the successful response. + * + * @apiNote ## Sample Code \n + * [!code-java[Sample_Code](../azure-storage-java/src/test/java/com/microsoft/azure/storage/Samples.java?name=account_info "Sample code for ServiceURL.getAccountInfo")] \n + * For more samples, please see the [Samples file] (https://github.com/Azure/azure-storage-java/blob/master/src/test/java/com/microsoft/azure/storage/Samples.java) + */ + public ServicesGetAccountInfoResponse getAccountInfo(Duration timeout) { + Mono response = storageAsyncRawClient.getAccountInfo(); + return Utility.blockWithOptionalTimeout(response, timeout); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/URLParser.java b/storage/client/blob/src/main/java/com/azure/storage/blob/URLParser.java new file mode 100644 index 0000000000000..afc8539341a5d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/URLParser.java @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import java.net.URL; +import java.util.Comparator; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +/** + * A class used to conveniently parse URLs into {@link BlobURLParts} to modify the components of the URL. + */ +final class URLParser { + + /** + * URLParser parses a URL initializing BlobURLParts' fields including any SAS-related and snapshot query parameters. + * Any other query parameters remain in the UnparsedParams field. This method overwrites all fields in the + * BlobURLParts object. + * + * @param url + * The {@code URL} to be parsed. + * + * @return A {@link BlobURLParts} object containing all the components of a BlobURL. + */ + public static BlobURLParts parse(URL url) { + + final String scheme = url.getProtocol(); + final String host = url.getHost(); + + String containerName = null; + String blobName = null; + + // find the container & blob names (if any) + String path = url.getPath(); + if (!Utility.isNullOrEmpty(path)) { + // if the path starts with a slash remove it + if (path.charAt(0) == '/') { + path = path.substring(1); + } + + int containerEndIndex = path.indexOf('/'); + if (containerEndIndex == -1) { + // path contains only a container name and no blob name + containerName = path; + } else { + // path contains the container name up until the slash and blob name is everything after the slash + containerName = path.substring(0, containerEndIndex); + blobName = path.substring(containerEndIndex + 1); + } + } + Map queryParamsMap = parseQueryString(url.getQuery()); + + String snapshot = null; + String[] snapshotArray = queryParamsMap.get("snapshot"); + if (snapshotArray != null) { + snapshot = snapshotArray[0]; + queryParamsMap.remove("snapshot"); + } + + SASQueryParameters sasQueryParameters = new SASQueryParameters(queryParamsMap, true); + + return new BlobURLParts() + .scheme(scheme) + .host(host) + .containerName(containerName) + .blobName(blobName) + .snapshot(snapshot) + .sasQueryParameters(sasQueryParameters) + .unparsedParameters(queryParamsMap); + } + + /** + * Parses a query string into a one to many hashmap. + * + * @param queryParams + * The string of query params to parse. + * + * @return A {@code HashMap} of the key values. + */ + private static TreeMap parseQueryString(String queryParams) { + + final TreeMap retVals = new TreeMap(new Comparator() { + @Override + public int compare(String s1, String s2) { + return s1.compareTo(s2); + } + }); + + if (Utility.isNullOrEmpty(queryParams)) { + return retVals; + } + + // split name value pairs by splitting on the 'c&' character + final String[] valuePairs = queryParams.split("&"); + + // for each field value pair parse into appropriate map entries + for (int m = 0; m < valuePairs.length; m++) { + // Getting key and value for a single query parameter + final int equalDex = valuePairs[m].indexOf("="); + String key = Utility.safeURLDecode(valuePairs[m].substring(0, equalDex)).toLowerCase(Locale.ROOT); + String value = Utility.safeURLDecode(valuePairs[m].substring(equalDex + 1)); + + // add to map + String[] keyValues = retVals.get(key); + + // check if map already contains key + if (keyValues == null) { + // map does not contain this key + keyValues = new String[]{value}; + } else { + // map contains this key already so append + final String[] newValues = new String[keyValues.length + 1]; + for (int j = 0; j < keyValues.length; j++) { + newValues[j] = keyValues[j]; + } + + newValues[newValues.length - 1] = value; + keyValues = newValues; + } + retVals.put(key, keyValues); + } + + return retVals; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java b/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java new file mode 100644 index 0000000000000..3b5d073c4023e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/Utility.java @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpHeader; +import com.azure.core.http.HttpHeaders; +import com.azure.core.implementation.http.UrlBuilder; +import com.azure.storage.blob.models.StorageErrorException; +import com.azure.storage.blob.models.UserDelegationKey; +import reactor.core.publisher.Mono; +import reactor.util.annotation.Nullable; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Base64; +import java.util.Locale; + +final class Utility { + + static final DateTimeFormatter RFC_1123_GMT_DATE_FORMATTER = + DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ROOT).withZone(ZoneId.of("GMT")); + + static final DateTimeFormatter ISO_8601_UTC_DATE_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ROOT).withZone(ZoneId.of("UTC")); + /** + * Stores a reference to the UTC time zone. + */ + static final ZoneId UTC_ZONE = ZoneId.of("UTC"); + /** + * Stores a reference to the date/time pattern with the greatest precision Java.util.Date is capable of expressing. + */ + private static final String MAX_PRECISION_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS"; + /** + * Stores a reference to the ISO8601 date/time pattern. + */ + private static final String ISO8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + /** + * Stores a reference to the ISO8601 date/time pattern. + */ + private static final String ISO8601_PATTERN_NO_SECONDS = "yyyy-MM-dd'T'HH:mm'Z'"; + /** + * The length of a datestring that matches the MAX_PRECISION_PATTERN. + */ + private static final int MAX_PRECISION_DATESTRING_LENGTH = MAX_PRECISION_PATTERN.replaceAll("'", "").length(); + + /** + * Asserts that a value is not null. + * + * @param param + * A {@code String} that represents the name of the parameter, which becomes the exception message + * text if the value parameter is null. + * @param value + * An Object object that represents the value of the specified parameter. This is the value + * being asserted as not null. + */ + static void assertNotNull(final String param, final Object value) { + if (value == null) { + throw new IllegalArgumentException(String.format(Locale.ROOT, SR.ARGUMENT_NULL_OR_EMPTY, param)); + } + } + + /** + * Returns a value that indicates whether the specified string is null or empty. + * + * @param value + * A {@code String} being examined for null or empty. + * + * @return true if the specified value is null or empty; otherwise, false + */ + static boolean isNullOrEmpty(final String value) { + return value == null || value.length() == 0; + } + + /** + * Performs safe decoding of the specified string, taking care to preserve each + character, rather + * than replacing it with a space character. + * + * @param stringToDecode + * A {@code String} that represents the string to decode. + * + * @return A {@code String} that represents the decoded string. + */ + static String safeURLDecode(final String stringToDecode) { + if (stringToDecode.length() == 0) { + return Constants.EMPTY_STRING; + } + + // '+' are decoded as ' ' so preserve before decoding + if (stringToDecode.contains("+")) { + final StringBuilder outBuilder = new StringBuilder(); + + int startDex = 0; + for (int m = 0; m < stringToDecode.length(); m++) { + if (stringToDecode.charAt(m) == '+') { + if (m > startDex) { + try { + outBuilder.append(URLDecoder.decode(stringToDecode.substring(startDex, m), + Constants.UTF8_CHARSET)); + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + + outBuilder.append("+"); + startDex = m + 1; + } + } + + if (startDex != stringToDecode.length()) { + try { + outBuilder.append(URLDecoder.decode(stringToDecode.substring(startDex, stringToDecode.length()), + Constants.UTF8_CHARSET)); + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + + return outBuilder.toString(); + } else { + try { + return URLDecoder.decode(stringToDecode, Constants.UTF8_CHARSET); + } catch (UnsupportedEncodingException e) { + throw new Error(e); + } + } + } + + /** + * Given a String representing a date in a form of the ISO8601 pattern, generates a Date representing it + * with up to millisecond precision. + * + * @param dateString + * the {@code String} to be interpreted as a Date + * + * @return the corresponding Date object + * @throws IllegalArgumentException If {@code dateString} doesn't match an ISO8601 pattern + */ + public static OffsetDateTime parseDate(String dateString) { + String pattern = MAX_PRECISION_PATTERN; + switch (dateString.length()) { + case 28: // "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'"-> [2012-01-04T23:21:59.1234567Z] length = 28 + case 27: // "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"-> [2012-01-04T23:21:59.123456Z] length = 27 + case 26: // "yyyy-MM-dd'T'HH:mm:ss.SSSSS'Z'"-> [2012-01-04T23:21:59.12345Z] length = 26 + case 25: // "yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'"-> [2012-01-04T23:21:59.1234Z] length = 25 + case 24: // "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"-> [2012-01-04T23:21:59.123Z] length = 24 + dateString = dateString.substring(0, MAX_PRECISION_DATESTRING_LENGTH); + break; + case 23: // "yyyy-MM-dd'T'HH:mm:ss.SS'Z'"-> [2012-01-04T23:21:59.12Z] length = 23 + // SS is assumed to be milliseconds, so a trailing 0 is necessary + dateString = dateString.replace("Z", "0"); + break; + case 22: // "yyyy-MM-dd'T'HH:mm:ss.S'Z'"-> [2012-01-04T23:21:59.1Z] length = 22 + // S is assumed to be milliseconds, so trailing 0's are necessary + dateString = dateString.replace("Z", "00"); + break; + case 20: // "yyyy-MM-dd'T'HH:mm:ss'Z'"-> [2012-01-04T23:21:59Z] length = 20 + pattern = Utility.ISO8601_PATTERN; + break; + case 17: // "yyyy-MM-dd'T'HH:mm'Z'"-> [2012-01-04T23:21Z] length = 17 + pattern = Utility.ISO8601_PATTERN_NO_SECONDS; + break; + default: + throw new IllegalArgumentException(String.format(Locale.ROOT, SR.INVALID_DATE_STRING, dateString)); + } + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern, Locale.ROOT); + return LocalDateTime.parse(dateString, formatter).atZone(UTC_ZONE).toOffsetDateTime(); + } + + /** + * Asserts that the specified integer is in the valid range. + * + * @param param + * A String that represents the name of the parameter, which becomes the exception message + * text if the value parameter is out of bounds. + * @param value + * The value of the specified parameter. + * @param min + * The minimum value for the specified parameter. + * @param max + * The maximum value for the specified parameter. + * @throws IllegalArgumentException If {@code value} is less than {@code min} or greater than {@code max}. + */ + public static void assertInBounds(final String param, final long value, final long min, final long max) { + if (value < min || value > max) { + throw new IllegalArgumentException(String.format(Locale.ROOT, SR.PARAMETER_NOT_IN_RANGE, param, min, max)); + } + } + + /** + * Performs safe encoding of the specified string, taking care to insert %20 for each space character, + * instead of inserting the + character. + */ + static String safeURLEncode(final String stringToEncode) { + if (stringToEncode == null) { + return null; + } + if (stringToEncode.length() == 0) { + return Constants.EMPTY_STRING; + } + + try { + final String tString = URLEncoder.encode(stringToEncode, Constants.UTF8_CHARSET); + + if (stringToEncode.contains(" ")) { + final StringBuilder outBuilder = new StringBuilder(); + + int startDex = 0; + for (int m = 0; m < stringToEncode.length(); m++) { + if (stringToEncode.charAt(m) == ' ') { + if (m > startDex) { + outBuilder.append(URLEncoder.encode(stringToEncode.substring(startDex, m), + Constants.UTF8_CHARSET)); + } + + outBuilder.append("%20"); + startDex = m + 1; + } + } + + if (startDex != stringToEncode.length()) { + outBuilder.append(URLEncoder.encode(stringToEncode.substring(startDex, stringToEncode.length()), + Constants.UTF8_CHARSET)); + } + + return outBuilder.toString(); + } else { + return tString; + } + + } catch (final UnsupportedEncodingException e) { + throw new Error(e); // If we can't encode UTF-8, we fail. + } + } + + static Mono postProcessResponse(Mono s) { + s = addErrorWrappingToSingle(s); + s = scrubEtagHeaderInResponse(s); + return s; + } + + /* + We need to convert the generated StorageErrorException to StorageException, which has a cleaner interface and + methods to conveniently access important values. + */ + private static Mono addErrorWrappingToSingle(Mono s) { + return s.onErrorResume( + StorageErrorException.class, + e -> e.response() + .bodyAsString() + .switchIfEmpty(Mono.just("")) + .flatMap(body -> Mono.error(new StorageException(e, body)))); + } + + /* + The service is inconsistent in whether or not the etag header value has quotes. This method will check if the + response returns an etag value, and if it does, remove any quotes that may be present to give the user a more + predictable format to work with. + */ + private static Mono scrubEtagHeaderInResponse(Mono s) { + return s.map(response -> { + String etag = null; + try { + Object headers = response.getClass().getMethod("deserializedHeaders").invoke(response); + Method etagGetterMethod = headers.getClass().getMethod("eTag"); + etag = (String) etagGetterMethod.invoke(headers); + // CommitBlockListHeaders has an etag property, but it's only set if the blob has committed blocks. + if (etag == null) { + return response; + } + etag = etag.replace("\"", ""); // Etag headers without the quotes will be unaffected. + headers.getClass().getMethod("eTag", String.class).invoke(headers, etag); + } catch (NoSuchMethodException e) { + // Response did not return an eTag value. No change necessary. + } catch (IllegalAccessException | InvocationTargetException e) { + //TODO (unknown): validate this won't throw + } + try { + HttpHeaders rawHeaders = (HttpHeaders) response.getClass().getMethod("headers").invoke(response); + // + if (etag != null) { + rawHeaders.put("ETag", etag); + } else { + HttpHeader eTagHeader = rawHeaders.get("etag"); + if (eTagHeader != null && eTagHeader.value() != null) { + etag = eTagHeader.value().replace("\"", ""); + rawHeaders.put("ETag", etag); + } + } + } catch (NoSuchMethodException e) { + // Response did not return an eTag value. No change necessary. + } catch (IllegalAccessException | InvocationTargetException e) { + //TODO (unknown): validate this won't throw + } + return response; + }); + } + + /** + * Computes a signature for the specified string using the HMAC-SHA256 algorithm. + * + * @param delegate + * Key used to sign + * @param stringToSign + * The UTF-8-encoded string to sign. + * + * @return A {@code String} that contains the HMAC-SHA256-encoded signature. + * + * @throws InvalidKeyException + * If the accountKey is not a valid Base64-encoded string. + */ + static String delegateComputeHmac256(final UserDelegationKey delegate, String stringToSign) throws InvalidKeyException { + try { + byte[] key = Base64.getDecoder().decode(delegate.value()); + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(key, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + return Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + } catch (final NoSuchAlgorithmException e) { + throw new Error(e); + } + } + + /** + * Appends a string to the end of a URL's path (prefixing the string with a '/' if required). + * + * @param baseURL + * The url to which the name should be appended. + * @param name + * The name to be appended. + * + * @return A url with the name appended. + * + * @throws RuntimeException + * Appending the specified name produced an invalid URL. + */ + static URL appendToURLPath(URL baseURL, String name) { + UrlBuilder url = UrlBuilder.parse(baseURL); + if (url.path() == null) { + url.path("/"); // .path() will return null if it is empty, so we have to process separately from below. + } else if (url.path().charAt(url.path().length() - 1) != '/') { + url.path(url.path() + '/'); + } + url.path(url.path() + name); + try { + return url.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + static URL stripLastPathSegment(URL baseURL) { + UrlBuilder url = UrlBuilder.parse(baseURL); + if (url.path() != null || !url.path().contains("/")) { + throw new IllegalArgumentException(String.format("URL %s does not contain path segments", baseURL)); + } + + String newPath = url.path().substring(0, url.path().lastIndexOf('/')); + url.path(newPath); + try { + return url.toURL(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + static T blockWithOptionalTimeout(Mono response, @Nullable Duration timeout) { + if (timeout == null) { + return response.block(); + } else { + return response.block(timeout); + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AppendBlobsImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AppendBlobsImpl.java new file mode 100644 index 0000000000000..77a1c79599e38 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AppendBlobsImpl.java @@ -0,0 +1,378 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.PathParam; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.util.Base64Util; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.AppendBlobsAppendBlockFromUrlResponse; +import com.azure.storage.blob.models.AppendBlobsAppendBlockResponse; +import com.azure.storage.blob.models.AppendBlobsCreateResponse; +import com.azure.storage.blob.models.AppendPositionAccessConditions; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.EncryptionAlgorithmType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import com.azure.storage.blob.models.StorageErrorException; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * AppendBlobs. + */ +public final class AppendBlobsImpl { + /** + * The proxy service used to perform REST calls. + */ + private AppendBlobsService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of AppendBlobsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public AppendBlobsImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(AppendBlobsService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for AppendBlobs to be used by + * the proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs AppendBlob") + private interface AppendBlobsService { + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("Content-Length") long contentLength, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-blob-type") String blobType, @HeaderParam("x-ms-blob-content-type") String blobContentType, @HeaderParam("x-ms-blob-content-encoding") String blobContentEncoding, @HeaderParam("x-ms-blob-content-language") String blobContentLanguage, @HeaderParam("x-ms-blob-content-md5") String blobContentMD5, @HeaderParam("x-ms-blob-cache-control") String blobCacheControl, @HeaderParam("x-ms-blob-content-disposition") String blobContentDisposition, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono appendBlock(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @BodyParam("application/octet-stream") Flux body, @QueryParam("timeout") Integer timeout, @HeaderParam("Content-Length") long contentLength, @HeaderParam("Content-MD5") String transactionalContentMD5, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-blob-condition-maxsize") Long maxSize, @HeaderParam("x-ms-blob-condition-appendpos") Long appendPosition, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono appendBlockFromUrl(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-source-range") String sourceRange, @HeaderParam("x-ms-source-content-md5") String sourceContentMD5, @QueryParam("timeout") Integer timeout, @HeaderParam("Content-Length") long contentLength, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-blob-condition-maxsize") Long maxSize, @HeaderParam("x-ms-blob-condition-appendpos") Long appendPosition, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-source-if-modified-since") DateTimeRfc1123 sourceIfModifiedSince, @HeaderParam("x-ms-source-if-unmodified-since") DateTimeRfc1123 sourceIfUnmodifiedSince, @HeaderParam("x-ms-source-if-match") String sourceIfMatch, @HeaderParam("x-ms-source-if-none-match") String sourceIfNoneMatch, Context context); + } + + /** + * The Create Append Blob operation creates a new append blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, String blob, long contentLength, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String blobType = "AppendBlob"; + final String blobContentType = null; + final String blobContentEncoding = null; + final String blobContentLanguage = null; + final String blobCacheControl = null; + final String blobContentDisposition = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String blobContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.create(containerName, blob, this.client.url(), timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Create Append Blob operation creates a new append blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param blobHTTPHeaders Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, String blob, long contentLength, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, BlobHTTPHeaders blobHTTPHeaders, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String blobType = "AppendBlob"; + String blobContentType = null; + if (blobHTTPHeaders != null) { + blobContentType = blobHTTPHeaders.blobContentType(); + } + String blobContentEncoding = null; + if (blobHTTPHeaders != null) { + blobContentEncoding = blobHTTPHeaders.blobContentEncoding(); + } + String blobContentLanguage = null; + if (blobHTTPHeaders != null) { + blobContentLanguage = blobHTTPHeaders.blobContentLanguage(); + } + byte[] blobContentMD5 = null; + if (blobHTTPHeaders != null) { + blobContentMD5 = blobHTTPHeaders.blobContentMD5(); + } + String blobCacheControl = null; + if (blobHTTPHeaders != null) { + blobCacheControl = blobHTTPHeaders.blobCacheControl(); + } + String blobContentDisposition = null; + if (blobHTTPHeaders != null) { + blobContentDisposition = blobHTTPHeaders.blobContentDisposition(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String blobContentMD5Converted = Base64Util.encodeToString(blobContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.create(containerName, blob, this.client.url(), timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Append Block operation commits a new block of data to the end of an existing append blob. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono appendBlockWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, Context context) { + final Integer timeout = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "appendblock"; + final String leaseId = null; + final Long maxSize = null; + final Long appendPosition = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String transactionalContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.appendBlock(containerName, blob, this.client.url(), body, timeout, contentLength, transactionalContentMD5Converted, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, maxSize, appendPosition, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Append Block operation commits a new block of data to the end of an existing append blob. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param transactionalContentMD5 Specify the transactional md5 for the body, to be validated by the service. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param appendPositionAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono appendBlockWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, Integer timeout, byte[] transactionalContentMD5, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, AppendPositionAccessConditions appendPositionAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "appendblock"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + Long maxSize = null; + if (appendPositionAccessConditions != null) { + maxSize = appendPositionAccessConditions.maxSize(); + } + Long appendPosition = null; + if (appendPositionAccessConditions != null) { + appendPosition = appendPositionAccessConditions.appendPosition(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String transactionalContentMD5Converted = Base64Util.encodeToString(transactionalContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.appendBlock(containerName, blob, this.client.url(), body, timeout, contentLength, transactionalContentMD5Converted, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, maxSize, appendPosition, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Append Block operation commits a new block of data to the end of an existing append blob where the contents are read from a source url. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sourceUrl Specify a URL to the copy source. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono appendBlockFromUrlWithRestResponseAsync(String containerName, String blob, URL sourceUrl, long contentLength, Context context) { + final String sourceRange = null; + final Integer timeout = null; + final String requestId = null; + final String comp = "appendblock"; + final String leaseId = null; + final Long maxSize = null; + final Long appendPosition = null; + final String ifMatch = null; + final String ifNoneMatch = null; + final String sourceIfMatch = null; + final String sourceIfNoneMatch = null; + String sourceContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + DateTimeRfc1123 sourceIfModifiedSinceConverted = null; + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = null; + return service.appendBlockFromUrl(containerName, blob, this.client.url(), sourceUrl, sourceRange, sourceContentMD5Converted, timeout, contentLength, this.client.version(), requestId, comp, leaseId, maxSize, appendPosition, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } + + /** + * The Append Block operation commits a new block of data to the end of an existing append blob where the contents are read from a source url. The Append Block operation is permitted only if the blob was created with x-ms-blob-type set to AppendBlob. Append Block is supported only on version 2015-02-21 version or later. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sourceUrl Specify a URL to the copy source. + * @param contentLength The length of the request. + * @param sourceRange Bytes of source data in the specified range. + * @param sourceContentMD5 Specify the md5 calculated for the range of bytes that must be read from the copy source. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param appendPositionAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param sourceModifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono appendBlockFromUrlWithRestResponseAsync(String containerName, String blob, URL sourceUrl, long contentLength, String sourceRange, byte[] sourceContentMD5, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, AppendPositionAccessConditions appendPositionAccessConditions, ModifiedAccessConditions modifiedAccessConditions, SourceModifiedAccessConditions sourceModifiedAccessConditions, Context context) { + final String comp = "appendblock"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + Long maxSize = null; + if (appendPositionAccessConditions != null) { + maxSize = appendPositionAccessConditions.maxSize(); + } + Long appendPosition = null; + if (appendPositionAccessConditions != null) { + appendPosition = appendPositionAccessConditions.appendPosition(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + OffsetDateTime sourceIfModifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfModifiedSince = sourceModifiedAccessConditions.sourceIfModifiedSince(); + } + OffsetDateTime sourceIfUnmodifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfUnmodifiedSince = sourceModifiedAccessConditions.sourceIfUnmodifiedSince(); + } + String sourceIfMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfMatch = sourceModifiedAccessConditions.sourceIfMatch(); + } + String sourceIfNoneMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfNoneMatch = sourceModifiedAccessConditions.sourceIfNoneMatch(); + } + String sourceContentMD5Converted = Base64Util.encodeToString(sourceContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + DateTimeRfc1123 sourceIfModifiedSinceConverted = sourceIfModifiedSince == null ? null : new DateTimeRfc1123(sourceIfModifiedSince); + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = sourceIfUnmodifiedSince == null ? null : new DateTimeRfc1123(sourceIfUnmodifiedSince); + return service.appendBlockFromUrl(containerName, blob, this.client.url(), sourceUrl, sourceRange, sourceContentMD5Converted, timeout, contentLength, this.client.version(), requestId, comp, leaseId, maxSize, appendPosition, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageBuilder.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageBuilder.java new file mode 100644 index 0000000000000..c77d984c4e928 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageBuilder.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * A builder for creating a new instance of the AzureBlobStorage type. + */ +public final class AzureBlobStorageBuilder { + /* + * The URL of the service account, container, or blob that is the targe of the desired operation. + */ + private String url; + + /** + * Sets The URL of the service account, container, or blob that is the targe of the desired operation. + * + * @param url the url value. + * @return the AzureBlobStorageBuilder. + */ + public AzureBlobStorageBuilder url(String url) { + this.url = url; + return this; + } + + /* + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the AzureBlobStorageBuilder. + */ + public AzureBlobStorageBuilder version(String version) { + this.version = version; + return this; + } + + /* + * The HTTP pipeline to send requests through + */ + private HttpPipeline pipeline; + + /** + * Sets The HTTP pipeline to send requests through. + * + * @param pipeline the pipeline value. + * @return the AzureBlobStorageBuilder. + */ + public AzureBlobStorageBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + /** + * Builds an instance of AzureBlobStorageImpl with the provided parameters. + * + * @return an instance of AzureBlobStorageImpl. + */ + public AzureBlobStorageImpl build() { + if (version == null) { + this.version = "2018-11-09"; + } + if (pipeline == null) { + this.pipeline = RestProxy.createDefaultPipeline(); + } + AzureBlobStorageImpl client = new AzureBlobStorageImpl(pipeline); + if (this.url != null) { + client.url(this.url); + } + if (this.version != null) { + client.version(this.version); + } + return client; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageImpl.java new file mode 100644 index 0000000000000..6702b82da14ea --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/AzureBlobStorageImpl.java @@ -0,0 +1,170 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.ServiceClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * Initializes a new instance of the AzureBlobStorage type. + */ +public final class AzureBlobStorageImpl extends ServiceClient { + /** + * The URL of the service account, container, or blob that is the targe of the desired operation. + */ + private String url; + + /** + * Gets The URL of the service account, container, or blob that is the targe of the desired operation. + * + * @return the url value. + */ + public String url() { + return this.url; + } + + /** + * Sets The URL of the service account, container, or blob that is the targe of the desired operation. + * + * @param url the url value. + * @return the service client itself. + */ + AzureBlobStorageImpl url(String url) { + this.url = url; + return this; + } + + /** + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Gets Specifies the version of the operation to use for this request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the service client itself. + */ + AzureBlobStorageImpl version(String version) { + this.version = version; + return this; + } + + /** + * The ServicesImpl object to access its operations. + */ + private ServicesImpl services; + + /** + * Gets the ServicesImpl object to access its operations. + * + * @return the ServicesImpl object. + */ + public ServicesImpl services() { + return this.services; + } + + /** + * The ContainersImpl object to access its operations. + */ + private ContainersImpl containers; + + /** + * Gets the ContainersImpl object to access its operations. + * + * @return the ContainersImpl object. + */ + public ContainersImpl containers() { + return this.containers; + } + + /** + * The BlobsImpl object to access its operations. + */ + private BlobsImpl blobs; + + /** + * Gets the BlobsImpl object to access its operations. + * + * @return the BlobsImpl object. + */ + public BlobsImpl blobs() { + return this.blobs; + } + + /** + * The PageBlobsImpl object to access its operations. + */ + private PageBlobsImpl pageBlobs; + + /** + * Gets the PageBlobsImpl object to access its operations. + * + * @return the PageBlobsImpl object. + */ + public PageBlobsImpl pageBlobs() { + return this.pageBlobs; + } + + /** + * The AppendBlobsImpl object to access its operations. + */ + private AppendBlobsImpl appendBlobs; + + /** + * Gets the AppendBlobsImpl object to access its operations. + * + * @return the AppendBlobsImpl object. + */ + public AppendBlobsImpl appendBlobs() { + return this.appendBlobs; + } + + /** + * The BlockBlobsImpl object to access its operations. + */ + private BlockBlobsImpl blockBlobs; + + /** + * Gets the BlockBlobsImpl object to access its operations. + * + * @return the BlockBlobsImpl object. + */ + public BlockBlobsImpl blockBlobs() { + return this.blockBlobs; + } + + /** + * Initializes an instance of AzureBlobStorage client. + */ + public AzureBlobStorageImpl() { + this(RestProxy.createDefaultPipeline()); + } + + /** + * Initializes an instance of AzureBlobStorage client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + */ + public AzureBlobStorageImpl(HttpPipeline httpPipeline) { + super(httpPipeline); + this.services = new ServicesImpl(this); + this.containers = new ContainersImpl(this); + this.blobs = new BlobsImpl(this); + this.pageBlobs = new PageBlobsImpl(this); + this.appendBlobs = new AppendBlobsImpl(this); + this.blockBlobs = new BlockBlobsImpl(this); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlobsImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlobsImpl.java new file mode 100644 index 0000000000000..bcdb0de6a2d7f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlobsImpl.java @@ -0,0 +1,1211 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HEAD; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.PathParam; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.util.Base64Util; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.AccessTier; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlobsAbortCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsAcquireLeaseResponse; +import com.azure.storage.blob.models.BlobsBreakLeaseResponse; +import com.azure.storage.blob.models.BlobsChangeLeaseResponse; +import com.azure.storage.blob.models.BlobsCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsCreateSnapshotResponse; +import com.azure.storage.blob.models.BlobsDeleteResponse; +import com.azure.storage.blob.models.BlobsDownloadResponse; +import com.azure.storage.blob.models.BlobsGetAccountInfoResponse; +import com.azure.storage.blob.models.BlobsGetPropertiesResponse; +import com.azure.storage.blob.models.BlobsReleaseLeaseResponse; +import com.azure.storage.blob.models.BlobsRenewLeaseResponse; +import com.azure.storage.blob.models.BlobsSetHTTPHeadersResponse; +import com.azure.storage.blob.models.BlobsSetMetadataResponse; +import com.azure.storage.blob.models.BlobsSetTierResponse; +import com.azure.storage.blob.models.BlobsStartCopyFromURLResponse; +import com.azure.storage.blob.models.BlobsUndeleteResponse; +import com.azure.storage.blob.models.DeleteSnapshotsOptionType; +import com.azure.storage.blob.models.EncryptionAlgorithmType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import com.azure.storage.blob.models.StorageErrorException; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Blobs. + */ +public final class BlobsImpl { + /** + * The proxy service used to perform REST calls. + */ + private BlobsService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of BlobsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public BlobsImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(BlobsService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Blobs to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs") + private interface BlobsService { + @GET("{containerName}/{blob}") + @ExpectedResponses({200, 206}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono download(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-range-get-content-md5") Boolean rangeGetContentMD5, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @HEAD("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("timeout") Integer timeout, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @DELETE("{containerName}/{blob}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-delete-snapshots") DeleteSnapshotsOptionType deleteSnapshots, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono undelete(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setHTTPHeaders(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-blob-cache-control") String blobCacheControl, @HeaderParam("x-ms-blob-content-type") String blobContentType, @HeaderParam("x-ms-blob-content-md5") String blobContentMD5, @HeaderParam("x-ms-blob-content-encoding") String blobContentEncoding, @HeaderParam("x-ms-blob-content-language") String blobContentLanguage, @HeaderParam("x-ms-blob-content-disposition") String blobContentDisposition, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono acquireLease(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-duration") Integer duration, @HeaderParam("x-ms-proposed-lease-id") String proposedLeaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono releaseLease(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono renewLease(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono changeLease(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-proposed-lease-id") String proposedLeaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono breakLease(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-break-period") Integer breakPeriod, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono createSnapshot(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono startCopyFromURL(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-source-if-modified-since") DateTimeRfc1123 sourceIfModifiedSince, @HeaderParam("x-ms-source-if-unmodified-since") DateTimeRfc1123 sourceIfUnmodifiedSince, @HeaderParam("x-ms-source-if-match") String sourceIfMatch, @HeaderParam("x-ms-source-if-none-match") String sourceIfNoneMatch, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono copyFromURL(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-requires-sync") String xMsRequiresSync, @HeaderParam("x-ms-source-if-modified-since") DateTimeRfc1123 sourceIfModifiedSince, @HeaderParam("x-ms-source-if-unmodified-since") DateTimeRfc1123 sourceIfUnmodifiedSince, @HeaderParam("x-ms-source-if-match") String sourceIfMatch, @HeaderParam("x-ms-source-if-none-match") String sourceIfNoneMatch, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono abortCopyFromURL(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("copyid") String copyId, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-copy-action") String copyActionAbortConstant, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200, 202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setTier(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-access-tier") AccessTier tier, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @GET("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccountInfo(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + } + + /** + * The Download operation reads or downloads a blob from the system, including its metadata and properties. You can also call Download to read a snapshot or verison. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono downloadWithRestResponseAsync(String containerName, String blob, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final String range = null; + final Boolean rangeGetContentMD5 = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.download(containerName, blob, this.client.url(), snapshot, versionId, timeout, range, rangeGetContentMD5, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Download operation reads or downloads a blob from the system, including its metadata and properties. You can also call Download to read a snapshot or verison. + * + * @param containerName The container name. + * @param blob The blob name. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param range Return only the bytes of the blob in the specified range. + * @param rangeGetContentMD5 When set to true and specified together with the Range, the service returns the MD5 hash for the range, as long as the range is less than or equal to 4 MB in size. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono downloadWithRestResponseAsync(String containerName, String blob, String snapshot, String versionId, Integer timeout, String range, Boolean rangeGetContentMD5, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.download(containerName, blob, this.client.url(), snapshot, versionId, timeout, range, rangeGetContentMD5, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system properties for the blob. It does not return the content of the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String containerName, String blob, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.getProperties(containerName, blob, this.client.url(), snapshot, versionId, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Get Properties operation returns all user-defined metadata, standard HTTP properties, and system properties for the blob. It does not return the content of the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String containerName, String blob, String snapshot, String versionId, Integer timeout, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.getProperties(containerName, blob, this.client.url(), snapshot, versionId, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * If the storage account's soft delete feature is disabled then, when a blob is deleted, it is permanently removed from the storage account. If the storage account's soft delete feature is enabled, then, when a blob is deleted, it is marked for deletion and becomes inaccessible immediately. However, the storage service retains the blob or snapshot for the number of days specified by the DeleteRetentionPolicy section of [Storage service properties] (Set-Blob-Service-Properties.md). After the specified number of days has passed, the blob's data is permanently removed from the storage account. Note that you continue to be charged for the soft-deleted blob's storage until it is permanently removed. Use the List Blobs API and specify the "include=deleted" query parameter to discover which blobs and snapshots have been soft deleted. You can then use the Undelete Blob API to restore a soft-deleted blob. All other operations on a soft-deleted blob or snapshot causes the service to return an HTTP status code of 404 (ResourceNotFound). If the storage account's automatic snapshot feature is enabled, then, when a blob is deleted, an automatic snapshot is created. The blob becomes inaccessible immediately. All other operations on the blob causes the service to return an HTTP status code of 404 (ResourceNotFound). You can access automatic snapshot using snapshot timestamp or version id. You can restore the blob by calling Put or Copy Blob API with automatic snapshot as source. Deleting automatic snapshot requires shared key or special SAS/RBAC permissions. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String containerName, String blob, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final DeleteSnapshotsOptionType deleteSnapshots = null; + final String requestId = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.delete(containerName, blob, this.client.url(), snapshot, versionId, timeout, deleteSnapshots, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * If the storage account's soft delete feature is disabled then, when a blob is deleted, it is permanently removed from the storage account. If the storage account's soft delete feature is enabled, then, when a blob is deleted, it is marked for deletion and becomes inaccessible immediately. However, the storage service retains the blob or snapshot for the number of days specified by the DeleteRetentionPolicy section of [Storage service properties] (Set-Blob-Service-Properties.md). After the specified number of days has passed, the blob's data is permanently removed from the storage account. Note that you continue to be charged for the soft-deleted blob's storage until it is permanently removed. Use the List Blobs API and specify the "include=deleted" query parameter to discover which blobs and snapshots have been soft deleted. You can then use the Undelete Blob API to restore a soft-deleted blob. All other operations on a soft-deleted blob or snapshot causes the service to return an HTTP status code of 404 (ResourceNotFound). If the storage account's automatic snapshot feature is enabled, then, when a blob is deleted, an automatic snapshot is created. The blob becomes inaccessible immediately. All other operations on the blob causes the service to return an HTTP status code of 404 (ResourceNotFound). You can access automatic snapshot using snapshot timestamp or version id. You can restore the blob by calling Put or Copy Blob API with automatic snapshot as source. Deleting automatic snapshot requires shared key or special SAS/RBAC permissions. + * + * @param containerName The container name. + * @param blob The blob name. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param deleteSnapshots Required if the blob has associated snapshots. Specify one of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's snapshots and not the blob itself. Possible values include: 'include', 'only'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String containerName, String blob, String snapshot, String versionId, Integer timeout, DeleteSnapshotsOptionType deleteSnapshots, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.delete(containerName, blob, this.client.url(), snapshot, versionId, timeout, deleteSnapshots, this.client.version(), requestId, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * Undelete a blob that was previously soft deleted. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono undeleteWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "undelete"; + return service.undelete(containerName, blob, this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * Undelete a blob that was previously soft deleted. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono undeleteWithRestResponseAsync(String containerName, String blob, Integer timeout, String requestId, Context context) { + final String comp = "undelete"; + return service.undelete(containerName, blob, this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * The Set HTTP Headers operation sets system properties on the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setHTTPHeadersWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "properties"; + final String blobCacheControl = null; + final String blobContentType = null; + final String blobContentEncoding = null; + final String blobContentLanguage = null; + final String blobContentDisposition = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String blobContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.setHTTPHeaders(containerName, blob, this.client.url(), timeout, this.client.version(), requestId, comp, blobCacheControl, blobContentType, blobContentMD5Converted, blobContentEncoding, blobContentLanguage, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Set HTTP Headers operation sets system properties on the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param blobHTTPHeaders Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setHTTPHeadersWithRestResponseAsync(String containerName, String blob, Integer timeout, String requestId, BlobHTTPHeaders blobHTTPHeaders, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "properties"; + String blobCacheControl = null; + if (blobHTTPHeaders != null) { + blobCacheControl = blobHTTPHeaders.blobCacheControl(); + } + String blobContentType = null; + if (blobHTTPHeaders != null) { + blobContentType = blobHTTPHeaders.blobContentType(); + } + byte[] blobContentMD5 = null; + if (blobHTTPHeaders != null) { + blobContentMD5 = blobHTTPHeaders.blobContentMD5(); + } + String blobContentEncoding = null; + if (blobHTTPHeaders != null) { + blobContentEncoding = blobHTTPHeaders.blobContentEncoding(); + } + String blobContentLanguage = null; + if (blobHTTPHeaders != null) { + blobContentLanguage = blobHTTPHeaders.blobContentLanguage(); + } + String blobContentDisposition = null; + if (blobHTTPHeaders != null) { + blobContentDisposition = blobHTTPHeaders.blobContentDisposition(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String blobContentMD5Converted = Base64Util.encodeToString(blobContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.setHTTPHeaders(containerName, blob, this.client.url(), timeout, this.client.version(), requestId, comp, blobCacheControl, blobContentType, blobContentMD5Converted, blobContentEncoding, blobContentLanguage, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Set Blob Metadata operation sets user-defined metadata for the specified blob as one or more name-value pairs. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "metadata"; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.setMetadata(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Set Blob Metadata operation sets user-defined metadata for the specified blob as one or more name-value pairs. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(String containerName, String blob, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "metadata"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.setMetadata(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono acquireLeaseWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final Integer duration = null; + final String proposedLeaseId = null; + final String requestId = null; + final String comp = "lease"; + final String action = "acquire"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.acquireLease(containerName, blob, this.client.url(), timeout, duration, proposedLeaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param duration Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono acquireLeaseWithRestResponseAsync(String containerName, String blob, Integer timeout, Integer duration, String proposedLeaseId, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String action = "acquire"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.acquireLease(containerName, blob, this.client.url(), timeout, duration, proposedLeaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono releaseLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String action = "release"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.releaseLease(containerName, blob, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono releaseLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String action = "release"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.releaseLease(containerName, blob, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono renewLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String action = "renew"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.renewLease(containerName, blob, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono renewLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String action = "renew"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.renewLease(containerName, blob, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono changeLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, String proposedLeaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String action = "change"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.changeLease(containerName, blob, this.client.url(), timeout, leaseId, proposedLeaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param leaseId Specifies the current lease ID on the resource. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono changeLeaseWithRestResponseAsync(String containerName, String blob, String leaseId, String proposedLeaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String action = "change"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.changeLease(containerName, blob, this.client.url(), timeout, leaseId, proposedLeaseId, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono breakLeaseWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final Integer breakPeriod = null; + final String requestId = null; + final String comp = "lease"; + final String action = "break"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.breakLease(containerName, blob, this.client.url(), timeout, breakPeriod, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete operations. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param breakPeriod For a break operation, proposed duration the lease should continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available before the break period has expired, but the lease may be held for longer than the break period. If this header does not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an infinite lease breaks immediately. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono breakLeaseWithRestResponseAsync(String containerName, String blob, Integer timeout, Integer breakPeriod, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String action = "break"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.breakLease(containerName, blob, this.client.url(), timeout, breakPeriod, this.client.version(), requestId, comp, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Create Snapshot operation creates a read-only snapshot of a blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createSnapshotWithRestResponseAsync(String containerName, String blob, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "snapshot"; + final String ifMatch = null; + final String ifNoneMatch = null; + final String leaseId = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.createSnapshot(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Create Snapshot operation creates a read-only snapshot of a blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createSnapshotWithRestResponseAsync(String containerName, String blob, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, ModifiedAccessConditions modifiedAccessConditions, LeaseAccessConditions leaseAccessConditions, Context context) { + final String comp = "snapshot"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.createSnapshot(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Start Copy From URL operation copies a blob or an internet resource to a new blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono startCopyFromURLWithRestResponseAsync(String containerName, String blob, URL copySource, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String requestId = null; + final String sourceIfMatch = null; + final String sourceIfNoneMatch = null; + final String ifMatch = null; + final String ifNoneMatch = null; + final String leaseId = null; + DateTimeRfc1123 sourceIfModifiedSinceConverted = null; + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.startCopyFromURL(containerName, blob, this.client.url(), timeout, metadata, copySource, this.client.version(), requestId, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Start Copy From URL operation copies a blob or an internet resource to a new blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param sourceModifiedAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono startCopyFromURLWithRestResponseAsync(String containerName, String blob, URL copySource, Integer timeout, Map metadata, String requestId, SourceModifiedAccessConditions sourceModifiedAccessConditions, ModifiedAccessConditions modifiedAccessConditions, LeaseAccessConditions leaseAccessConditions, Context context) { + OffsetDateTime sourceIfModifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfModifiedSince = sourceModifiedAccessConditions.sourceIfModifiedSince(); + } + OffsetDateTime sourceIfUnmodifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfUnmodifiedSince = sourceModifiedAccessConditions.sourceIfUnmodifiedSince(); + } + String sourceIfMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfMatch = sourceModifiedAccessConditions.sourceIfMatch(); + } + String sourceIfNoneMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfNoneMatch = sourceModifiedAccessConditions.sourceIfNoneMatch(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + DateTimeRfc1123 sourceIfModifiedSinceConverted = sourceIfModifiedSince == null ? null : new DateTimeRfc1123(sourceIfModifiedSince); + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = sourceIfUnmodifiedSince == null ? null : new DateTimeRfc1123(sourceIfUnmodifiedSince); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.startCopyFromURL(containerName, blob, this.client.url(), timeout, metadata, copySource, this.client.version(), requestId, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Copy From URL operation copies a blob or an internet resource to a new blob. It will not return a response until the copy is complete. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono copyFromURLWithRestResponseAsync(String containerName, String blob, URL copySource, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String requestId = null; + final String xMsRequiresSync = "true"; + final String sourceIfMatch = null; + final String sourceIfNoneMatch = null; + final String ifMatch = null; + final String ifNoneMatch = null; + final String leaseId = null; + DateTimeRfc1123 sourceIfModifiedSinceConverted = null; + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.copyFromURL(containerName, blob, this.client.url(), timeout, metadata, copySource, this.client.version(), requestId, xMsRequiresSync, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Copy From URL operation copies a blob or an internet resource to a new blob. It will not return a response until the copy is complete. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param sourceModifiedAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono copyFromURLWithRestResponseAsync(String containerName, String blob, URL copySource, Integer timeout, Map metadata, String requestId, SourceModifiedAccessConditions sourceModifiedAccessConditions, ModifiedAccessConditions modifiedAccessConditions, LeaseAccessConditions leaseAccessConditions, Context context) { + final String xMsRequiresSync = "true"; + OffsetDateTime sourceIfModifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfModifiedSince = sourceModifiedAccessConditions.sourceIfModifiedSince(); + } + OffsetDateTime sourceIfUnmodifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfUnmodifiedSince = sourceModifiedAccessConditions.sourceIfUnmodifiedSince(); + } + String sourceIfMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfMatch = sourceModifiedAccessConditions.sourceIfMatch(); + } + String sourceIfNoneMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfNoneMatch = sourceModifiedAccessConditions.sourceIfNoneMatch(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + DateTimeRfc1123 sourceIfModifiedSinceConverted = sourceIfModifiedSince == null ? null : new DateTimeRfc1123(sourceIfModifiedSince); + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = sourceIfUnmodifiedSince == null ? null : new DateTimeRfc1123(sourceIfUnmodifiedSince); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.copyFromURL(containerName, blob, this.client.url(), timeout, metadata, copySource, this.client.version(), requestId, xMsRequiresSync, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, leaseId, context); + } + + /** + * The Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a destination blob with zero length and full metadata. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copyId The copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono abortCopyFromURLWithRestResponseAsync(String containerName, String blob, String copyId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "copy"; + final String copyActionAbortConstant = "abort"; + final String leaseId = null; + return service.abortCopyFromURL(containerName, blob, this.client.url(), copyId, timeout, this.client.version(), requestId, comp, copyActionAbortConstant, leaseId, context); + } + + /** + * The Abort Copy From URL operation aborts a pending Copy From URL operation, and leaves a destination blob with zero length and full metadata. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copyId The copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono abortCopyFromURLWithRestResponseAsync(String containerName, String blob, String copyId, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String comp = "copy"; + final String copyActionAbortConstant = "abort"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + return service.abortCopyFromURL(containerName, blob, this.client.url(), copyId, timeout, this.client.version(), requestId, comp, copyActionAbortConstant, leaseId, context); + } + + /** + * The Set Tier operation sets the tier on a blob. The operation is allowed on a page blob in a premium storage account and on a block blob in a blob storage account (locally redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation does not update the blob's ETag. + * + * @param containerName The container name. + * @param blob The blob name. + * @param tier Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', 'P10', 'P20', 'P30', 'P40', 'P50', 'Hot', 'Cool', 'Archive'. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setTierWithRestResponseAsync(String containerName, String blob, AccessTier tier, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "tier"; + final String leaseId = null; + return service.setTier(containerName, blob, this.client.url(), timeout, tier, this.client.version(), requestId, comp, leaseId, context); + } + + /** + * The Set Tier operation sets the tier on a blob. The operation is allowed on a page blob in a premium storage account and on a block blob in a blob storage account (locally redundant storage only). A premium page blob's tier determines the allowed size, IOPS, and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation does not update the blob's ETag. + * + * @param containerName The container name. + * @param blob The blob name. + * @param tier Indicates the tier to be set on the blob. Possible values include: 'P4', 'P6', 'P10', 'P20', 'P30', 'P40', 'P50', 'Hot', 'Cool', 'Archive'. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setTierWithRestResponseAsync(String containerName, String blob, AccessTier tier, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String comp = "tier"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + return service.setTier(containerName, blob, this.client.url(), timeout, tier, this.client.version(), requestId, comp, leaseId, context); + } + + /** + * Returns the sku name and account kind. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccountInfoWithRestResponseAsync(String containerName, String blob, Context context) { + final String restype = "account"; + final String comp = "properties"; + return service.getAccountInfo(containerName, blob, this.client.url(), this.client.version(), restype, comp, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlockBlobsImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlockBlobsImpl.java new file mode 100644 index 0000000000000..2c4645d2bd4bc --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/BlockBlobsImpl.java @@ -0,0 +1,483 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.PathParam; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.util.Base64Util; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.BlockBlobsCommitBlockListResponse; +import com.azure.storage.blob.models.BlockBlobsGetBlockListResponse; +import com.azure.storage.blob.models.BlockBlobsStageBlockFromURLResponse; +import com.azure.storage.blob.models.BlockBlobsStageBlockResponse; +import com.azure.storage.blob.models.BlockBlobsUploadResponse; +import com.azure.storage.blob.models.BlockListType; +import com.azure.storage.blob.models.BlockLookupList; +import com.azure.storage.blob.models.EncryptionAlgorithmType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import com.azure.storage.blob.models.StorageErrorException; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * BlockBlobs. + */ +public final class BlockBlobsImpl { + /** + * The proxy service used to perform REST calls. + */ + private BlockBlobsService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of BlockBlobsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public BlockBlobsImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(BlockBlobsService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for BlockBlobs to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs BlockBlob") + private interface BlockBlobsService { + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono upload(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @BodyParam("application/octet-stream") Flux body, @QueryParam("timeout") Integer timeout, @HeaderParam("Content-Length") long contentLength, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-blob-type") String blobType, @HeaderParam("x-ms-blob-content-type") String blobContentType, @HeaderParam("x-ms-blob-content-encoding") String blobContentEncoding, @HeaderParam("x-ms-blob-content-language") String blobContentLanguage, @HeaderParam("x-ms-blob-content-md5") String blobContentMD5, @HeaderParam("x-ms-blob-cache-control") String blobCacheControl, @HeaderParam("x-ms-blob-content-disposition") String blobContentDisposition, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono stageBlock(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("blockid") String blockId, @HeaderParam("Content-Length") long contentLength, @HeaderParam("Content-MD5") String transactionalContentMD5, @BodyParam("application/octet-stream") Flux body, @QueryParam("timeout") Integer timeout, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono stageBlockFromURL(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("blockid") String blockId, @HeaderParam("Content-Length") long contentLength, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-source-range") String sourceRange, @HeaderParam("x-ms-source-content-md5") String sourceContentMD5, @QueryParam("timeout") Integer timeout, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-source-if-modified-since") DateTimeRfc1123 sourceIfModifiedSince, @HeaderParam("x-ms-source-if-unmodified-since") DateTimeRfc1123 sourceIfUnmodifiedSince, @HeaderParam("x-ms-source-if-match") String sourceIfMatch, @HeaderParam("x-ms-source-if-none-match") String sourceIfNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono commitBlockList(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @BodyParam("application/xml; charset=utf-8") BlockLookupList blocks, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-blob-cache-control") String blobCacheControl, @HeaderParam("x-ms-blob-content-type") String blobContentType, @HeaderParam("x-ms-blob-content-encoding") String blobContentEncoding, @HeaderParam("x-ms-blob-content-language") String blobContentLanguage, @HeaderParam("x-ms-blob-content-md5") String blobContentMD5, @HeaderParam("x-ms-blob-content-disposition") String blobContentDisposition, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @GET("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getBlockList(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("blocklisttype") BlockListType listType, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + } + + /** + * The Upload Block Blob operation updates the content of an existing block blob. Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a block blob, use the Put Block List operation. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String blobType = "BlockBlob"; + final String blobContentType = null; + final String blobContentEncoding = null; + final String blobContentLanguage = null; + final String blobCacheControl = null; + final String blobContentDisposition = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String blobContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.upload(containerName, blob, this.client.url(), body, timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Upload Block Blob operation updates the content of an existing block blob. Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a block blob, use the Put Block List operation. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param blobHTTPHeaders Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, BlobHTTPHeaders blobHTTPHeaders, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String blobType = "BlockBlob"; + String blobContentType = null; + if (blobHTTPHeaders != null) { + blobContentType = blobHTTPHeaders.blobContentType(); + } + String blobContentEncoding = null; + if (blobHTTPHeaders != null) { + blobContentEncoding = blobHTTPHeaders.blobContentEncoding(); + } + String blobContentLanguage = null; + if (blobHTTPHeaders != null) { + blobContentLanguage = blobHTTPHeaders.blobContentLanguage(); + } + byte[] blobContentMD5 = null; + if (blobHTTPHeaders != null) { + blobContentMD5 = blobHTTPHeaders.blobContentMD5(); + } + String blobCacheControl = null; + if (blobHTTPHeaders != null) { + blobCacheControl = blobHTTPHeaders.blobCacheControl(); + } + String blobContentDisposition = null; + if (blobHTTPHeaders != null) { + blobContentDisposition = blobHTTPHeaders.blobContentDisposition(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String blobContentMD5Converted = Base64Util.encodeToString(blobContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.upload(containerName, blob, this.client.url(), body, timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Stage Block operation creates a new block to be committed as part of a blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the same size for each block. + * @param contentLength The length of the request. + * @param body Initial data. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono stageBlockWithRestResponseAsync(String containerName, String blob, String blockId, long contentLength, Flux body, Context context) { + final Integer timeout = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "block"; + final String leaseId = null; + String transactionalContentMD5Converted = null; + return service.stageBlock(containerName, blob, this.client.url(), blockId, contentLength, transactionalContentMD5Converted, body, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, context); + } + + /** + * The Stage Block operation creates a new block to be committed as part of a blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the same size for each block. + * @param contentLength The length of the request. + * @param body Initial data. + * @param transactionalContentMD5 Specify the transactional md5 for the body, to be validated by the service. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono stageBlockWithRestResponseAsync(String containerName, String blob, String blockId, long contentLength, Flux body, byte[] transactionalContentMD5, Integer timeout, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String comp = "block"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + String transactionalContentMD5Converted = Base64Util.encodeToString(transactionalContentMD5); + return service.stageBlock(containerName, blob, this.client.url(), blockId, contentLength, transactionalContentMD5Converted, body, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, context); + } + + /** + * The Stage Block operation creates a new block to be committed as part of a blob where the contents are read from a URL. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the same size for each block. + * @param contentLength The length of the request. + * @param sourceUrl Specify a URL to the copy source. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono stageBlockFromURLWithRestResponseAsync(String containerName, String blob, String blockId, long contentLength, URL sourceUrl, Context context) { + final String sourceRange = null; + final Integer timeout = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "block"; + final String leaseId = null; + final String sourceIfMatch = null; + final String sourceIfNoneMatch = null; + String sourceContentMD5Converted = null; + DateTimeRfc1123 sourceIfModifiedSinceConverted = null; + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = null; + return service.stageBlockFromURL(containerName, blob, this.client.url(), blockId, contentLength, sourceUrl, sourceRange, sourceContentMD5Converted, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } + + /** + * The Stage Block operation creates a new block to be committed as part of a blob where the contents are read from a URL. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blockId A valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the same size for each block. + * @param contentLength The length of the request. + * @param sourceUrl Specify a URL to the copy source. + * @param sourceRange Bytes of source data in the specified range. + * @param sourceContentMD5 Specify the md5 calculated for the range of bytes that must be read from the copy source. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param sourceModifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono stageBlockFromURLWithRestResponseAsync(String containerName, String blob, String blockId, long contentLength, URL sourceUrl, String sourceRange, byte[] sourceContentMD5, Integer timeout, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, SourceModifiedAccessConditions sourceModifiedAccessConditions, Context context) { + final String comp = "block"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime sourceIfModifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfModifiedSince = sourceModifiedAccessConditions.sourceIfModifiedSince(); + } + OffsetDateTime sourceIfUnmodifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfUnmodifiedSince = sourceModifiedAccessConditions.sourceIfUnmodifiedSince(); + } + String sourceIfMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfMatch = sourceModifiedAccessConditions.sourceIfMatch(); + } + String sourceIfNoneMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfNoneMatch = sourceModifiedAccessConditions.sourceIfNoneMatch(); + } + String sourceContentMD5Converted = Base64Util.encodeToString(sourceContentMD5); + DateTimeRfc1123 sourceIfModifiedSinceConverted = sourceIfModifiedSince == null ? null : new DateTimeRfc1123(sourceIfModifiedSince); + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = sourceIfUnmodifiedSince == null ? null : new DateTimeRfc1123(sourceIfUnmodifiedSince); + return service.stageBlockFromURL(containerName, blob, this.client.url(), blockId, contentLength, sourceUrl, sourceRange, sourceContentMD5Converted, timeout, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, leaseId, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } + + /** + * The Commit Block List operation writes a blob by specifying the list of block IDs that make up the blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior Put Block operation. You can call Put Block List to update a blob by uploading only those blocks that have changed, then committing the new and existing blocks together. You can do this by specifying whether to commit a block from the committed block list or from the uncommitted block list, or to commit the most recently uploaded version of the block, whichever list it may belong to. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blocks the BlockLookupList value. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono commitBlockListWithRestResponseAsync(String containerName, String blob, BlockLookupList blocks, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "blocklist"; + final String blobCacheControl = null; + final String blobContentType = null; + final String blobContentEncoding = null; + final String blobContentLanguage = null; + final String blobContentDisposition = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String blobContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.commitBlockList(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, blocks, this.client.version(), requestId, comp, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Commit Block List operation writes a blob by specifying the list of block IDs that make up the blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior Put Block operation. You can call Put Block List to update a blob by uploading only those blocks that have changed, then committing the new and existing blocks together. You can do this by specifying whether to commit a block from the committed block list or from the uncommitted block list, or to commit the most recently uploaded version of the block, whichever list it may belong to. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blocks the BlockLookupList value. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param blobHTTPHeaders Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono commitBlockListWithRestResponseAsync(String containerName, String blob, BlockLookupList blocks, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, BlobHTTPHeaders blobHTTPHeaders, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "blocklist"; + String blobCacheControl = null; + if (blobHTTPHeaders != null) { + blobCacheControl = blobHTTPHeaders.blobCacheControl(); + } + String blobContentType = null; + if (blobHTTPHeaders != null) { + blobContentType = blobHTTPHeaders.blobContentType(); + } + String blobContentEncoding = null; + if (blobHTTPHeaders != null) { + blobContentEncoding = blobHTTPHeaders.blobContentEncoding(); + } + String blobContentLanguage = null; + if (blobHTTPHeaders != null) { + blobContentLanguage = blobHTTPHeaders.blobContentLanguage(); + } + byte[] blobContentMD5 = null; + if (blobHTTPHeaders != null) { + blobContentMD5 = blobHTTPHeaders.blobContentMD5(); + } + String blobContentDisposition = null; + if (blobHTTPHeaders != null) { + blobContentDisposition = blobHTTPHeaders.blobContentDisposition(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String blobContentMD5Converted = Base64Util.encodeToString(blobContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.commitBlockList(containerName, blob, this.client.url(), timeout, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, blocks, this.client.version(), requestId, comp, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Get Block List operation retrieves the list of blocks that have been uploaded as part of a block blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param listType Specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists together. Possible values include: 'committed', 'uncommitted', 'all'. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getBlockListWithRestResponseAsync(String containerName, String blob, BlockListType listType, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final String requestId = null; + final String comp = "blocklist"; + final String leaseId = null; + return service.getBlockList(containerName, blob, this.client.url(), snapshot, versionId, listType, timeout, this.client.version(), requestId, comp, leaseId, context); + } + + /** + * The Get Block List operation retrieves the list of blocks that have been uploaded as part of a block blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param listType Specifies whether to return the list of committed blocks, the list of uncommitted blocks, or both lists together. Possible values include: 'committed', 'uncommitted', 'all'. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getBlockListWithRestResponseAsync(String containerName, String blob, BlockListType listType, String snapshot, String versionId, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String comp = "blocklist"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + return service.getBlockList(containerName, blob, this.client.url(), snapshot, versionId, listType, timeout, this.client.version(), requestId, comp, leaseId, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ContainersImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ContainersImpl.java new file mode 100644 index 0000000000000..780b3a356a619 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ContainersImpl.java @@ -0,0 +1,759 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.PathParam; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.CollectionFormat; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.serializer.jackson.JacksonAdapter; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.ContainersAcquireLeaseResponse; +import com.azure.storage.blob.models.ContainersBreakLeaseResponse; +import com.azure.storage.blob.models.ContainersChangeLeaseResponse; +import com.azure.storage.blob.models.ContainersCreateResponse; +import com.azure.storage.blob.models.ContainersDeleteResponse; +import com.azure.storage.blob.models.ContainersGetAccessPolicyResponse; +import com.azure.storage.blob.models.ContainersGetAccountInfoResponse; +import com.azure.storage.blob.models.ContainersGetPropertiesResponse; +import com.azure.storage.blob.models.ContainersListBlobFlatSegmentResponse; +import com.azure.storage.blob.models.ContainersListBlobHierarchySegmentResponse; +import com.azure.storage.blob.models.ContainersReleaseLeaseResponse; +import com.azure.storage.blob.models.ContainersRenewLeaseResponse; +import com.azure.storage.blob.models.ContainersSetAccessPolicyResponse; +import com.azure.storage.blob.models.ContainersSetMetadataResponse; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ListBlobsIncludeItem; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PublicAccessType; +import com.azure.storage.blob.models.SignedIdentifier; +import com.azure.storage.blob.models.StorageErrorException; +import reactor.core.publisher.Mono; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Containers. + */ +public final class ContainersImpl { + /** + * The proxy service used to perform REST calls. + */ + private ContainersService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of ContainersImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public ContainersImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(ContainersService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Containers to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs Containers") + private interface ContainersService { + @PUT("{containerName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-blob-public-access") PublicAccessType access, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, Context context); + + @GET("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @DELETE("{containerName}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, Context context); + + @GET("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccessPolicy(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, Context context); + + @PUT("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setAccessPolicy(@PathParam("containerName") String containerName, @HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") SignedIdentifiersWrapper containerAcl, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-blob-public-access") PublicAccessType access, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono acquireLease(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-duration") Integer duration, @HeaderParam("x-ms-proposed-lease-id") String proposedLeaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono releaseLease(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono renewLease(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono breakLease(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-break-period") Integer breakPeriod, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @PUT("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono changeLease(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-proposed-lease-id") String proposedLeaseId, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @QueryParam("restype") String restype, @HeaderParam("x-ms-lease-action") String action, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, Context context); + + @GET("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listBlobFlatSegment(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("include") String include, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listBlobHierarchySegment(@PathParam("containerName") String containerName, @HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("delimiter") String delimiter, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("include") String include, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{containerName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccountInfo(@PathParam("containerName") String containerName, @HostParam("url") String url, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + } + + /** + * creates a new container under the specified account. If the container with the same name already exists, the operation fails. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final Map metadata = null; + final PublicAccessType access = null; + final String requestId = null; + final String restype = "container"; + return service.create(containerName, this.client.url(), timeout, metadata, access, this.client.version(), requestId, restype, context); + } + + /** + * creates a new container under the specified account. If the container with the same name already exists, the operation fails. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param access Specifies whether data in the container may be accessed publicly and the level of access. Possible values include: 'container', 'blob'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, Integer timeout, Map metadata, PublicAccessType access, String requestId, Context context) { + final String restype = "container"; + return service.create(containerName, this.client.url(), timeout, metadata, access, this.client.version(), requestId, restype, context); + } + + /** + * returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "container"; + final String leaseId = null; + return service.getProperties(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, leaseId, context); + } + + /** + * returns all user-defined metadata and system properties for the specified container. The data returned does not include the container's list of blobs. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String containerName, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String restype = "container"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + return service.getProperties(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, leaseId, context); + } + + /** + * operation marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "container"; + final String leaseId = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.delete(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * operation marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String containerName, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String restype = "container"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.delete(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * operation sets one or more user-defined name-value pairs for the specified container. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String requestId = null; + final String restype = "container"; + final String comp = "metadata"; + final String leaseId = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + return service.setMetadata(containerName, this.client.url(), timeout, metadata, this.client.version(), requestId, restype, comp, leaseId, ifModifiedSinceConverted, context); + } + + /** + * operation sets one or more user-defined name-value pairs for the specified container. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(String containerName, Integer timeout, Map metadata, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String restype = "container"; + final String comp = "metadata"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + return service.setMetadata(containerName, this.client.url(), timeout, metadata, this.client.version(), requestId, restype, comp, leaseId, ifModifiedSinceConverted, context); + } + + /** + * gets the permissions for the specified container. The permissions indicate whether container data may be accessed publicly. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "container"; + final String comp = "acl"; + final String leaseId = null; + return service.getAccessPolicy(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, comp, leaseId, context); + } + + /** + * gets the permissions for the specified container. The permissions indicate whether container data may be accessed publicly. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(String containerName, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, Context context) { + final String restype = "container"; + final String comp = "acl"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + return service.getAccessPolicy(containerName, this.client.url(), timeout, this.client.version(), requestId, restype, comp, leaseId, context); + } + + /** + * sets the permissions for the specified container. The permissions indicate whether blobs in a container may be accessed publicly. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final PublicAccessType access = null; + final String requestId = null; + final String restype = "container"; + final String comp = "acl"; + final String leaseId = null; + SignedIdentifiersWrapper containerAclConverted = new SignedIdentifiersWrapper(null); + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.setAccessPolicy(containerName, this.client.url(), containerAclConverted, timeout, access, this.client.version(), requestId, restype, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * sets the permissions for the specified container. The permissions indicate whether blobs in a container may be accessed publicly. + * + * @param containerName The container name. + * @param containerAcl the acls for the container. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param access Specifies whether data in the container may be accessed publicly and the level of access. Possible values include: 'container', 'blob'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(String containerName, List containerAcl, Integer timeout, PublicAccessType access, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String restype = "container"; + final String comp = "acl"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + SignedIdentifiersWrapper containerAclConverted = new SignedIdentifiersWrapper(containerAcl); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.setAccessPolicy(containerName, this.client.url(), containerAclConverted, timeout, access, this.client.version(), requestId, restype, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono acquireLeaseWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final Integer duration = null; + final String proposedLeaseId = null; + final String requestId = null; + final String comp = "lease"; + final String restype = "container"; + final String action = "acquire"; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.acquireLease(containerName, this.client.url(), timeout, duration, proposedLeaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param duration Specifies the duration of the lease, in seconds, or negative one (-1) for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be changed using renew or change. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono acquireLeaseWithRestResponseAsync(String containerName, Integer timeout, Integer duration, String proposedLeaseId, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String restype = "container"; + final String action = "acquire"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.acquireLease(containerName, this.client.url(), timeout, duration, proposedLeaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono releaseLeaseWithRestResponseAsync(String containerName, String leaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String restype = "container"; + final String action = "release"; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.releaseLease(containerName, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono releaseLeaseWithRestResponseAsync(String containerName, String leaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String restype = "container"; + final String action = "release"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.releaseLease(containerName, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono renewLeaseWithRestResponseAsync(String containerName, String leaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String restype = "container"; + final String action = "renew"; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.renewLease(containerName, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono renewLeaseWithRestResponseAsync(String containerName, String leaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String restype = "container"; + final String action = "renew"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.renewLease(containerName, this.client.url(), timeout, leaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono breakLeaseWithRestResponseAsync(String containerName, Context context) { + final Integer timeout = null; + final Integer breakPeriod = null; + final String requestId = null; + final String comp = "lease"; + final String restype = "container"; + final String action = "break"; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.breakLease(containerName, this.client.url(), timeout, breakPeriod, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param breakPeriod For a break operation, proposed duration the lease should continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available before the break period has expired, but the lease may be held for longer than the break period. If this header does not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an infinite lease breaks immediately. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono breakLeaseWithRestResponseAsync(String containerName, Integer timeout, Integer breakPeriod, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String restype = "container"; + final String action = "break"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.breakLease(containerName, this.client.url(), timeout, breakPeriod, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono changeLeaseWithRestResponseAsync(String containerName, String leaseId, String proposedLeaseId, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "lease"; + final String restype = "container"; + final String action = "change"; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.changeLease(containerName, this.client.url(), timeout, leaseId, proposedLeaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60 seconds, or can be infinite. + * + * @param containerName The container name. + * @param leaseId Specifies the current lease ID on the resource. + * @param proposedLeaseId Proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string formats. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono changeLeaseWithRestResponseAsync(String containerName, String leaseId, String proposedLeaseId, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "lease"; + final String restype = "container"; + final String action = "change"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.changeLease(containerName, this.client.url(), timeout, leaseId, proposedLeaseId, this.client.version(), requestId, comp, restype, action, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, context); + } + + /** + * [Update] The List Blobs operation returns a list of the blobs under the specified container. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listBlobFlatSegmentWithRestResponseAsync(String containerName, Context context) { + final String prefix = null; + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String requestId = null; + final String restype = "container"; + final String comp = "list"; + String includeConverted = null; + return service.listBlobFlatSegment(containerName, this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * [Update] The List Blobs operation returns a list of the blobs under the specified container. + * + * @param containerName The container name. + * @param prefix Filters the results to return only containers whose name begins with the specified prefix. + * @param marker A string value that identifies the portion of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000. + * @param include Include this parameter to specify one or more datasets to include in the response. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listBlobFlatSegmentWithRestResponseAsync(String containerName, String prefix, String marker, Integer maxresults, List include, Integer timeout, String requestId, Context context) { + final String restype = "container"; + final String comp = "list"; + String includeConverted = JacksonAdapter.createDefaultSerializerAdapter().serializeList(include, CollectionFormat.CSV); + return service.listBlobFlatSegment(containerName, this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * [Update] The List Blobs operation returns a list of the blobs under the specified container. + * + * @param containerName The container name. + * @param delimiter When the request includes this parameter, the operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may be a single character or a string. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listBlobHierarchySegmentWithRestResponseAsync(String containerName, String delimiter, Context context) { + final String prefix = null; + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String requestId = null; + final String restype = "container"; + final String comp = "list"; + String includeConverted = null; + return service.listBlobHierarchySegment(containerName, this.client.url(), prefix, delimiter, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * [Update] The List Blobs operation returns a list of the blobs under the specified container. + * + * @param containerName The container name. + * @param delimiter When the request includes this parameter, the operation returns a BlobPrefix element in the response body that acts as a placeholder for all blobs whose names begin with the same substring up to the appearance of the delimiter character. The delimiter may be a single character or a string. + * @param prefix Filters the results to return only containers whose name begins with the specified prefix. + * @param marker A string value that identifies the portion of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000. + * @param include Include this parameter to specify one or more datasets to include in the response. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listBlobHierarchySegmentWithRestResponseAsync(String containerName, String delimiter, String prefix, String marker, Integer maxresults, List include, Integer timeout, String requestId, Context context) { + final String restype = "container"; + final String comp = "list"; + String includeConverted = JacksonAdapter.createDefaultSerializerAdapter().serializeList(include, CollectionFormat.CSV); + return service.listBlobHierarchySegment(containerName, this.client.url(), prefix, delimiter, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Returns the sku name and account kind. + * + * @param containerName The container name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccountInfoWithRestResponseAsync(String containerName, Context context) { + final String restype = "account"; + final String comp = "properties"; + return service.getAccountInfo(containerName, this.client.url(), this.client.version(), restype, comp, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ListBlobsIncludeItemWrapper.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ListBlobsIncludeItemWrapper.java new file mode 100644 index 0000000000000..5616bafdc3336 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ListBlobsIncludeItemWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.storage.blob.models.ListBlobsIncludeItem; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<ListBlobsIncludeItem> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "ListBlobsIncludeItem") +public final class ListBlobsIncludeItemWrapper { + @JacksonXmlProperty(localName = "ListBlobsIncludeItem") + private final List listBlobsIncludeItem; + + /** + * Creates an instance of ListBlobsIncludeItemWrapper. + * + * @param listBlobsIncludeItem the list. + */ + @JsonCreator + public ListBlobsIncludeItemWrapper(@JsonProperty("ListBlobsIncludeItem") List listBlobsIncludeItem) { + this.listBlobsIncludeItem = listBlobsIncludeItem; + } + + /** + * Get the List<ListBlobsIncludeItem> contained in this wrapper. + * + * @return the List<ListBlobsIncludeItem>. + */ + public List items() { + return listBlobsIncludeItem; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/PageBlobsImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/PageBlobsImpl.java new file mode 100644 index 0000000000000..f6f6d23380cd6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/PageBlobsImpl.java @@ -0,0 +1,842 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.PathParam; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.util.Base64Util; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.EncryptionAlgorithmType; +import com.azure.storage.blob.models.LeaseAccessConditions; +import com.azure.storage.blob.models.ModifiedAccessConditions; +import com.azure.storage.blob.models.PageBlobsClearPagesResponse; +import com.azure.storage.blob.models.PageBlobsCopyIncrementalResponse; +import com.azure.storage.blob.models.PageBlobsCreateResponse; +import com.azure.storage.blob.models.PageBlobsGetPageRangesDiffResponse; +import com.azure.storage.blob.models.PageBlobsGetPageRangesResponse; +import com.azure.storage.blob.models.PageBlobsResizeResponse; +import com.azure.storage.blob.models.PageBlobsUpdateSequenceNumberResponse; +import com.azure.storage.blob.models.PageBlobsUploadPagesFromURLResponse; +import com.azure.storage.blob.models.PageBlobsUploadPagesResponse; +import com.azure.storage.blob.models.SequenceNumberAccessConditions; +import com.azure.storage.blob.models.SequenceNumberActionType; +import com.azure.storage.blob.models.SourceModifiedAccessConditions; +import com.azure.storage.blob.models.StorageErrorException; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URL; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * PageBlobs. + */ +public final class PageBlobsImpl { + /** + * The proxy service used to perform REST calls. + */ + private PageBlobsService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of PageBlobsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public PageBlobsImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(PageBlobsService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for PageBlobs to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs PageBlobs") + private interface PageBlobsService { + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("Content-Length") long contentLength, @HeaderParam("x-ms-meta-") Map metadata, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-blob-content-length") long blobContentLength, @HeaderParam("x-ms-blob-sequence-number") Long blobSequenceNumber, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @HeaderParam("x-ms-blob-type") String blobType, @HeaderParam("x-ms-blob-content-type") String blobContentType, @HeaderParam("x-ms-blob-content-encoding") String blobContentEncoding, @HeaderParam("x-ms-blob-content-language") String blobContentLanguage, @HeaderParam("x-ms-blob-content-md5") String blobContentMD5, @HeaderParam("x-ms-blob-cache-control") String blobCacheControl, @HeaderParam("x-ms-blob-content-disposition") String blobContentDisposition, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono uploadPages(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @BodyParam("application/octet-stream") Flux body, @HeaderParam("Content-Length") long contentLength, @HeaderParam("Content-MD5") String transactionalContentMD5, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @QueryParam("x-ms-encryption-key") String encryptionKey, @QueryParam("x-ms-encryption-key-sha256") String encryptionKeySha256, @QueryParam("x-ms-encryption-algorithm") EncryptionAlgorithmType encryptionAlgorithm, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-page-write") String pageWrite, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-if-sequence-number-le") Long ifSequenceNumberLessThanOrEqualTo, @HeaderParam("x-ms-if-sequence-number-lt") Long ifSequenceNumberLessThan, @HeaderParam("x-ms-if-sequence-number-eq") Long ifSequenceNumberEqualTo, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono clearPages(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @HeaderParam("Content-Length") long contentLength, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-page-write") String pageWrite, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-if-sequence-number-le") Long ifSequenceNumberLessThanOrEqualTo, @HeaderParam("x-ms-if-sequence-number-lt") Long ifSequenceNumberLessThan, @HeaderParam("x-ms-if-sequence-number-eq") Long ifSequenceNumberEqualTo, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono uploadPagesFromURL(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-source-range") String sourceRange, @HeaderParam("x-ms-source-content-md5") String sourceContentMD5, @HeaderParam("Content-Length") long contentLength, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-page-write") String pageWrite, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("x-ms-if-sequence-number-le") Long ifSequenceNumberLessThanOrEqualTo, @HeaderParam("x-ms-if-sequence-number-lt") Long ifSequenceNumberLessThan, @HeaderParam("x-ms-if-sequence-number-eq") Long ifSequenceNumberEqualTo, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, @HeaderParam("x-ms-source-if-modified-since") DateTimeRfc1123 sourceIfModifiedSince, @HeaderParam("x-ms-source-if-unmodified-since") DateTimeRfc1123 sourceIfUnmodifiedSince, @HeaderParam("x-ms-source-if-match") String sourceIfMatch, @HeaderParam("x-ms-source-if-none-match") String sourceIfNoneMatch, Context context); + + @GET("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getPageRanges(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @GET("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getPageRangesDiff(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("snapshot") String snapshot, @QueryParam("versionid") String versionId, @QueryParam("timeout") Integer timeout, @QueryParam("prevsnapshot") String prevsnapshot, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono resize(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-blob-content-length") long blobContentLength, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono updateSequenceNumber(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-sequence-number-action") SequenceNumberActionType sequenceNumberAction, @HeaderParam("x-ms-blob-sequence-number") Long blobSequenceNumber, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("x-ms-lease-id") String leaseId, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + + @PUT("{containerName}/{blob}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono copyIncremental(@PathParam("containerName") String containerName, @PathParam("blob") String blob, @HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-copy-source") URL copySource, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, @HeaderParam("If-Modified-Since") DateTimeRfc1123 ifModifiedSince, @HeaderParam("If-Unmodified-Since") DateTimeRfc1123 ifUnmodifiedSince, @HeaderParam("If-Match") String ifMatch, @HeaderParam("If-None-Match") String ifNoneMatch, Context context); + } + + /** + * The Create operation creates a new page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, String blob, long contentLength, long blobContentLength, Context context) { + final Integer timeout = null; + final Map metadata = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final Long blobSequenceNumber = 0L; + final String requestId = null; + final String blobType = "PageBlob"; + final String blobContentType = null; + final String blobContentEncoding = null; + final String blobContentLanguage = null; + final String blobCacheControl = null; + final String blobContentDisposition = null; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String blobContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.create(containerName, blob, this.client.url(), timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, blobContentLength, blobSequenceNumber, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Create operation creates a new page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param metadata Optional. Specifies a user-defined name-value pair associated with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and Metadata for more information. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param blobSequenceNumber Set for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param blobHTTPHeaders Additional parameters for the operation. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(String containerName, String blob, long contentLength, long blobContentLength, Integer timeout, Map metadata, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, Long blobSequenceNumber, String requestId, BlobHTTPHeaders blobHTTPHeaders, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String blobType = "PageBlob"; + String blobContentType = null; + if (blobHTTPHeaders != null) { + blobContentType = blobHTTPHeaders.blobContentType(); + } + String blobContentEncoding = null; + if (blobHTTPHeaders != null) { + blobContentEncoding = blobHTTPHeaders.blobContentEncoding(); + } + String blobContentLanguage = null; + if (blobHTTPHeaders != null) { + blobContentLanguage = blobHTTPHeaders.blobContentLanguage(); + } + byte[] blobContentMD5 = null; + if (blobHTTPHeaders != null) { + blobContentMD5 = blobHTTPHeaders.blobContentMD5(); + } + String blobCacheControl = null; + if (blobHTTPHeaders != null) { + blobCacheControl = blobHTTPHeaders.blobCacheControl(); + } + String blobContentDisposition = null; + if (blobHTTPHeaders != null) { + blobContentDisposition = blobHTTPHeaders.blobContentDisposition(); + } + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String blobContentMD5Converted = Base64Util.encodeToString(blobContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.create(containerName, blob, this.client.url(), timeout, contentLength, metadata, encryptionKey, encryptionKeySha256, encryptionAlgorithm, blobContentLength, blobSequenceNumber, this.client.version(), requestId, blobType, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5Converted, blobCacheControl, blobContentDisposition, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Upload Pages operation writes a range of pages to a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadPagesWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, Context context) { + final Integer timeout = null; + final String range = null; + final String encryptionKey = null; + final String encryptionKeySha256 = null; + final EncryptionAlgorithmType encryptionAlgorithm = null; + final String requestId = null; + final String comp = "page"; + final String pageWrite = "update"; + final String leaseId = null; + final Long ifSequenceNumberLessThanOrEqualTo = null; + final Long ifSequenceNumberLessThan = null; + final Long ifSequenceNumberEqualTo = null; + final String ifMatch = null; + final String ifNoneMatch = null; + String transactionalContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.uploadPages(containerName, blob, this.client.url(), body, contentLength, transactionalContentMD5Converted, timeout, range, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Upload Pages operation writes a range of pages to a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param body Initial data. + * @param contentLength The length of the request. + * @param transactionalContentMD5 Specify the transactional md5 for the body, to be validated by the service. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param range Return only the bytes of the blob in the specified range. + * @param encryptionKey Optional. Specifies the encryption key to use to encrypt the data provided in the request. If not specified, encryption is performed with the root account encryption key. For more information, see Encryption at Rest for Azure Storage Services. + * @param encryptionKeySha256 The SHA-256 hash of the provided encryption key. Must be provided if the x-ms-encryption-key header is provided. + * @param encryptionAlgorithm The algorithm used to produce the encryption key hash. Currently, the only accepted value is "AES256". Must be provided if the x-ms-encryption-key header is provided. Possible values include: 'AES256'. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param sequenceNumberAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadPagesWithRestResponseAsync(String containerName, String blob, Flux body, long contentLength, byte[] transactionalContentMD5, Integer timeout, String range, String encryptionKey, String encryptionKeySha256, EncryptionAlgorithmType encryptionAlgorithm, String requestId, LeaseAccessConditions leaseAccessConditions, SequenceNumberAccessConditions sequenceNumberAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "page"; + final String pageWrite = "update"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + Long ifSequenceNumberLessThanOrEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThanOrEqualTo = sequenceNumberAccessConditions.ifSequenceNumberLessThanOrEqualTo(); + } + Long ifSequenceNumberLessThan = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThan = sequenceNumberAccessConditions.ifSequenceNumberLessThan(); + } + Long ifSequenceNumberEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberEqualTo = sequenceNumberAccessConditions.ifSequenceNumberEqualTo(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + String transactionalContentMD5Converted = Base64Util.encodeToString(transactionalContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.uploadPages(containerName, blob, this.client.url(), body, contentLength, transactionalContentMD5Converted, timeout, range, encryptionKey, encryptionKeySha256, encryptionAlgorithm, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Clear Pages operation clears a set of pages from a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono clearPagesWithRestResponseAsync(String containerName, String blob, long contentLength, Context context) { + final Integer timeout = null; + final String range = null; + final String requestId = null; + final String comp = "page"; + final String pageWrite = "clear"; + final String leaseId = null; + final Long ifSequenceNumberLessThanOrEqualTo = null; + final Long ifSequenceNumberLessThan = null; + final Long ifSequenceNumberEqualTo = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.clearPages(containerName, blob, this.client.url(), contentLength, timeout, range, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Clear Pages operation clears a set of pages from a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param contentLength The length of the request. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param range Return only the bytes of the blob in the specified range. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param sequenceNumberAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono clearPagesWithRestResponseAsync(String containerName, String blob, long contentLength, Integer timeout, String range, String requestId, LeaseAccessConditions leaseAccessConditions, SequenceNumberAccessConditions sequenceNumberAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "page"; + final String pageWrite = "clear"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + Long ifSequenceNumberLessThanOrEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThanOrEqualTo = sequenceNumberAccessConditions.ifSequenceNumberLessThanOrEqualTo(); + } + Long ifSequenceNumberLessThan = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThan = sequenceNumberAccessConditions.ifSequenceNumberLessThan(); + } + Long ifSequenceNumberEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberEqualTo = sequenceNumberAccessConditions.ifSequenceNumberEqualTo(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.clearPages(containerName, blob, this.client.url(), contentLength, timeout, range, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Upload Pages operation writes a range of pages to a page blob where the contents are read from a URL. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sourceUrl Specify a URL to the copy source. + * @param sourceRange Bytes of source data in the specified range. The length of this range should match the ContentLength header and x-ms-range/Range destination range header. + * @param contentLength The length of the request. + * @param range The range of bytes to which the source range would be written. The range should be 512 aligned and range-end is required. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadPagesFromURLWithRestResponseAsync(String containerName, String blob, URL sourceUrl, String sourceRange, long contentLength, String range, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "page"; + final String pageWrite = "update"; + final String leaseId = null; + final Long ifSequenceNumberLessThanOrEqualTo = null; + final Long ifSequenceNumberLessThan = null; + final Long ifSequenceNumberEqualTo = null; + final String ifMatch = null; + final String ifNoneMatch = null; + final String sourceIfMatch = null; + final String sourceIfNoneMatch = null; + String sourceContentMD5Converted = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + DateTimeRfc1123 sourceIfModifiedSinceConverted = null; + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = null; + return service.uploadPagesFromURL(containerName, blob, this.client.url(), sourceUrl, sourceRange, sourceContentMD5Converted, contentLength, timeout, range, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } + + /** + * The Upload Pages operation writes a range of pages to a page blob where the contents are read from a URL. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sourceUrl Specify a URL to the copy source. + * @param sourceRange Bytes of source data in the specified range. The length of this range should match the ContentLength header and x-ms-range/Range destination range header. + * @param contentLength The length of the request. + * @param range The range of bytes to which the source range would be written. The range should be 512 aligned and range-end is required. + * @param sourceContentMD5 Specify the md5 calculated for the range of bytes that must be read from the copy source. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param sequenceNumberAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param sourceModifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadPagesFromURLWithRestResponseAsync(String containerName, String blob, URL sourceUrl, String sourceRange, long contentLength, String range, byte[] sourceContentMD5, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, SequenceNumberAccessConditions sequenceNumberAccessConditions, ModifiedAccessConditions modifiedAccessConditions, SourceModifiedAccessConditions sourceModifiedAccessConditions, Context context) { + final String comp = "page"; + final String pageWrite = "update"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + Long ifSequenceNumberLessThanOrEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThanOrEqualTo = sequenceNumberAccessConditions.ifSequenceNumberLessThanOrEqualTo(); + } + Long ifSequenceNumberLessThan = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberLessThan = sequenceNumberAccessConditions.ifSequenceNumberLessThan(); + } + Long ifSequenceNumberEqualTo = null; + if (sequenceNumberAccessConditions != null) { + ifSequenceNumberEqualTo = sequenceNumberAccessConditions.ifSequenceNumberEqualTo(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + OffsetDateTime sourceIfModifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfModifiedSince = sourceModifiedAccessConditions.sourceIfModifiedSince(); + } + OffsetDateTime sourceIfUnmodifiedSince = null; + if (sourceModifiedAccessConditions != null) { + sourceIfUnmodifiedSince = sourceModifiedAccessConditions.sourceIfUnmodifiedSince(); + } + String sourceIfMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfMatch = sourceModifiedAccessConditions.sourceIfMatch(); + } + String sourceIfNoneMatch = null; + if (sourceModifiedAccessConditions != null) { + sourceIfNoneMatch = sourceModifiedAccessConditions.sourceIfNoneMatch(); + } + String sourceContentMD5Converted = Base64Util.encodeToString(sourceContentMD5); + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + DateTimeRfc1123 sourceIfModifiedSinceConverted = sourceIfModifiedSince == null ? null : new DateTimeRfc1123(sourceIfModifiedSince); + DateTimeRfc1123 sourceIfUnmodifiedSinceConverted = sourceIfUnmodifiedSince == null ? null : new DateTimeRfc1123(sourceIfUnmodifiedSince); + return service.uploadPagesFromURL(containerName, blob, this.client.url(), sourceUrl, sourceRange, sourceContentMD5Converted, contentLength, timeout, range, this.client.version(), requestId, comp, pageWrite, leaseId, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, sourceIfModifiedSinceConverted, sourceIfUnmodifiedSinceConverted, sourceIfMatch, sourceIfNoneMatch, context); + } + + /** + * The Get Page Ranges operation returns the list of valid page ranges for a page blob, version or snapshot of a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPageRangesWithRestResponseAsync(String containerName, String blob, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final String range = null; + final String requestId = null; + final String comp = "pagelist"; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.getPageRanges(containerName, blob, this.client.url(), snapshot, versionId, timeout, range, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Get Page Ranges operation returns the list of valid page ranges for a page blob, version or snapshot of a page blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param range Return only the bytes of the blob in the specified range. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPageRangesWithRestResponseAsync(String containerName, String blob, String snapshot, String versionId, Integer timeout, String range, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "pagelist"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.getPageRanges(containerName, blob, this.client.url(), snapshot, versionId, timeout, range, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that were changed between target blob and previous snapshot or version. + * + * @param containerName The container name. + * @param blob The blob name. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPageRangesDiffWithRestResponseAsync(String containerName, String blob, Context context) { + final String snapshot = null; + final String versionId = null; + final Integer timeout = null; + final String prevsnapshot = null; + final String range = null; + final String requestId = null; + final String comp = "pagelist"; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.getPageRangesDiff(containerName, blob, this.client.url(), snapshot, versionId, timeout, prevsnapshot, range, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * [Update] The Get Page Ranges Diff operation returns the list of valid page ranges for a page blob that were changed between target blob and previous snapshot or version. + * + * @param containerName The container name. + * @param blob The blob name. + * @param snapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the blob snapshot to retrieve. For more information on working with blob snapshots, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating a Snapshot of a Blob.</a>. + * @param versionId The version ID parameter is an opaque DateTime value that, when present, specifies the blob version to retrieve. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param prevsnapshot Optional in version 2015-07-08 and newer. The prevsnapshot parameter is a DateTime value that specifies that the response will contain only pages that were changed between target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots are currently supported only for blobs created on or after January 1, 2016. + * @param range Return only the bytes of the blob in the specified range. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPageRangesDiffWithRestResponseAsync(String containerName, String blob, String snapshot, String versionId, Integer timeout, String prevsnapshot, String range, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "pagelist"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.getPageRangesDiff(containerName, blob, this.client.url(), snapshot, versionId, timeout, prevsnapshot, range, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * Resize the Blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono resizeWithRestResponseAsync(String containerName, String blob, long blobContentLength, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "properties"; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.resize(containerName, blob, this.client.url(), timeout, blobContentLength, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * Resize the Blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param blobContentLength This header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono resizeWithRestResponseAsync(String containerName, String blob, long blobContentLength, Integer timeout, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "properties"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.resize(containerName, blob, this.client.url(), timeout, blobContentLength, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * Update the sequence number of the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sequenceNumberAction Required if the x-ms-blob-sequence-number header is set for the request. This property applies to page blobs only. This property indicates how the service should modify the blob's sequence number. Possible values include: 'max', 'update', 'increment'. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono updateSequenceNumberWithRestResponseAsync(String containerName, String blob, SequenceNumberActionType sequenceNumberAction, Context context) { + final Integer timeout = null; + final Long blobSequenceNumber = 0L; + final String requestId = null; + final String comp = "properties"; + final String leaseId = null; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.updateSequenceNumber(containerName, blob, this.client.url(), timeout, sequenceNumberAction, blobSequenceNumber, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * Update the sequence number of the blob. + * + * @param containerName The container name. + * @param blob The blob name. + * @param sequenceNumberAction Required if the x-ms-blob-sequence-number header is set for the request. This property applies to page blobs only. This property indicates how the service should modify the blob's sequence number. Possible values include: 'max', 'update', 'increment'. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param blobSequenceNumber Set for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param leaseAccessConditions Additional parameters for the operation. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono updateSequenceNumberWithRestResponseAsync(String containerName, String blob, SequenceNumberActionType sequenceNumberAction, Integer timeout, Long blobSequenceNumber, String requestId, LeaseAccessConditions leaseAccessConditions, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "properties"; + String leaseId = null; + if (leaseAccessConditions != null) { + leaseId = leaseAccessConditions.leaseId(); + } + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.updateSequenceNumber(containerName, blob, this.client.url(), timeout, sequenceNumberAction, blobSequenceNumber, this.client.version(), requestId, comp, leaseId, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Copy Incremental operation copies a snapshot of the source page blob to a destination page blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. This API is supported since REST version 2016-05-31. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono copyIncrementalWithRestResponseAsync(String containerName, String blob, URL copySource, Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "incrementalcopy"; + final String ifMatch = null; + final String ifNoneMatch = null; + DateTimeRfc1123 ifModifiedSinceConverted = null; + DateTimeRfc1123 ifUnmodifiedSinceConverted = null; + return service.copyIncremental(containerName, blob, this.client.url(), timeout, copySource, this.client.version(), requestId, comp, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } + + /** + * The Copy Incremental operation copies a snapshot of the source page blob to a destination page blob. The snapshot is copied such that only the differential changes between the previously copied snapshot are transferred to the destination. The copied snapshots are complete copies of the original snapshot and can be read or copied from as usual. This API is supported since REST version 2016-05-31. + * + * @param containerName The container name. + * @param blob The blob name. + * @param copySource Specifies the name of the source page blob snapshot. This value is a URL of up to 2 KB in length that specifies a page blob snapshot. The value should be URL-encoded as it would appear in a request URI. The source blob must either be public or must be authenticated via a shared access signature. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param modifiedAccessConditions Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono copyIncrementalWithRestResponseAsync(String containerName, String blob, URL copySource, Integer timeout, String requestId, ModifiedAccessConditions modifiedAccessConditions, Context context) { + final String comp = "incrementalcopy"; + OffsetDateTime ifModifiedSince = null; + if (modifiedAccessConditions != null) { + ifModifiedSince = modifiedAccessConditions.ifModifiedSince(); + } + OffsetDateTime ifUnmodifiedSince = null; + if (modifiedAccessConditions != null) { + ifUnmodifiedSince = modifiedAccessConditions.ifUnmodifiedSince(); + } + String ifMatch = null; + if (modifiedAccessConditions != null) { + ifMatch = modifiedAccessConditions.ifMatch(); + } + String ifNoneMatch = null; + if (modifiedAccessConditions != null) { + ifNoneMatch = modifiedAccessConditions.ifNoneMatch(); + } + DateTimeRfc1123 ifModifiedSinceConverted = ifModifiedSince == null ? null : new DateTimeRfc1123(ifModifiedSince); + DateTimeRfc1123 ifUnmodifiedSinceConverted = ifUnmodifiedSince == null ? null : new DateTimeRfc1123(ifUnmodifiedSince); + return service.copyIncremental(containerName, blob, this.client.url(), timeout, copySource, this.client.version(), requestId, comp, ifModifiedSinceConverted, ifUnmodifiedSinceConverted, ifMatch, ifNoneMatch, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ServicesImpl.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ServicesImpl.java new file mode 100644 index 0000000000000..a31982006724c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/ServicesImpl.java @@ -0,0 +1,267 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.POST; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.blob.models.KeyInfo; +import com.azure.storage.blob.models.ListContainersIncludeType; +import com.azure.storage.blob.models.ServicesGetAccountInfoResponse; +import com.azure.storage.blob.models.ServicesGetPropertiesResponse; +import com.azure.storage.blob.models.ServicesGetStatisticsResponse; +import com.azure.storage.blob.models.ServicesGetUserDelegationKeyResponse; +import com.azure.storage.blob.models.ServicesListContainersSegmentResponse; +import com.azure.storage.blob.models.ServicesSetPropertiesResponse; +import com.azure.storage.blob.models.StorageErrorException; +import com.azure.storage.blob.models.StorageServiceProperties; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in + * Services. + */ +public final class ServicesImpl { + /** + * The proxy service used to perform REST calls. + */ + private ServicesService service; + + /** + * The service client containing this operation class. + */ + private AzureBlobStorageImpl client; + + /** + * Initializes an instance of ServicesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public ServicesImpl(AzureBlobStorageImpl client) { + this.service = RestProxy.create(ServicesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Services to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Blobs Service") + private interface ServicesService { + @PUT("") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setProperties(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") StorageServiceProperties storageServiceProperties, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getStatistics(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listContainersSegment(@HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("include") ListContainersIncludeType include, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + + @POST("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getUserDelegationKey(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") KeyInfo keyInfo, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccountInfo(@HostParam("url") String url, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + } + + /** + * Sets properties for a storage account's Blob service endpoint, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Sets properties for a storage account's Blob service endpoint, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * gets the properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * gets the properties of a storage account's Blob service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Retrieves statistics related to replication for the Blob service. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * The List Containers Segment operation returns a list of the containers under the specified account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listContainersSegmentWithRestResponseAsync(Context context) { + final String prefix = null; + final String marker = null; + final Integer maxresults = null; + final ListContainersIncludeType include = null; + final Integer timeout = null; + final String requestId = null; + final String comp = "list"; + return service.listContainersSegment(this.client.url(), prefix, marker, maxresults, include, timeout, this.client.version(), requestId, comp, context); + } + + /** + * The List Containers Segment operation returns a list of the containers under the specified account. + * + * @param prefix Filters the results to return only containers whose name begins with the specified prefix. + * @param marker A string value that identifies the portion of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all containers remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000. + * @param include Include this parameter to specify that the container's metadata be returned as part of the response body. Possible values include: 'metadata'. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listContainersSegmentWithRestResponseAsync(String prefix, String marker, Integer maxresults, ListContainersIncludeType include, Integer timeout, String requestId, Context context) { + final String comp = "list"; + return service.listContainersSegment(this.client.url(), prefix, marker, maxresults, include, timeout, this.client.version(), requestId, comp, context); + } + + /** + * Retrieves a user delgation key for the Blob service. This is only a valid operation when using bearer token authentication. + * + * @param keyInfo the KeyInfo value. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getUserDelegationKeyWithRestResponseAsync(KeyInfo keyInfo, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "userdelegationkey"; + return service.getUserDelegationKey(this.client.url(), keyInfo, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Retrieves a user delgation key for the Blob service. This is only a valid operation when using bearer token authentication. + * + * @param keyInfo the KeyInfo value. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getUserDelegationKeyWithRestResponseAsync(KeyInfo keyInfo, Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "userdelegationkey"; + return service.getUserDelegationKey(this.client.url(), keyInfo, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Returns the sku name and account kind. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccountInfoWithRestResponseAsync(Context context) { + final String restype = "account"; + final String comp = "properties"; + return service.getAccountInfo(this.client.url(), this.client.version(), restype, comp, context); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/SignedIdentifiersWrapper.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/SignedIdentifiersWrapper.java new file mode 100644 index 0000000000000..41bac045975b2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/SignedIdentifiersWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.implementation; + +import com.azure.storage.blob.models.SignedIdentifier; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<SignedIdentifier> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "SignedIdentifiers") +public final class SignedIdentifiersWrapper { + @JacksonXmlProperty(localName = "SignedIdentifier") + private final List signedIdentifiers; + + /** + * Creates an instance of SignedIdentifiersWrapper. + * + * @param signedIdentifiers the list. + */ + @JsonCreator + public SignedIdentifiersWrapper(@JsonProperty("SignedIdentifiers") List signedIdentifiers) { + this.signedIdentifiers = signedIdentifiers; + } + + /** + * Get the List<SignedIdentifier> contained in this wrapper. + * + * @return the List<SignedIdentifier>. + */ + public List items() { + return signedIdentifiers; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/package-info.java b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/package-info.java new file mode 100644 index 0000000000000..5f341b8ad1be0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/implementation/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementations and inner classes for + * AzureBlobStorage. + */ +package com.azure.storage.blob.implementation; diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessPolicy.java new file mode 100644 index 0000000000000..8b33f24bf5714 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessPolicy.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * An Access policy. + */ +@JacksonXmlRootElement(localName = "AccessPolicy") +public final class AccessPolicy { + /* + * the date-time the policy is active + */ + @JsonProperty(value = "Start", required = true) + private OffsetDateTime start; + + /* + * the date-time the policy expires + */ + @JsonProperty(value = "Expiry", required = true) + private OffsetDateTime expiry; + + /* + * the permissions for the acl policy + */ + @JsonProperty(value = "Permission", required = true) + private String permission; + + /** + * Get the start property: the date-time the policy is active. + * + * @return the start value. + */ + public OffsetDateTime start() { + return this.start; + } + + /** + * Set the start property: the date-time the policy is active. + * + * @param start the start value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy start(OffsetDateTime start) { + this.start = start; + return this; + } + + /** + * Get the expiry property: the date-time the policy expires. + * + * @return the expiry value. + */ + public OffsetDateTime expiry() { + return this.expiry; + } + + /** + * Set the expiry property: the date-time the policy expires. + * + * @param expiry the expiry value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy expiry(OffsetDateTime expiry) { + this.expiry = expiry; + return this; + } + + /** + * Get the permission property: the permissions for the acl policy. + * + * @return the permission value. + */ + public String permission() { + return this.permission; + } + + /** + * Set the permission property: the permissions for the acl policy. + * + * @param permission the permission value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy permission(String permission) { + this.permission = permission; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessTier.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessTier.java new file mode 100644 index 0000000000000..d916bd851ce46 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccessTier.java @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for AccessTier. + */ +public final class AccessTier extends ExpandableStringEnum { + /** + * Static value P4 for AccessTier. + */ + public static final AccessTier P4 = fromString("P4"); + + /** + * Static value P6 for AccessTier. + */ + public static final AccessTier P6 = fromString("P6"); + + /** + * Static value P10 for AccessTier. + */ + public static final AccessTier P10 = fromString("P10"); + + /** + * Static value P20 for AccessTier. + */ + public static final AccessTier P20 = fromString("P20"); + + /** + * Static value P30 for AccessTier. + */ + public static final AccessTier P30 = fromString("P30"); + + /** + * Static value P40 for AccessTier. + */ + public static final AccessTier P40 = fromString("P40"); + + /** + * Static value P50 for AccessTier. + */ + public static final AccessTier P50 = fromString("P50"); + + /** + * Static value Hot for AccessTier. + */ + public static final AccessTier HOT = fromString("Hot"); + + /** + * Static value Cool for AccessTier. + */ + public static final AccessTier COOL = fromString("Cool"); + + /** + * Static value Archive for AccessTier. + */ + public static final AccessTier ARCHIVE = fromString("Archive"); + + /** + * Creates or finds a AccessTier from its string representation. + * + * @param name a name to look for. + * @return the corresponding AccessTier. + */ + @JsonCreator + public static AccessTier fromString(String name) { + return fromString(name, AccessTier.class); + } + + /** + * @return known AccessTier values. + */ + public static Collection values() { + return values(AccessTier.class); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccountKind.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccountKind.java new file mode 100644 index 0000000000000..72ce1183886ec --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AccountKind.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for AccountKind. + */ +public enum AccountKind { + /** + * Enum value Storage. + */ + STORAGE("Storage"), + + /** + * Enum value BlobStorage. + */ + BLOB_STORAGE("BlobStorage"), + + /** + * Enum value StorageV2. + */ + STORAGE_V2("StorageV2"); + + /** + * The actual serialized value for a AccountKind instance. + */ + private final String value; + + AccountKind(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a AccountKind instance. + * + * @param value the serialized value to parse. + * @return the parsed AccountKind object, or null if unable to parse. + */ + @JsonCreator + public static AccountKind fromString(String value) { + AccountKind[] items = AccountKind.values(); + for (AccountKind item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAccessConditions.java new file mode 100644 index 0000000000000..6bba05f391dc6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAccessConditions.java @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +/** + * This class contains values that restrict the successful completion of AppendBlock operations to certain conditions. + * Any field may be set to null if no access conditions are desired. + *

    + * Please refer to the request header section + * here for more conceptual + * information. + */ +public final class AppendBlobAccessConditions { + + private AppendPositionAccessConditions appendPositionAccessConditions; + + private ModifiedAccessConditions modifiedAccessConditions; + + private LeaseAccessConditions leaseAccessConditions; + + /** + * Creates an instance which has fields set to non-null, empty values. + */ + public AppendBlobAccessConditions() { + appendPositionAccessConditions = new AppendPositionAccessConditions(); + modifiedAccessConditions = new ModifiedAccessConditions(); + leaseAccessConditions = new LeaseAccessConditions(); + } + + /** + * Access conditions used for appending data only if the operation meets the provided conditions related to the + * size of the append blob. + * + * @return the append position access conditions + */ + public AppendPositionAccessConditions appendPositionAccessConditions() { + return appendPositionAccessConditions; + } + + /** + * Access conditions used for appending data only if the operation meets the provided conditions related to the + * size of the append blob. + * + * @param appendPositionAccessConditions the append position access conditions to set + * @return the updated AppendBlobAccessConditions object + */ + public AppendBlobAccessConditions appendPositionAccessConditions(AppendPositionAccessConditions appendPositionAccessConditions) { + this.appendPositionAccessConditions = appendPositionAccessConditions; + return this; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return the modified access conditions + */ + public ModifiedAccessConditions modifiedAccessConditions() { + return modifiedAccessConditions; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @param modifiedAccessConditions the modified access conditions to set + * @return the updated AppendBlobAccessConditions object + */ + public AppendBlobAccessConditions modifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) { + this.modifiedAccessConditions = modifiedAccessConditions; + return this; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @return the lease access conditions + */ + public LeaseAccessConditions leaseAccessConditions() { + return leaseAccessConditions; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @param leaseAccessConditions the lease access conditions to set + * @return the updated AppendBlobAccessConditions object + */ + public AppendBlobAccessConditions leaseAccessConditions(LeaseAccessConditions leaseAccessConditions) { + this.leaseAccessConditions = leaseAccessConditions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockFromUrlHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockFromUrlHeaders.java new file mode 100644 index 0000000000000..8273338cb6676 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockFromUrlHeaders.java @@ -0,0 +1,305 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AppendBlockFromUrl operation. + */ +@JacksonXmlRootElement(localName = "AppendBlob-AppendBlockFromUrl-Headers") +public final class AppendBlobAppendBlockFromUrlHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * This response header is returned only for append operations. It returns + * the offset at which the block was committed, in bytes. + */ + @JsonProperty(value = "x-ms-blob-append-offset") + private String blobAppendOffset; + + /* + * The number of committed blocks present in the blob. This header is + * returned only for append blobs. + */ + @JsonProperty(value = "x-ms-blob-committed-block-count") + private Integer blobCommittedBlockCount; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the blobAppendOffset property: This response header is returned only + * for append operations. It returns the offset at which the block was + * committed, in bytes. + * + * @return the blobAppendOffset value. + */ + public String blobAppendOffset() { + return this.blobAppendOffset; + } + + /** + * Set the blobAppendOffset property: This response header is returned only + * for append operations. It returns the offset at which the block was + * committed, in bytes. + * + * @param blobAppendOffset the blobAppendOffset value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders blobAppendOffset(String blobAppendOffset) { + this.blobAppendOffset = blobAppendOffset; + return this; + } + + /** + * Get the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @return the blobCommittedBlockCount value. + */ + public Integer blobCommittedBlockCount() { + return this.blobCommittedBlockCount; + } + + /** + * Set the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @param blobCommittedBlockCount the blobCommittedBlockCount value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders blobCommittedBlockCount(Integer blobCommittedBlockCount) { + this.blobCommittedBlockCount = blobCommittedBlockCount; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the AppendBlobAppendBlockFromUrlHeaders object itself. + */ + public AppendBlobAppendBlockFromUrlHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockHeaders.java new file mode 100644 index 0000000000000..8fe788378e589 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobAppendBlockHeaders.java @@ -0,0 +1,369 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AppendBlock operation. + */ +@JacksonXmlRootElement(localName = "AppendBlob-AppendBlock-Headers") +public final class AppendBlobAppendBlockHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * This response header is returned only for append operations. It returns + * the offset at which the block was committed, in bytes. + */ + @JsonProperty(value = "x-ms-blob-append-offset") + private String blobAppendOffset; + + /* + * The number of committed blocks present in the blob. This header is + * returned only for append blobs. + */ + @JsonProperty(value = "x-ms-blob-committed-block-count") + private Integer blobCommittedBlockCount; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the block. This + * header is only returned when the block was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the blobAppendOffset property: This response header is returned only + * for append operations. It returns the offset at which the block was + * committed, in bytes. + * + * @return the blobAppendOffset value. + */ + public String blobAppendOffset() { + return this.blobAppendOffset; + } + + /** + * Set the blobAppendOffset property: This response header is returned only + * for append operations. It returns the offset at which the block was + * committed, in bytes. + * + * @param blobAppendOffset the blobAppendOffset value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders blobAppendOffset(String blobAppendOffset) { + this.blobAppendOffset = blobAppendOffset; + return this; + } + + /** + * Get the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @return the blobCommittedBlockCount value. + */ + public Integer blobCommittedBlockCount() { + return this.blobCommittedBlockCount; + } + + /** + * Set the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @param blobCommittedBlockCount the blobCommittedBlockCount value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders blobCommittedBlockCount(Integer blobCommittedBlockCount) { + this.blobCommittedBlockCount = blobCommittedBlockCount; + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the AppendBlobAppendBlockHeaders object itself. + */ + public AppendBlobAppendBlockHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobCreateHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobCreateHeaders.java new file mode 100644 index 0000000000000..45fd447bde387 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobCreateHeaders.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "AppendBlob-Create-Headers") +public final class AppendBlobCreateHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies a version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the blob. This + * header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the AppendBlobCreateHeaders object itself. + */ + public AppendBlobCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobItem.java new file mode 100644 index 0000000000000..ef1774048e7f9 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobItem.java @@ -0,0 +1,67 @@ +package com.azure.storage.blob.models; + +import com.azure.core.implementation.util.ImplUtils; + +import java.time.OffsetDateTime; + +public class AppendBlobItem { + + private OffsetDateTime lastModified; + + private final byte[] contentMD5; + + private Boolean isServerEncrypted; + + private String encryptionKeySha256; + + private String blobAppendOffset; + + private Integer blobCommittedBlockCount; + + public AppendBlobItem(AppendBlobCreateHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + } + + public AppendBlobItem(AppendBlobAppendBlockHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + this.blobAppendOffset = generatedHeaders.blobAppendOffset(); + this.blobCommittedBlockCount = generatedHeaders.blobCommittedBlockCount(); + } + + public AppendBlobItem(AppendBlobAppendBlockFromUrlHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.blobAppendOffset = generatedHeaders.blobAppendOffset(); + this.blobCommittedBlockCount = generatedHeaders.blobCommittedBlockCount(); + } + + public OffsetDateTime lastModified() { + return lastModified; + }; + + public Boolean isServerEncrypted() { + return isServerEncrypted; + } + + public String encryptionKeySha256() { + return encryptionKeySha256; + } + + public byte[] contentMD5() { + return ImplUtils.clone(contentMD5); + } + + public String blobAppendOffset() { + return blobAppendOffset; + }; + + public Integer blobCommittedBlockCount() { + return blobCommittedBlockCount; + }; +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockFromUrlResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockFromUrlResponse.java new file mode 100644 index 0000000000000..55cf1e763dc97 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockFromUrlResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the appendBlockFromUrl operation. + */ +public final class AppendBlobsAppendBlockFromUrlResponse extends ResponseBase { + /** + * Creates an instance of AppendBlobsAppendBlockFromUrlResponse. + * + * @param request the request which resulted in this AppendBlobsAppendBlockFromUrlResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public AppendBlobsAppendBlockFromUrlResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, AppendBlobAppendBlockFromUrlHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockResponse.java new file mode 100644 index 0000000000000..2dc53c0da52d0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsAppendBlockResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the appendBlock operation. + */ +public final class AppendBlobsAppendBlockResponse extends ResponseBase { + /** + * Creates an instance of AppendBlobsAppendBlockResponse. + * + * @param request the request which resulted in this AppendBlobsAppendBlockResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public AppendBlobsAppendBlockResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, AppendBlobAppendBlockHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsCreateResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsCreateResponse.java new file mode 100644 index 0000000000000..c8f4cd830c9f8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendBlobsCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class AppendBlobsCreateResponse extends ResponseBase { + /** + * Creates an instance of AppendBlobsCreateResponse. + * + * @param request the request which resulted in this AppendBlobsCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public AppendBlobsCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, AppendBlobCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendPositionAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendPositionAccessConditions.java new file mode 100644 index 0000000000000..5894e08f86e36 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/AppendPositionAccessConditions.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Additional parameters for a set of operations, such as: + * AppendBlobs_appendBlock, AppendBlobs_appendBlockFromUrl. + */ +@JacksonXmlRootElement(localName = "append-position-access-conditions") +public final class AppendPositionAccessConditions { + /* + * Optional conditional header. The max length in bytes permitted for the + * append blob. If the Append Block operation would cause the blob to + * exceed that limit or if the blob size is already greater than the value + * specified in this header, the request will fail with + * MaxBlobSizeConditionNotMet error (HTTP status code 412 - Precondition + * Failed). + */ + @JsonProperty(value = "maxSize") + private Long maxSize; + + /* + * Optional conditional header, used only for the Append Block operation. A + * number indicating the byte offset to compare. Append Block will succeed + * only if the append position is equal to this number. If it is not, the + * request will fail with the AppendPositionConditionNotMet error (HTTP + * status code 412 - Precondition Failed). + */ + @JsonProperty(value = "appendPosition") + private Long appendPosition; + + /** + * Get the maxSize property: Optional conditional header. The max length in + * bytes permitted for the append blob. If the Append Block operation would + * cause the blob to exceed that limit or if the blob size is already + * greater than the value specified in this header, the request will fail + * with MaxBlobSizeConditionNotMet error (HTTP status code 412 - + * Precondition Failed). + * + * @return the maxSize value. + */ + public Long maxSize() { + return this.maxSize; + } + + /** + * Set the maxSize property: Optional conditional header. The max length in + * bytes permitted for the append blob. If the Append Block operation would + * cause the blob to exceed that limit or if the blob size is already + * greater than the value specified in this header, the request will fail + * with MaxBlobSizeConditionNotMet error (HTTP status code 412 - + * Precondition Failed). + * + * @param maxSize the maxSize value to set. + * @return the AppendPositionAccessConditions object itself. + */ + public AppendPositionAccessConditions maxSize(Long maxSize) { + this.maxSize = maxSize; + return this; + } + + /** + * Get the appendPosition property: Optional conditional header, used only + * for the Append Block operation. A number indicating the byte offset to + * compare. Append Block will succeed only if the append position is equal + * to this number. If it is not, the request will fail with the + * AppendPositionConditionNotMet error (HTTP status code 412 - Precondition + * Failed). + * + * @return the appendPosition value. + */ + public Long appendPosition() { + return this.appendPosition; + } + + /** + * Set the appendPosition property: Optional conditional header, used only + * for the Append Block operation. A number indicating the byte offset to + * compare. Append Block will succeed only if the append position is equal + * to this number. If it is not, the request will fail with the + * AppendPositionConditionNotMet error (HTTP status code 412 - Precondition + * Failed). + * + * @param appendPosition the appendPosition value to set. + * @return the AppendPositionAccessConditions object itself. + */ + public AppendPositionAccessConditions appendPosition(Long appendPosition) { + this.appendPosition = appendPosition; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ArchiveStatus.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ArchiveStatus.java new file mode 100644 index 0000000000000..5bf03bde28dfa --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ArchiveStatus.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for ArchiveStatus. + */ +public final class ArchiveStatus extends ExpandableStringEnum { + /** + * Static value rehydrate-pending-to-hot for ArchiveStatus. + */ + public static final ArchiveStatus REHYDRATE_PENDING_TO_HOT = fromString("rehydrate-pending-to-hot"); + + /** + * Static value rehydrate-pending-to-cool for ArchiveStatus. + */ + public static final ArchiveStatus REHYDRATE_PENDING_TO_COOL = fromString("rehydrate-pending-to-cool"); + + /** + * Creates or finds a ArchiveStatus from its string representation. + * + * @param name a name to look for. + * @return the corresponding ArchiveStatus. + */ + @JsonCreator + public static ArchiveStatus fromString(String name) { + return fromString(name, ArchiveStatus.class); + } + + /** + * @return known ArchiveStatus values. + */ + public static Collection values() { + return values(ArchiveStatus.class); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAbortCopyFromURLHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAbortCopyFromURLHeaders.java new file mode 100644 index 0000000000000..e439f5b8b0892 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAbortCopyFromURLHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AbortCopyFromURL operation. + */ +@JacksonXmlRootElement(localName = "Blob-AbortCopyFromURL-Headers") +public final class BlobAbortCopyFromURLHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobAbortCopyFromURLHeaders object itself. + */ + public BlobAbortCopyFromURLHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobAbortCopyFromURLHeaders object itself. + */ + public BlobAbortCopyFromURLHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobAbortCopyFromURLHeaders object itself. + */ + public BlobAbortCopyFromURLHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobAbortCopyFromURLHeaders object itself. + */ + public BlobAbortCopyFromURLHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAccessConditions.java new file mode 100644 index 0000000000000..5ef80e82ca4da --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAccessConditions.java @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +/** + * This class contains values which will restrict the successful operation of a variety of requests to the conditions + * present. These conditions are entirely optional. The entire object or any of its properties may be set to null when + * passed to a method to indicate that those conditions are not desired. Please refer to the type of each field for more + * information on those particular access conditions. + */ +public final class BlobAccessConditions { + + private ModifiedAccessConditions modifiedAccessConditions; + + private LeaseAccessConditions leaseAccessConditions; + + /** + * Creates an instance which has fields set to non-null, empty values. + */ + public BlobAccessConditions() { + modifiedAccessConditions = new ModifiedAccessConditions(); + leaseAccessConditions = new LeaseAccessConditions(); + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return the modified access conditions + */ + public ModifiedAccessConditions modifiedAccessConditions() { + return modifiedAccessConditions; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @param modifiedAccessConditions the modified access conditions to set + * @return the updated BlobAccessConditions object + */ + public BlobAccessConditions modifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) { + this.modifiedAccessConditions = modifiedAccessConditions; + return this; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @return the lease access conditions + */ + public LeaseAccessConditions leaseAccessConditions() { + return leaseAccessConditions; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @param leaseAccessConditions the lease access conditions to set + * @return the updated BlobAccessConditions object + */ + public BlobAccessConditions leaseAccessConditions(LeaseAccessConditions leaseAccessConditions) { + this.leaseAccessConditions = leaseAccessConditions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAcquireLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAcquireLeaseHeaders.java new file mode 100644 index 0000000000000..5bf6ef2560117 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobAcquireLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AcquireLease operation. + */ +@JacksonXmlRootElement(localName = "Blob-AcquireLease-Headers") +public final class BlobAcquireLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Uniquely identifies a blobs's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a blobs's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a blobs's lease. + * + * @param leaseId the leaseId value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobAcquireLeaseHeaders object itself. + */ + public BlobAcquireLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobBreakLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobBreakLeaseHeaders.java new file mode 100644 index 0000000000000..b136802ce69ad --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobBreakLeaseHeaders.java @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for BreakLease operation. + */ +@JacksonXmlRootElement(localName = "Blob-BreakLease-Headers") +public final class BlobBreakLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Approximate time remaining in the lease period, in seconds. + */ + @JsonProperty(value = "x-ms-lease-time") + private Integer leaseTime; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseTime property: Approximate time remaining in the lease + * period, in seconds. + * + * @return the leaseTime value. + */ + public Integer leaseTime() { + return this.leaseTime; + } + + /** + * Set the leaseTime property: Approximate time remaining in the lease + * period, in seconds. + * + * @param leaseTime the leaseTime value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders leaseTime(Integer leaseTime) { + this.leaseTime = leaseTime; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobBreakLeaseHeaders object itself. + */ + public BlobBreakLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobChangeLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobChangeLeaseHeaders.java new file mode 100644 index 0000000000000..1c3010861eaf0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobChangeLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ChangeLease operation. + */ +@JacksonXmlRootElement(localName = "Blob-ChangeLease-Headers") +public final class BlobChangeLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Uniquely identifies a blobs's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a blobs's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a blobs's lease. + * + * @param leaseId the leaseId value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobChangeLeaseHeaders object itself. + */ + public BlobChangeLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCopyFromURLHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCopyFromURLHeaders.java new file mode 100644 index 0000000000000..2568e1c566bcf --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCopyFromURLHeaders.java @@ -0,0 +1,299 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for CopyFromURL operation. + */ +@JacksonXmlRootElement(localName = "Blob-CopyFromURL-Headers") +public final class BlobCopyFromURLHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies the version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * String identifier for this copy operation. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'success' + */ + @JsonProperty(value = "x-ms-copy-status") + private SyncCopyStatusType copyStatus; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. + * + * @param copyId the copyId value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'success'. + * + * @return the copyStatus value. + */ + public SyncCopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'success'. + * + * @param copyStatus the copyStatus value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders copyStatus(SyncCopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobCopyFromURLHeaders object itself. + */ + public BlobCopyFromURLHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCreateSnapshotHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCreateSnapshotHeaders.java new file mode 100644 index 0000000000000..f185a465e483e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobCreateSnapshotHeaders.java @@ -0,0 +1,344 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for CreateSnapshot operation. + */ +@JacksonXmlRootElement(localName = "Blob-CreateSnapshot-Headers") +public final class BlobCreateSnapshotHeaders { + /* + * Uniquely identifies the snapshot and indicates the snapshot version. It + * may be used in subsequent requests to access the snapshot + */ + @JsonProperty(value = "x-ms-snapshot") + private String snapshot; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies the version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * True if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. For a snapshot request, this + * header is set to true when metadata was provided in the request and + * encrypted with a customer-provided key. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the source blob. + * This header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the snapshot property: Uniquely identifies the snapshot and + * indicates the snapshot version. It may be used in subsequent requests to + * access the snapshot. + * + * @return the snapshot value. + */ + public String snapshot() { + return this.snapshot; + } + + /** + * Set the snapshot property: Uniquely identifies the snapshot and + * indicates the snapshot version. It may be used in subsequent requests to + * access the snapshot. + * + * @param snapshot the snapshot value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: True if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. For a snapshot request, this header is set to true when + * metadata was provided in the request and encrypted with a + * customer-provided key. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: True if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. For a snapshot request, this header is set to true when + * metadata was provided in the request and encrypted with a + * customer-provided key. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the source blob. This header is only returned when + * the blob was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the source blob. This header is only returned when + * the blob was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobCreateSnapshotHeaders object itself. + */ + public BlobCreateSnapshotHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDeleteHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDeleteHeaders.java new file mode 100644 index 0000000000000..7aeac53bc5a33 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDeleteHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "Blob-Delete-Headers") +public final class BlobDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobDeleteHeaders object itself. + */ + public BlobDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobDeleteHeaders object itself. + */ + public BlobDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobDeleteHeaders object itself. + */ + public BlobDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobDeleteHeaders object itself. + */ + public BlobDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java new file mode 100644 index 0000000000000..aa56c2e6683c4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java @@ -0,0 +1,1043 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for Download operation. + */ +@JacksonXmlRootElement(localName = "Blob-Download-Headers") +public final class BlobDownloadHeaders { + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The number of bytes present in the response body. + */ + @JsonProperty(value = "Content-Length") + private Long contentLength; + + /* + * The media type of the body of the response. For Download Blob this is + * 'application/octet-stream' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * Indicates the range of bytes returned in the event that the client + * requested a subset of the blob by setting the 'Range' request header. + */ + @JsonProperty(value = "Content-Range") + private String contentRange; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header returns the value that was specified for the + * Content-Encoding request header + */ + @JsonProperty(value = "Content-Encoding") + private String contentEncoding; + + /* + * This header is returned if it was previously specified for the blob. + */ + @JsonProperty(value = "Cache-Control") + private String cacheControl; + + /* + * This header returns the value that was specified for the + * 'x-ms-blob-content-disposition' header. The Content-Disposition response + * header field conveys additional information about how to process the + * response payload, and also can be used to attach additional metadata. + * For example, if set to attachment, it indicates that the user-agent + * should not display the response, but instead show a Save As dialog with + * a filename other than the blob name specified. + */ + @JsonProperty(value = "Content-Disposition") + private String contentDisposition; + + /* + * This header returns the value that was specified for the + * Content-Language request header. + */ + @JsonProperty(value = "Content-Language") + private String contentLanguage; + + /* + * The current sequence number for a page blob. This header is not returned + * for block blobs or append blobs + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * The blob's type. Possible values include: 'BlockBlob', 'PageBlob', + * 'AppendBlob' + */ + @JsonProperty(value = "x-ms-blob-type") + private BlobType blobType; + + /* + * Conclusion time of the last attempted Copy Blob operation where this + * blob was the destination blob. This value can specify the time of a + * completed, aborted, or failed copy attempt. This header does not appear + * if a copy is pending, if this blob has never been the destination in a + * Copy Blob operation, or if this blob has been modified after a concluded + * Copy Blob operation using Set Blob Properties, Put Blob, or Put Block + * List. + */ + @JsonProperty(value = "x-ms-copy-completion-time") + private DateTimeRfc1123 copyCompletionTime; + + /* + * Only appears when x-ms-copy-status is failed or pending. Describes the + * cause of the last fatal or non-fatal copy operation failure. This header + * does not appear if this blob has never been the destination in a Copy + * Blob operation, or if this blob has been modified after a concluded Copy + * Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + @JsonProperty(value = "x-ms-copy-status-description") + private String copyStatusDescription; + + /* + * String identifier for this copy operation. Use with Get Blob Properties + * to check the status of this copy operation, or pass to Abort Copy Blob + * to abort a pending copy. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * Contains the number of bytes copied and the total bytes in the source in + * the last attempted Copy Blob operation where this blob was the + * destination blob. Can show between 0 and Content-Length bytes copied. + * This header does not appear if this blob has never been the destination + * in a Copy Blob operation, or if this blob has been modified after a + * concluded Copy Blob operation using Set Blob Properties, Put Blob, or + * Put Block List + */ + @JsonProperty(value = "x-ms-copy-progress") + private String copyProgress; + + /* + * URL up to 2 KB in length that specifies the source blob or file used in + * the last attempted Copy Blob operation where this blob was the + * destination blob. This header does not appear if this blob has never + * been the destination in a Copy Blob operation, or if this blob has been + * modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + */ + @JsonProperty(value = "x-ms-copy-source") + private String copySource; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * When a blob is leased, specifies whether the lease is of infinite or + * fixed duration. Possible values include: 'infinite', 'fixed' + */ + @JsonProperty(value = "x-ms-lease-duration") + private LeaseDurationType leaseDuration; + + /* + * Lease state of the blob. Possible values include: 'available', 'leased', + * 'expired', 'breaking', 'broken' + */ + @JsonProperty(value = "x-ms-lease-state") + private LeaseStateType leaseState; + + /* + * The current lease status of the blob. Possible values include: 'locked', + * 'unlocked' + */ + @JsonProperty(value = "x-ms-lease-status") + private LeaseStatusType leaseStatus; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * Indicates that the service supports requests for partial blob content. + */ + @JsonProperty(value = "Accept-Ranges") + private String acceptRanges; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The number of committed blocks present in the blob. This header is + * returned only for append blobs. + */ + @JsonProperty(value = "x-ms-blob-committed-block-count") + private Integer blobCommittedBlockCount; + + /* + * The value of this header is set to true if the blob data and application + * metadata are completely encrypted using the specified algorithm. + * Otherwise, the value is set to false (when the blob is unencrypted, or + * if only parts of the blob/application metadata are encrypted). + */ + @JsonProperty(value = "x-ms-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the blob. This + * header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * If the blob has a MD5 hash, and if request contains range header (Range + * or x-ms-range), this response header is returned with the value of the + * whole blob's MD5 value. This value may or may not be equal to the value + * returned in Content-MD5 header, with the latter calculated from the + * requested range + */ + @JsonProperty(value = "x-ms-blob-content-md5") + private byte[] blobContentMD5; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the contentLength property: The number of bytes present in the + * response body. + * + * @return the contentLength value. + */ + public Long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: The number of bytes present in the + * response body. + * + * @param contentLength the contentLength value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentLength(Long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * Get the contentType property: The media type of the body of the + * response. For Download Blob this is 'application/octet-stream'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The media type of the body of the + * response. For Download Blob this is 'application/octet-stream'. + * + * @param contentType the contentType value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the contentRange property: Indicates the range of bytes returned in + * the event that the client requested a subset of the blob by setting the + * 'Range' request header. + * + * @return the contentRange value. + */ + public String contentRange() { + return this.contentRange; + } + + /** + * Set the contentRange property: Indicates the range of bytes returned in + * the event that the client requested a subset of the blob by setting the + * 'Range' request header. + * + * @param contentRange the contentRange value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentRange(String contentRange) { + this.contentRange = contentRange; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the contentEncoding property: This header returns the value that was + * specified for the Content-Encoding request header. + * + * @return the contentEncoding value. + */ + public String contentEncoding() { + return this.contentEncoding; + } + + /** + * Set the contentEncoding property: This header returns the value that was + * specified for the Content-Encoding request header. + * + * @param contentEncoding the contentEncoding value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * Get the cacheControl property: This header is returned if it was + * previously specified for the blob. + * + * @return the cacheControl value. + */ + public String cacheControl() { + return this.cacheControl; + } + + /** + * Set the cacheControl property: This header is returned if it was + * previously specified for the blob. + * + * @param cacheControl the cacheControl value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * Get the contentDisposition property: This header returns the value that + * was specified for the 'x-ms-blob-content-disposition' header. The + * Content-Disposition response header field conveys additional information + * about how to process the response payload, and also can be used to + * attach additional metadata. For example, if set to attachment, it + * indicates that the user-agent should not display the response, but + * instead show a Save As dialog with a filename other than the blob name + * specified. + * + * @return the contentDisposition value. + */ + public String contentDisposition() { + return this.contentDisposition; + } + + /** + * Set the contentDisposition property: This header returns the value that + * was specified for the 'x-ms-blob-content-disposition' header. The + * Content-Disposition response header field conveys additional information + * about how to process the response payload, and also can be used to + * attach additional metadata. For example, if set to attachment, it + * indicates that the user-agent should not display the response, but + * instead show a Save As dialog with a filename other than the blob name + * specified. + * + * @param contentDisposition the contentDisposition value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * Get the contentLanguage property: This header returns the value that was + * specified for the Content-Language request header. + * + * @return the contentLanguage value. + */ + public String contentLanguage() { + return this.contentLanguage; + } + + /** + * Set the contentLanguage property: This header returns the value that was + * specified for the Content-Language request header. + * + * @param contentLanguage the contentLanguage value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the blobType property: The blob's type. Possible values include: + * 'BlockBlob', 'PageBlob', 'AppendBlob'. + * + * @return the blobType value. + */ + public BlobType blobType() { + return this.blobType; + } + + /** + * Set the blobType property: The blob's type. Possible values include: + * 'BlockBlob', 'PageBlob', 'AppendBlob'. + * + * @param blobType the blobType value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders blobType(BlobType blobType) { + this.blobType = blobType; + return this; + } + + /** + * Get the copyCompletionTime property: Conclusion time of the last + * attempted Copy Blob operation where this blob was the destination blob. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @return the copyCompletionTime value. + */ + public OffsetDateTime copyCompletionTime() { + if (this.copyCompletionTime == null) { + return null; + } + return this.copyCompletionTime.dateTime(); + } + + /** + * Set the copyCompletionTime property: Conclusion time of the last + * attempted Copy Blob operation where this blob was the destination blob. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @param copyCompletionTime the copyCompletionTime value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copyCompletionTime(OffsetDateTime copyCompletionTime) { + if (copyCompletionTime == null) { + this.copyCompletionTime = null; + } else { + this.copyCompletionTime = new DateTimeRfc1123(copyCompletionTime); + } + return this; + } + + /** + * Get the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear + * if this blob has never been the destination in a Copy Blob operation, or + * if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + * + * @return the copyStatusDescription value. + */ + public String copyStatusDescription() { + return this.copyStatusDescription; + } + + /** + * Set the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear + * if this blob has never been the destination in a Copy Blob operation, or + * if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + * + * @param copyStatusDescription the copyStatusDescription value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copyStatusDescription(String copyStatusDescription) { + this.copyStatusDescription = copyStatusDescription; + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @param copyId the copyId value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy Blob operation + * where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @return the copyProgress value. + */ + public String copyProgress() { + return this.copyProgress; + } + + /** + * Set the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy Blob operation + * where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @param copyProgress the copyProgress value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copyProgress(String copyProgress) { + this.copyProgress = copyProgress; + return this; + } + + /** + * Get the copySource property: URL up to 2 KB in length that specifies the + * source blob or file used in the last attempted Copy Blob operation where + * this blob was the destination blob. This header does not appear if this + * blob has never been the destination in a Copy Blob operation, or if this + * blob has been modified after a concluded Copy Blob operation using Set + * Blob Properties, Put Blob, or Put Block List. + * + * @return the copySource value. + */ + public String copySource() { + return this.copySource; + } + + /** + * Set the copySource property: URL up to 2 KB in length that specifies the + * source blob or file used in the last attempted Copy Blob operation where + * this blob was the destination blob. This header does not appear if this + * blob has never been the destination in a Copy Blob operation, or if this + * blob has been modified after a concluded Copy Blob operation using Set + * Blob Properties, Put Blob, or Put Block List. + * + * @param copySource the copySource value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copySource(String copySource) { + this.copySource = copySource; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @return the leaseDuration value. + */ + public LeaseDurationType leaseDuration() { + return this.leaseDuration; + } + + /** + * Set the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @param leaseDuration the leaseDuration value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders leaseDuration(LeaseDurationType leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + /** + * Get the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @return the leaseState value. + */ + public LeaseStateType leaseState() { + return this.leaseState; + } + + /** + * Set the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @param leaseState the leaseState value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders leaseState(LeaseStateType leaseState) { + this.leaseState = leaseState; + return this; + } + + /** + * Get the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @return the leaseStatus value. + */ + public LeaseStatusType leaseStatus() { + return this.leaseStatus; + } + + /** + * Set the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @param leaseStatus the leaseStatus value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders leaseStatus(LeaseStatusType leaseStatus) { + this.leaseStatus = leaseStatus; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the acceptRanges property: Indicates that the service supports + * requests for partial blob content. + * + * @return the acceptRanges value. + */ + public String acceptRanges() { + return this.acceptRanges; + } + + /** + * Set the acceptRanges property: Indicates that the service supports + * requests for partial blob content. + * + * @param acceptRanges the acceptRanges value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders acceptRanges(String acceptRanges) { + this.acceptRanges = acceptRanges; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @return the blobCommittedBlockCount value. + */ + public Integer blobCommittedBlockCount() { + return this.blobCommittedBlockCount; + } + + /** + * Set the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @param blobCommittedBlockCount the blobCommittedBlockCount value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders blobCommittedBlockCount(Integer blobCommittedBlockCount) { + this.blobCommittedBlockCount = blobCommittedBlockCount; + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the blob data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the blob is unencrypted, or if only parts of the blob/application + * metadata are encrypted). + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the blob data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the blob is unencrypted, or if only parts of the blob/application + * metadata are encrypted). + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the blobContentMD5 property: If the blob has a MD5 hash, and if + * request contains range header (Range or x-ms-range), this response + * header is returned with the value of the whole blob's MD5 value. This + * value may or may not be equal to the value returned in Content-MD5 + * header, with the latter calculated from the requested range. + * + * @return the blobContentMD5 value. + */ + public byte[] blobContentMD5() { + return ImplUtils.clone(this.blobContentMD5); + } + + /** + * Set the blobContentMD5 property: If the blob has a MD5 hash, and if + * request contains range header (Range or x-ms-range), this response + * header is returned with the value of the whole blob's MD5 value. This + * value may or may not be equal to the value returned in Content-MD5 + * header, with the latter calculated from the requested range. + * + * @param blobContentMD5 the blobContentMD5 value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders blobContentMD5(byte[] blobContentMD5) { + this.blobContentMD5 = ImplUtils.clone(blobContentMD5); + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobFlatListSegment.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobFlatListSegment.java new file mode 100644 index 0000000000000..97f8e48a9c832 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobFlatListSegment.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * The BlobFlatListSegment model. + */ +@JacksonXmlRootElement(localName = "Blobs") +public final class BlobFlatListSegment { + /* + * The blobItems property. + */ + @JsonProperty("Blob") + private List blobItems = new ArrayList<>(); + + /** + * Get the blobItems property: The blobItems property. + * + * @return the blobItems value. + */ + public List blobItems() { + return this.blobItems; + } + + /** + * Set the blobItems property: The blobItems property. + * + * @param blobItems the blobItems value to set. + * @return the BlobFlatListSegment object itself. + */ + public BlobFlatListSegment blobItems(List blobItems) { + this.blobItems = blobItems; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetAccountInfoHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetAccountInfoHeaders.java new file mode 100644 index 0000000000000..81c8b54b46615 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetAccountInfoHeaders.java @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccountInfo operation. + */ +@JacksonXmlRootElement(localName = "Blob-GetAccountInfo-Headers") +public final class BlobGetAccountInfoHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Identifies the sku name of the account. Possible values include: + * 'Standard_LRS', 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', + * 'Premium_LRS' + */ + @JsonProperty(value = "x-ms-sku-name") + private SkuName skuName; + + /* + * Identifies the account kind. Possible values include: 'Storage', + * 'BlobStorage', 'StorageV2' + */ + @JsonProperty(value = "x-ms-account-kind") + private AccountKind accountKind; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @return the skuName value. + */ + public SkuName skuName() { + return this.skuName; + } + + /** + * Set the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @param skuName the skuName value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders skuName(SkuName skuName) { + this.skuName = skuName; + return this; + } + + /** + * Get the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @return the accountKind value. + */ + public AccountKind accountKind() { + return this.accountKind; + } + + /** + * Set the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @param accountKind the accountKind value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders accountKind(AccountKind accountKind) { + this.accountKind = accountKind; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobGetAccountInfoHeaders object itself. + */ + public BlobGetAccountInfoHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetPropertiesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetPropertiesHeaders.java new file mode 100644 index 0000000000000..cb1d9e3ba1762 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobGetPropertiesHeaders.java @@ -0,0 +1,1218 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Blob-GetProperties-Headers") +public final class BlobGetPropertiesHeaders { + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Returns the date and time the blob was created. + */ + @JsonProperty(value = "x-ms-creation-time") + private DateTimeRfc1123 creationTime; + + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The blob's type. Possible values include: 'BlockBlob', 'PageBlob', + * 'AppendBlob' + */ + @JsonProperty(value = "x-ms-blob-type") + private BlobType blobType; + + /* + * Conclusion time of the last attempted Copy Blob operation where this + * blob was the destination blob. This value can specify the time of a + * completed, aborted, or failed copy attempt. This header does not appear + * if a copy is pending, if this blob has never been the destination in a + * Copy Blob operation, or if this blob has been modified after a concluded + * Copy Blob operation using Set Blob Properties, Put Blob, or Put Block + * List. + */ + @JsonProperty(value = "x-ms-copy-completion-time") + private DateTimeRfc1123 copyCompletionTime; + + /* + * Only appears when x-ms-copy-status is failed or pending. Describes the + * cause of the last fatal or non-fatal copy operation failure. This header + * does not appear if this blob has never been the destination in a Copy + * Blob operation, or if this blob has been modified after a concluded Copy + * Blob operation using Set Blob Properties, Put Blob, or Put Block List + */ + @JsonProperty(value = "x-ms-copy-status-description") + private String copyStatusDescription; + + /* + * String identifier for this copy operation. Use with Get Blob Properties + * to check the status of this copy operation, or pass to Abort Copy Blob + * to abort a pending copy. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * Contains the number of bytes copied and the total bytes in the source in + * the last attempted Copy Blob operation where this blob was the + * destination blob. Can show between 0 and Content-Length bytes copied. + * This header does not appear if this blob has never been the destination + * in a Copy Blob operation, or if this blob has been modified after a + * concluded Copy Blob operation using Set Blob Properties, Put Blob, or + * Put Block List + */ + @JsonProperty(value = "x-ms-copy-progress") + private String copyProgress; + + /* + * URL up to 2 KB in length that specifies the source blob or file used in + * the last attempted Copy Blob operation where this blob was the + * destination blob. This header does not appear if this blob has never + * been the destination in a Copy Blob operation, or if this blob has been + * modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + */ + @JsonProperty(value = "x-ms-copy-source") + private String copySource; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * Included if the blob is incremental copy blob. + */ + @JsonProperty(value = "x-ms-incremental-copy") + private Boolean isIncrementalCopy; + + /* + * Included if the blob is incremental copy blob or incremental copy + * snapshot, if x-ms-copy-status is success. Snapshot time of the last + * successful incremental copy snapshot for this blob. + */ + @JsonProperty(value = "x-ms-copy-destination-snapshot") + private String destinationSnapshot; + + /* + * When a blob is leased, specifies whether the lease is of infinite or + * fixed duration. Possible values include: 'infinite', 'fixed' + */ + @JsonProperty(value = "x-ms-lease-duration") + private LeaseDurationType leaseDuration; + + /* + * Lease state of the blob. Possible values include: 'available', 'leased', + * 'expired', 'breaking', 'broken' + */ + @JsonProperty(value = "x-ms-lease-state") + private LeaseStateType leaseState; + + /* + * The current lease status of the blob. Possible values include: 'locked', + * 'unlocked' + */ + @JsonProperty(value = "x-ms-lease-status") + private LeaseStatusType leaseStatus; + + /* + * The number of bytes present in the response body. + */ + @JsonProperty(value = "Content-Length") + private Long contentLength; + + /* + * The content type specified for the blob. The default content type is + * 'application/octet-stream' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header returns the value that was specified for the + * Content-Encoding request header + */ + @JsonProperty(value = "Content-Encoding") + private String contentEncoding; + + /* + * This header returns the value that was specified for the + * 'x-ms-blob-content-disposition' header. The Content-Disposition response + * header field conveys additional information about how to process the + * response payload, and also can be used to attach additional metadata. + * For example, if set to attachment, it indicates that the user-agent + * should not display the response, but instead show a Save As dialog with + * a filename other than the blob name specified. + */ + @JsonProperty(value = "Content-Disposition") + private String contentDisposition; + + /* + * This header returns the value that was specified for the + * Content-Language request header. + */ + @JsonProperty(value = "Content-Language") + private String contentLanguage; + + /* + * This header is returned if it was previously specified for the blob. + */ + @JsonProperty(value = "Cache-Control") + private String cacheControl; + + /* + * The current sequence number for a page blob. This header is not returned + * for block blobs or append blobs + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Indicates that the service supports requests for partial blob content. + */ + @JsonProperty(value = "Accept-Ranges") + private String acceptRanges; + + /* + * The number of committed blocks present in the blob. This header is + * returned only for append blobs. + */ + @JsonProperty(value = "x-ms-blob-committed-block-count") + private Integer blobCommittedBlockCount; + + /* + * The value of this header is set to true if the blob data and application + * metadata are completely encrypted using the specified algorithm. + * Otherwise, the value is set to false (when the blob is unencrypted, or + * if only parts of the blob/application metadata are encrypted). + */ + @JsonProperty(value = "x-ms-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the metadata. + * This header is only returned when the metadata was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The tier of page blob on a premium storage account or tier of block blob + * on blob storage LRS accounts. For a list of allowed premium page blob + * tiers, see + * https://docs.microsoft.com/en-us/azure/virtual-machines/windows/premium-storage#features. + * For blob storage LRS accounts, valid values are Hot/Cool/Archive. + */ + @JsonProperty(value = "x-ms-access-tier") + private String accessTier; + + /* + * For page blobs on a premium storage account only. If the access tier is + * not explicitly set on the blob, the tier is inferred based on its + * content length and this header will be returned with true value. + */ + @JsonProperty(value = "x-ms-access-tier-inferred") + private Boolean accessTierInferred; + + /* + * For blob storage LRS accounts, valid values are + * rehydrate-pending-to-hot/rehydrate-pending-to-cool. If the blob is being + * rehydrated and is not complete then this header is returned indicating + * that rehydrate is pending and also tells the destination tier. + */ + @JsonProperty(value = "x-ms-archive-status") + private String archiveStatus; + + /* + * The time the tier was changed on the object. This is only returned if + * the tier on the block blob was ever set. + */ + @JsonProperty(value = "x-ms-access-tier-change-time") + private DateTimeRfc1123 accessTierChangeTime; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the creationTime property: Returns the date and time the blob was + * created. + * + * @return the creationTime value. + */ + public OffsetDateTime creationTime() { + if (this.creationTime == null) { + return null; + } + return this.creationTime.dateTime(); + } + + /** + * Set the creationTime property: Returns the date and time the blob was + * created. + * + * @param creationTime the creationTime value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders creationTime(OffsetDateTime creationTime) { + if (creationTime == null) { + this.creationTime = null; + } else { + this.creationTime = new DateTimeRfc1123(creationTime); + } + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the blobType property: The blob's type. Possible values include: + * 'BlockBlob', 'PageBlob', 'AppendBlob'. + * + * @return the blobType value. + */ + public BlobType blobType() { + return this.blobType; + } + + /** + * Set the blobType property: The blob's type. Possible values include: + * 'BlockBlob', 'PageBlob', 'AppendBlob'. + * + * @param blobType the blobType value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders blobType(BlobType blobType) { + this.blobType = blobType; + return this; + } + + /** + * Get the copyCompletionTime property: Conclusion time of the last + * attempted Copy Blob operation where this blob was the destination blob. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @return the copyCompletionTime value. + */ + public OffsetDateTime copyCompletionTime() { + if (this.copyCompletionTime == null) { + return null; + } + return this.copyCompletionTime.dateTime(); + } + + /** + * Set the copyCompletionTime property: Conclusion time of the last + * attempted Copy Blob operation where this blob was the destination blob. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. This header does not appear if a copy is pending, if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @param copyCompletionTime the copyCompletionTime value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copyCompletionTime(OffsetDateTime copyCompletionTime) { + if (copyCompletionTime == null) { + this.copyCompletionTime = null; + } else { + this.copyCompletionTime = new DateTimeRfc1123(copyCompletionTime); + } + return this; + } + + /** + * Get the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear + * if this blob has never been the destination in a Copy Blob operation, or + * if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + * + * @return the copyStatusDescription value. + */ + public String copyStatusDescription() { + return this.copyStatusDescription; + } + + /** + * Set the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes the cause of the last + * fatal or non-fatal copy operation failure. This header does not appear + * if this blob has never been the destination in a Copy Blob operation, or + * if this blob has been modified after a concluded Copy Blob operation + * using Set Blob Properties, Put Blob, or Put Block List. + * + * @param copyStatusDescription the copyStatusDescription value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copyStatusDescription(String copyStatusDescription) { + this.copyStatusDescription = copyStatusDescription; + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @param copyId the copyId value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy Blob operation + * where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @return the copyProgress value. + */ + public String copyProgress() { + return this.copyProgress; + } + + /** + * Set the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy Blob operation + * where this blob was the destination blob. Can show between 0 and + * Content-Length bytes copied. This header does not appear if this blob + * has never been the destination in a Copy Blob operation, or if this blob + * has been modified after a concluded Copy Blob operation using Set Blob + * Properties, Put Blob, or Put Block List. + * + * @param copyProgress the copyProgress value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copyProgress(String copyProgress) { + this.copyProgress = copyProgress; + return this; + } + + /** + * Get the copySource property: URL up to 2 KB in length that specifies the + * source blob or file used in the last attempted Copy Blob operation where + * this blob was the destination blob. This header does not appear if this + * blob has never been the destination in a Copy Blob operation, or if this + * blob has been modified after a concluded Copy Blob operation using Set + * Blob Properties, Put Blob, or Put Block List. + * + * @return the copySource value. + */ + public String copySource() { + return this.copySource; + } + + /** + * Set the copySource property: URL up to 2 KB in length that specifies the + * source blob or file used in the last attempted Copy Blob operation where + * this blob was the destination blob. This header does not appear if this + * blob has never been the destination in a Copy Blob operation, or if this + * blob has been modified after a concluded Copy Blob operation using Set + * Blob Properties, Put Blob, or Put Block List. + * + * @param copySource the copySource value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copySource(String copySource) { + this.copySource = copySource; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the isIncrementalCopy property: Included if the blob is incremental + * copy blob. + * + * @return the isIncrementalCopy value. + */ + public Boolean isIncrementalCopy() { + return this.isIncrementalCopy; + } + + /** + * Set the isIncrementalCopy property: Included if the blob is incremental + * copy blob. + * + * @param isIncrementalCopy the isIncrementalCopy value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders isIncrementalCopy(Boolean isIncrementalCopy) { + this.isIncrementalCopy = isIncrementalCopy; + return this; + } + + /** + * Get the destinationSnapshot property: Included if the blob is + * incremental copy blob or incremental copy snapshot, if x-ms-copy-status + * is success. Snapshot time of the last successful incremental copy + * snapshot for this blob. + * + * @return the destinationSnapshot value. + */ + public String destinationSnapshot() { + return this.destinationSnapshot; + } + + /** + * Set the destinationSnapshot property: Included if the blob is + * incremental copy blob or incremental copy snapshot, if x-ms-copy-status + * is success. Snapshot time of the last successful incremental copy + * snapshot for this blob. + * + * @param destinationSnapshot the destinationSnapshot value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders destinationSnapshot(String destinationSnapshot) { + this.destinationSnapshot = destinationSnapshot; + return this; + } + + /** + * Get the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @return the leaseDuration value. + */ + public LeaseDurationType leaseDuration() { + return this.leaseDuration; + } + + /** + * Set the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @param leaseDuration the leaseDuration value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders leaseDuration(LeaseDurationType leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + /** + * Get the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @return the leaseState value. + */ + public LeaseStateType leaseState() { + return this.leaseState; + } + + /** + * Set the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @param leaseState the leaseState value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders leaseState(LeaseStateType leaseState) { + this.leaseState = leaseState; + return this; + } + + /** + * Get the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @return the leaseStatus value. + */ + public LeaseStatusType leaseStatus() { + return this.leaseStatus; + } + + /** + * Set the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @param leaseStatus the leaseStatus value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders leaseStatus(LeaseStatusType leaseStatus) { + this.leaseStatus = leaseStatus; + return this; + } + + /** + * Get the contentLength property: The number of bytes present in the + * response body. + * + * @return the contentLength value. + */ + public Long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: The number of bytes present in the + * response body. + * + * @param contentLength the contentLength value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentLength(Long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * Get the contentType property: The content type specified for the blob. + * The default content type is 'application/octet-stream'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The content type specified for the blob. + * The default content type is 'application/octet-stream'. + * + * @param contentType the contentType value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the contentEncoding property: This header returns the value that was + * specified for the Content-Encoding request header. + * + * @return the contentEncoding value. + */ + public String contentEncoding() { + return this.contentEncoding; + } + + /** + * Set the contentEncoding property: This header returns the value that was + * specified for the Content-Encoding request header. + * + * @param contentEncoding the contentEncoding value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * Get the contentDisposition property: This header returns the value that + * was specified for the 'x-ms-blob-content-disposition' header. The + * Content-Disposition response header field conveys additional information + * about how to process the response payload, and also can be used to + * attach additional metadata. For example, if set to attachment, it + * indicates that the user-agent should not display the response, but + * instead show a Save As dialog with a filename other than the blob name + * specified. + * + * @return the contentDisposition value. + */ + public String contentDisposition() { + return this.contentDisposition; + } + + /** + * Set the contentDisposition property: This header returns the value that + * was specified for the 'x-ms-blob-content-disposition' header. The + * Content-Disposition response header field conveys additional information + * about how to process the response payload, and also can be used to + * attach additional metadata. For example, if set to attachment, it + * indicates that the user-agent should not display the response, but + * instead show a Save As dialog with a filename other than the blob name + * specified. + * + * @param contentDisposition the contentDisposition value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * Get the contentLanguage property: This header returns the value that was + * specified for the Content-Language request header. + * + * @return the contentLanguage value. + */ + public String contentLanguage() { + return this.contentLanguage; + } + + /** + * Set the contentLanguage property: This header returns the value that was + * specified for the Content-Language request header. + * + * @param contentLanguage the contentLanguage value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * Get the cacheControl property: This header is returned if it was + * previously specified for the blob. + * + * @return the cacheControl value. + */ + public String cacheControl() { + return this.cacheControl; + } + + /** + * Set the cacheControl property: This header is returned if it was + * previously specified for the blob. + * + * @param cacheControl the cacheControl value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the acceptRanges property: Indicates that the service supports + * requests for partial blob content. + * + * @return the acceptRanges value. + */ + public String acceptRanges() { + return this.acceptRanges; + } + + /** + * Set the acceptRanges property: Indicates that the service supports + * requests for partial blob content. + * + * @param acceptRanges the acceptRanges value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders acceptRanges(String acceptRanges) { + this.acceptRanges = acceptRanges; + return this; + } + + /** + * Get the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @return the blobCommittedBlockCount value. + */ + public Integer blobCommittedBlockCount() { + return this.blobCommittedBlockCount; + } + + /** + * Set the blobCommittedBlockCount property: The number of committed blocks + * present in the blob. This header is returned only for append blobs. + * + * @param blobCommittedBlockCount the blobCommittedBlockCount value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders blobCommittedBlockCount(Integer blobCommittedBlockCount) { + this.blobCommittedBlockCount = blobCommittedBlockCount; + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the blob data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the blob is unencrypted, or if only parts of the blob/application + * metadata are encrypted). + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the blob data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the blob is unencrypted, or if only parts of the blob/application + * metadata are encrypted). + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the metadata. This header is only returned when the + * metadata was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the metadata. This header is only returned when the + * metadata was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the accessTier property: The tier of page blob on a premium storage + * account or tier of block blob on blob storage LRS accounts. For a list + * of allowed premium page blob tiers, see + * https://docs.microsoft.com/en-us/azure/virtual-machines/windows/premium-storage#features. + * For blob storage LRS accounts, valid values are Hot/Cool/Archive. + * + * @return the accessTier value. + */ + public String accessTier() { + return this.accessTier; + } + + /** + * Set the accessTier property: The tier of page blob on a premium storage + * account or tier of block blob on blob storage LRS accounts. For a list + * of allowed premium page blob tiers, see + * https://docs.microsoft.com/en-us/azure/virtual-machines/windows/premium-storage#features. + * For blob storage LRS accounts, valid values are Hot/Cool/Archive. + * + * @param accessTier the accessTier value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders accessTier(String accessTier) { + this.accessTier = accessTier; + return this; + } + + /** + * Get the accessTierInferred property: For page blobs on a premium storage + * account only. If the access tier is not explicitly set on the blob, the + * tier is inferred based on its content length and this header will be + * returned with true value. + * + * @return the accessTierInferred value. + */ + public Boolean accessTierInferred() { + return this.accessTierInferred; + } + + /** + * Set the accessTierInferred property: For page blobs on a premium storage + * account only. If the access tier is not explicitly set on the blob, the + * tier is inferred based on its content length and this header will be + * returned with true value. + * + * @param accessTierInferred the accessTierInferred value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders accessTierInferred(Boolean accessTierInferred) { + this.accessTierInferred = accessTierInferred; + return this; + } + + /** + * Get the archiveStatus property: For blob storage LRS accounts, valid + * values are rehydrate-pending-to-hot/rehydrate-pending-to-cool. If the + * blob is being rehydrated and is not complete then this header is + * returned indicating that rehydrate is pending and also tells the + * destination tier. + * + * @return the archiveStatus value. + */ + public String archiveStatus() { + return this.archiveStatus; + } + + /** + * Set the archiveStatus property: For blob storage LRS accounts, valid + * values are rehydrate-pending-to-hot/rehydrate-pending-to-cool. If the + * blob is being rehydrated and is not complete then this header is + * returned indicating that rehydrate is pending and also tells the + * destination tier. + * + * @param archiveStatus the archiveStatus value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders archiveStatus(String archiveStatus) { + this.archiveStatus = archiveStatus; + return this; + } + + /** + * Get the accessTierChangeTime property: The time the tier was changed on + * the object. This is only returned if the tier on the block blob was ever + * set. + * + * @return the accessTierChangeTime value. + */ + public OffsetDateTime accessTierChangeTime() { + if (this.accessTierChangeTime == null) { + return null; + } + return this.accessTierChangeTime.dateTime(); + } + + /** + * Set the accessTierChangeTime property: The time the tier was changed on + * the object. This is only returned if the tier on the block blob was ever + * set. + * + * @param accessTierChangeTime the accessTierChangeTime value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders accessTierChangeTime(OffsetDateTime accessTierChangeTime) { + if (accessTierChangeTime == null) { + this.accessTierChangeTime = null; + } else { + this.accessTierChangeTime = new DateTimeRfc1123(accessTierChangeTime); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobGetPropertiesHeaders object itself. + */ + public BlobGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHTTPHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHTTPHeaders.java new file mode 100644 index 0000000000000..aafbd1eb56e5e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHTTPHeaders.java @@ -0,0 +1,199 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Additional parameters for a set of operations. + */ +@JacksonXmlRootElement(localName = "blob-HTTP-headers") +public final class BlobHTTPHeaders { + /* + * Optional. Sets the blob's cache control. If specified, this property is + * stored with the blob and returned with a read request. + */ + @JsonProperty(value = "blobCacheControl") + private String blobCacheControl; + + /* + * Optional. Sets the blob's content type. If specified, this property is + * stored with the blob and returned with a read request. + */ + @JsonProperty(value = "blobContentType") + private String blobContentType; + + /* + * Optional. An MD5 hash of the blob content. Note that this hash is not + * validated, as the hashes for the individual blocks were validated when + * each was uploaded. + */ + @JsonProperty(value = "blobContentMD5") + private byte[] blobContentMD5; + + /* + * Optional. Sets the blob's content encoding. If specified, this property + * is stored with the blob and returned with a read request. + */ + @JsonProperty(value = "blobContentEncoding") + private String blobContentEncoding; + + /* + * Optional. Set the blob's content language. If specified, this property + * is stored with the blob and returned with a read request. + */ + @JsonProperty(value = "blobContentLanguage") + private String blobContentLanguage; + + /* + * Optional. Sets the blob's Content-Disposition header. + */ + @JsonProperty(value = "blobContentDisposition") + private String blobContentDisposition; + + /** + * Get the blobCacheControl property: Optional. Sets the blob's cache + * control. If specified, this property is stored with the blob and + * returned with a read request. + * + * @return the blobCacheControl value. + */ + public String blobCacheControl() { + return this.blobCacheControl; + } + + /** + * Set the blobCacheControl property: Optional. Sets the blob's cache + * control. If specified, this property is stored with the blob and + * returned with a read request. + * + * @param blobCacheControl the blobCacheControl value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobCacheControl(String blobCacheControl) { + this.blobCacheControl = blobCacheControl; + return this; + } + + /** + * Get the blobContentType property: Optional. Sets the blob's content + * type. If specified, this property is stored with the blob and returned + * with a read request. + * + * @return the blobContentType value. + */ + public String blobContentType() { + return this.blobContentType; + } + + /** + * Set the blobContentType property: Optional. Sets the blob's content + * type. If specified, this property is stored with the blob and returned + * with a read request. + * + * @param blobContentType the blobContentType value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobContentType(String blobContentType) { + this.blobContentType = blobContentType; + return this; + } + + /** + * Get the blobContentMD5 property: Optional. An MD5 hash of the blob + * content. Note that this hash is not validated, as the hashes for the + * individual blocks were validated when each was uploaded. + * + * @return the blobContentMD5 value. + */ + public byte[] blobContentMD5() { + return ImplUtils.clone(this.blobContentMD5); + } + + /** + * Set the blobContentMD5 property: Optional. An MD5 hash of the blob + * content. Note that this hash is not validated, as the hashes for the + * individual blocks were validated when each was uploaded. + * + * @param blobContentMD5 the blobContentMD5 value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobContentMD5(byte[] blobContentMD5) { + this.blobContentMD5 = ImplUtils.clone(blobContentMD5); + return this; + } + + /** + * Get the blobContentEncoding property: Optional. Sets the blob's content + * encoding. If specified, this property is stored with the blob and + * returned with a read request. + * + * @return the blobContentEncoding value. + */ + public String blobContentEncoding() { + return this.blobContentEncoding; + } + + /** + * Set the blobContentEncoding property: Optional. Sets the blob's content + * encoding. If specified, this property is stored with the blob and + * returned with a read request. + * + * @param blobContentEncoding the blobContentEncoding value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobContentEncoding(String blobContentEncoding) { + this.blobContentEncoding = blobContentEncoding; + return this; + } + + /** + * Get the blobContentLanguage property: Optional. Set the blob's content + * language. If specified, this property is stored with the blob and + * returned with a read request. + * + * @return the blobContentLanguage value. + */ + public String blobContentLanguage() { + return this.blobContentLanguage; + } + + /** + * Set the blobContentLanguage property: Optional. Set the blob's content + * language. If specified, this property is stored with the blob and + * returned with a read request. + * + * @param blobContentLanguage the blobContentLanguage value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobContentLanguage(String blobContentLanguage) { + this.blobContentLanguage = blobContentLanguage; + return this; + } + + /** + * Get the blobContentDisposition property: Optional. Sets the blob's + * Content-Disposition header. + * + * @return the blobContentDisposition value. + */ + public String blobContentDisposition() { + return this.blobContentDisposition; + } + + /** + * Set the blobContentDisposition property: Optional. Sets the blob's + * Content-Disposition header. + * + * @param blobContentDisposition the blobContentDisposition value to set. + * @return the BlobHTTPHeaders object itself. + */ + public BlobHTTPHeaders blobContentDisposition(String blobContentDisposition) { + this.blobContentDisposition = blobContentDisposition; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHierarchyListSegment.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHierarchyListSegment.java new file mode 100644 index 0000000000000..a70c2d2122f04 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobHierarchyListSegment.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * The BlobHierarchyListSegment model. + */ +@JacksonXmlRootElement(localName = "Blobs") +@JsonDeserialize(using = CustomHierarchicalListingDeserializer.class) +public final class BlobHierarchyListSegment { + /* + * The blobPrefixes property. + */ + @JsonProperty("BlobPrefix") + private List blobPrefixes = new ArrayList<>(); + + /* + * The blobItems property. + */ + @JsonProperty("Blob") + private List blobItems = new ArrayList<>(); + + /** + * Get the blobPrefixes property: The blobPrefixes property. + * + * @return the blobPrefixes value. + */ + public List blobPrefixes() { + return this.blobPrefixes; + } + + /** + * Set the blobPrefixes property: The blobPrefixes property. + * + * @param blobPrefixes the blobPrefixes value to set. + * @return the BlobHierarchyListSegment object itself. + */ + public BlobHierarchyListSegment blobPrefixes(List blobPrefixes) { + this.blobPrefixes = blobPrefixes; + return this; + } + + /** + * Get the blobItems property: The blobItems property. + * + * @return the blobItems value. + */ + public List blobItems() { + return this.blobItems; + } + + /** + * Set the blobItems property: The blobItems property. + * + * @param blobItems the blobItems value to set. + * @return the BlobHierarchyListSegment object itself. + */ + public BlobHierarchyListSegment blobItems(List blobItems) { + this.blobItems = blobItems; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobItem.java new file mode 100644 index 0000000000000..eb73dd3366b67 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobItem.java @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +import java.util.Map; + +/** + * An Azure Storage blob. + */ +@JacksonXmlRootElement(localName = "Blob") +public final class BlobItem { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The deleted property. + */ + @JsonProperty(value = "Deleted", required = true) + private boolean deleted; + + /* + * The snapshot property. + */ + @JsonProperty(value = "Snapshot", required = true) + private String snapshot; + + /* + * The versionId property. + */ + @JsonProperty(value = "VersionId", required = true) + private String versionId; + + /* + * The properties property. + */ + @JsonProperty(value = "Properties", required = true) + private BlobProperties properties; + + /* + * The metadata property. + */ + @JsonProperty(value = "Metadata") + private Map metadata; + + private boolean isPrefix = false; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the BlobItem object itself. + */ + public BlobItem name(String name) { + this.name = name; + return this; + } + + /** + * Get the deleted property: The deleted property. + * + * @return the deleted value. + */ + public boolean deleted() { + return this.deleted; + } + + /** + * Set the deleted property: The deleted property. + * + * @param deleted the deleted value to set. + * @return the BlobItem object itself. + */ + public BlobItem deleted(boolean deleted) { + this.deleted = deleted; + return this; + } + + /** + * Get the snapshot property: The snapshot property. + * + * @return the snapshot value. + */ + public String snapshot() { + return this.snapshot; + } + + /** + * Set the snapshot property: The snapshot property. + * + * @param snapshot the snapshot value to set. + * @return the BlobItem object itself. + */ + public BlobItem snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Get the versionId property: The versionId property. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: The versionId property. + * + * @param versionId the versionId value to set. + * @return the BlobItem object itself. + */ + public BlobItem versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the properties property: The properties property. + * + * @return the properties value. + */ + public BlobProperties properties() { + return this.properties; + } + + /** + * Set the properties property: The properties property. + * + * @param properties the properties value to set. + * @return the BlobItem object itself. + */ + public BlobItem properties(BlobProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the BlobItem object itself. + */ + public BlobItem metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * @return if the blob item is a prefix instead of an actual blob. + */ + public boolean isPrefix() { + return isPrefix; + } + + /** + * Sets if the blob item is a prefix instead of an actual blob + * @param isPrefix if the item is a prefix + * @return the BlobItem object itself + */ + public BlobItem isPrefix(boolean isPrefix) { + this.isPrefix = isPrefix; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java new file mode 100644 index 0000000000000..e69618951e88c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobListDetails.java @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.azure.storage.blob.ContainerClient; + +import java.util.ArrayList; + +/** + * This type allows users to specify additional information the service should return with each blob when listing blobs + * in a container (via a {@link ContainerClient} object). This type is immutable to ensure thread-safety of requests, so + * changing the details for a different listing operation requires construction of a new object. Null may be passed if + * none of the options are desirable. + */ +public final class BlobListDetails { + + private boolean copy; + + private boolean metadata; + + private boolean snapshots; + + private boolean uncommittedBlobs; + + private boolean deletedBlobs; + + public BlobListDetails() { + } + + /** + * Whether blob metadata related to any current or previous Copy Blob operation should be included in the + * response. + * + * @return a flag indicating if copy information will be returned in the listing + */ + public boolean copy() { + return copy; + } + + /** + * Whether blob metadata related to any current or previous Copy Blob operation should be included in the + * response. + * + * @param copy Flag indicating whether copy information should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails copy(boolean copy) { + this.copy = copy; + return this; + } + + /** + * Whether blob metadata should be returned. + * + * @return a flag indicating if metadata will be returned in the listing + */ + public boolean metadata() { + return metadata; + } + + /** + * Whether blob metadata should be returned. + * + * @param metadata Flag indicating whether metadata should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails metadata(boolean metadata) { + this.metadata = metadata; + return this; + } + + /** + * Whether snapshots should be returned. Snapshots are listed from oldest to newest. + * + * @return a flag indicating if snapshots will be returned in the listing + */ + public boolean snapshots() { + return snapshots; + } + + /** + * Whether snapshots should be returned. Snapshots are listed from oldest to newest. + * + * @param snapshots Flag indicating whether snapshots should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails snapshots(boolean snapshots) { + this.snapshots = snapshots; + return this; + } + + /** + * Whether blobs for which blocks have been uploaded, but which have not been committed using Put Block List, + * should be included in the response. + * + * @return a flag indicating if uncommitted blobs will be returned in the listing + */ + public boolean uncommittedBlobs() { + return uncommittedBlobs; + } + + /** + * Whether blobs for which blocks have been uploaded, but which have not been committed using Put Block List, + * should be included in the response. + * + * @param uncommittedBlobs Flag indicating whether uncommitted blobs should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails uncommittedBlobs(boolean uncommittedBlobs) { + this.uncommittedBlobs = uncommittedBlobs; + return this; + } + + /** + * Whether blobs which have been soft deleted should be returned. + * + * @return a flag indicating if deleted blobs will be returned in the listing + */ + public boolean deletedBlobs() { + return deletedBlobs; + } + + /** + * Whether blobs which have been soft deleted should be returned. + * + * @param deletedBlobs Flag indicating whether deleted blobs should be returned + * @return the updated BlobListDetails object + */ + public BlobListDetails deletedBlobs(boolean deletedBlobs) { + this.deletedBlobs = deletedBlobs; + return this; + } + + /** + * @return a list of the flag set to true + */ + public ArrayList toList() { + ArrayList details = new ArrayList(); + if (this.copy) { + details.add(ListBlobsIncludeItem.COPY); + } + if (this.deletedBlobs) { + details.add(ListBlobsIncludeItem.DELETED); + } + if (this.metadata) { + details.add(ListBlobsIncludeItem.METADATA); + } + if (this.snapshots) { + details.add(ListBlobsIncludeItem.SNAPSHOTS); + } + if (this.uncommittedBlobs) { + details.add(ListBlobsIncludeItem.UNCOMMITTEDBLOBS); + } + return details; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobMetadata.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobMetadata.java new file mode 100644 index 0000000000000..5753ff479dbfb --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobMetadata.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.Map; + +/** + * The BlobMetadata model. + */ +@JacksonXmlRootElement(localName = "Metadata") +public final class BlobMetadata { + /* + * Unmatched properties from the message are deserialized this collection + */ + @JsonProperty(value = "additionalProperties") + private Map additionalProperties; + + /* + * The encrypted property. + */ + @JacksonXmlProperty(localName = "Encrypted", isAttribute = true) + private String encrypted; + + /** + * Get the additionalProperties property: Unmatched properties from the + * message are deserialized this collection. + * + * @return the additionalProperties value. + */ + public Map additionalProperties() { + return this.additionalProperties; + } + + /** + * Set the additionalProperties property: Unmatched properties from the + * message are deserialized this collection. + * + * @param additionalProperties the additionalProperties value to set. + * @return the BlobMetadata object itself. + */ + public BlobMetadata additionalProperties(Map additionalProperties) { + this.additionalProperties = additionalProperties; + return this; + } + + /** + * Get the encrypted property: The encrypted property. + * + * @return the encrypted value. + */ + public String encrypted() { + return this.encrypted; + } + + /** + * Set the encrypted property: The encrypted property. + * + * @param encrypted the encrypted value to set. + * @return the BlobMetadata object itself. + */ + public BlobMetadata encrypted(String encrypted) { + this.encrypted = encrypted; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobPrefix.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobPrefix.java new file mode 100644 index 0000000000000..6507aaecfd380 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobPrefix.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The BlobPrefix model. + */ +@JacksonXmlRootElement(localName = "BlobPrefix") +public final class BlobPrefix { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the BlobPrefix object itself. + */ + public BlobPrefix name(String name) { + this.name = name; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobProperties.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobProperties.java new file mode 100644 index 0000000000000..a297fe40e0432 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobProperties.java @@ -0,0 +1,884 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Properties of a blob. + */ +@JacksonXmlRootElement(localName = "Properties") +public final class BlobProperties { + /* + * The creationTime property. + */ + @JsonProperty(value = "Creation-Time") + private DateTimeRfc1123 creationTime; + + /* + * The lastModified property. + */ + @JsonProperty(value = "Last-Modified", required = true) + private DateTimeRfc1123 lastModified; + + /* + * The etag property. + */ + @JsonProperty(value = "Etag", required = true) + private String etag; + + /* + * Size in bytes + */ + @JsonProperty(value = "Content-Length") + private Long contentLength; + + /* + * The contentType property. + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * The contentEncoding property. + */ + @JsonProperty(value = "Content-Encoding") + private String contentEncoding; + + /* + * The contentLanguage property. + */ + @JsonProperty(value = "Content-Language") + private String contentLanguage; + + /* + * The contentMD5 property. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * The contentDisposition property. + */ + @JsonProperty(value = "Content-Disposition") + private String contentDisposition; + + /* + * The cacheControl property. + */ + @JsonProperty(value = "Cache-Control") + private String cacheControl; + + /* + * The blobSequenceNumber property. + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * Possible values include: 'BlockBlob', 'PageBlob', 'AppendBlob' + */ + @JsonProperty(value = "BlobType") + private BlobType blobType; + + /* + * Possible values include: 'locked', 'unlocked' + */ + @JsonProperty(value = "LeaseStatus") + private LeaseStatusType leaseStatus; + + /* + * Possible values include: 'available', 'leased', 'expired', 'breaking', + * 'broken' + */ + @JsonProperty(value = "LeaseState") + private LeaseStateType leaseState; + + /* + * Possible values include: 'infinite', 'fixed' + */ + @JsonProperty(value = "LeaseDuration") + private LeaseDurationType leaseDuration; + + /* + * The copyId property. + */ + @JsonProperty(value = "CopyId") + private String copyId; + + /* + * Possible values include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "CopyStatus") + private CopyStatusType copyStatus; + + /* + * The copySource property. + */ + @JsonProperty(value = "CopySource") + private String copySource; + + /* + * The copyProgress property. + */ + @JsonProperty(value = "CopyProgress") + private String copyProgress; + + /* + * The copyCompletionTime property. + */ + @JsonProperty(value = "CopyCompletionTime") + private DateTimeRfc1123 copyCompletionTime; + + /* + * The copyStatusDescription property. + */ + @JsonProperty(value = "CopyStatusDescription") + private String copyStatusDescription; + + /* + * The serverEncrypted property. + */ + @JsonProperty(value = "ServerEncrypted") + private Boolean serverEncrypted; + + /* + * The incrementalCopy property. + */ + @JsonProperty(value = "IncrementalCopy") + private Boolean incrementalCopy; + + /* + * The destinationSnapshot property. + */ + @JsonProperty(value = "DestinationSnapshot") + private String destinationSnapshot; + + /* + * The deletedTime property. + */ + @JsonProperty(value = "DeletedTime") + private DateTimeRfc1123 deletedTime; + + /* + * The remainingRetentionDays property. + */ + @JsonProperty(value = "RemainingRetentionDays") + private Integer remainingRetentionDays; + + /* + * Possible values include: 'P4', 'P6', 'P10', 'P20', 'P30', 'P40', 'P50', + * 'Hot', 'Cool', 'Archive' + */ + @JsonProperty(value = "AccessTier") + private AccessTier accessTier; + + /* + * The accessTierInferred property. + */ + @JsonProperty(value = "AccessTierInferred") + private Boolean accessTierInferred; + + /* + * Possible values include: 'rehydrate-pending-to-hot', + * 'rehydrate-pending-to-cool' + */ + @JsonProperty(value = "ArchiveStatus") + private ArchiveStatus archiveStatus; + + /* + * The customerProvidedKeySha256 property. + */ + @JsonProperty(value = "CustomerProvidedKeySha256") + private String customerProvidedKeySha256; + + /* + * The accessTierChangeTime property. + */ + @JsonProperty(value = "AccessTierChangeTime") + private DateTimeRfc1123 accessTierChangeTime; + + /** + * Get the creationTime property: The creationTime property. + * + * @return the creationTime value. + */ + public OffsetDateTime creationTime() { + if (this.creationTime == null) { + return null; + } + return this.creationTime.dateTime(); + } + + /** + * Set the creationTime property: The creationTime property. + * + * @param creationTime the creationTime value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties creationTime(OffsetDateTime creationTime) { + if (creationTime == null) { + this.creationTime = null; + } else { + this.creationTime = new DateTimeRfc1123(creationTime); + } + return this; + } + + /** + * Get the lastModified property: The lastModified property. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: The lastModified property. + * + * @param lastModified the lastModified value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the etag property: The etag property. + * + * @return the etag value. + */ + public String etag() { + return this.etag; + } + + /** + * Set the etag property: The etag property. + * + * @param etag the etag value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties etag(String etag) { + this.etag = etag; + return this; + } + + /** + * Get the contentLength property: Size in bytes. + * + * @return the contentLength value. + */ + public Long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: Size in bytes. + * + * @param contentLength the contentLength value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentLength(Long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * Get the contentType property: The contentType property. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The contentType property. + * + * @param contentType the contentType value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the contentEncoding property: The contentEncoding property. + * + * @return the contentEncoding value. + */ + public String contentEncoding() { + return this.contentEncoding; + } + + /** + * Set the contentEncoding property: The contentEncoding property. + * + * @param contentEncoding the contentEncoding value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * Get the contentLanguage property: The contentLanguage property. + * + * @return the contentLanguage value. + */ + public String contentLanguage() { + return this.contentLanguage; + } + + /** + * Set the contentLanguage property: The contentLanguage property. + * + * @param contentLanguage the contentLanguage value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * Get the contentMD5 property: The contentMD5 property. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: The contentMD5 property. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the contentDisposition property: The contentDisposition property. + * + * @return the contentDisposition value. + */ + public String contentDisposition() { + return this.contentDisposition; + } + + /** + * Set the contentDisposition property: The contentDisposition property. + * + * @param contentDisposition the contentDisposition value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * Get the cacheControl property: The cacheControl property. + * + * @return the cacheControl value. + */ + public String cacheControl() { + return this.cacheControl; + } + + /** + * Set the cacheControl property: The cacheControl property. + * + * @param cacheControl the cacheControl value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * Get the blobSequenceNumber property: The blobSequenceNumber property. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The blobSequenceNumber property. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the blobType property: Possible values include: 'BlockBlob', + * 'PageBlob', 'AppendBlob'. + * + * @return the blobType value. + */ + public BlobType blobType() { + return this.blobType; + } + + /** + * Set the blobType property: Possible values include: 'BlockBlob', + * 'PageBlob', 'AppendBlob'. + * + * @param blobType the blobType value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties blobType(BlobType blobType) { + this.blobType = blobType; + return this; + } + + /** + * Get the leaseStatus property: Possible values include: 'locked', + * 'unlocked'. + * + * @return the leaseStatus value. + */ + public LeaseStatusType leaseStatus() { + return this.leaseStatus; + } + + /** + * Set the leaseStatus property: Possible values include: 'locked', + * 'unlocked'. + * + * @param leaseStatus the leaseStatus value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties leaseStatus(LeaseStatusType leaseStatus) { + this.leaseStatus = leaseStatus; + return this; + } + + /** + * Get the leaseState property: Possible values include: 'available', + * 'leased', 'expired', 'breaking', 'broken'. + * + * @return the leaseState value. + */ + public LeaseStateType leaseState() { + return this.leaseState; + } + + /** + * Set the leaseState property: Possible values include: 'available', + * 'leased', 'expired', 'breaking', 'broken'. + * + * @param leaseState the leaseState value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties leaseState(LeaseStateType leaseState) { + this.leaseState = leaseState; + return this; + } + + /** + * Get the leaseDuration property: Possible values include: 'infinite', + * 'fixed'. + * + * @return the leaseDuration value. + */ + public LeaseDurationType leaseDuration() { + return this.leaseDuration; + } + + /** + * Set the leaseDuration property: Possible values include: 'infinite', + * 'fixed'. + * + * @param leaseDuration the leaseDuration value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties leaseDuration(LeaseDurationType leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + /** + * Get the copyId property: The copyId property. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: The copyId property. + * + * @param copyId the copyId value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyStatus property: Possible values include: 'pending', + * 'success', 'aborted', 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: Possible values include: 'pending', + * 'success', 'aborted', 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the copySource property: The copySource property. + * + * @return the copySource value. + */ + public String copySource() { + return this.copySource; + } + + /** + * Set the copySource property: The copySource property. + * + * @param copySource the copySource value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copySource(String copySource) { + this.copySource = copySource; + return this; + } + + /** + * Get the copyProgress property: The copyProgress property. + * + * @return the copyProgress value. + */ + public String copyProgress() { + return this.copyProgress; + } + + /** + * Set the copyProgress property: The copyProgress property. + * + * @param copyProgress the copyProgress value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copyProgress(String copyProgress) { + this.copyProgress = copyProgress; + return this; + } + + /** + * Get the copyCompletionTime property: The copyCompletionTime property. + * + * @return the copyCompletionTime value. + */ + public OffsetDateTime copyCompletionTime() { + if (this.copyCompletionTime == null) { + return null; + } + return this.copyCompletionTime.dateTime(); + } + + /** + * Set the copyCompletionTime property: The copyCompletionTime property. + * + * @param copyCompletionTime the copyCompletionTime value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copyCompletionTime(OffsetDateTime copyCompletionTime) { + if (copyCompletionTime == null) { + this.copyCompletionTime = null; + } else { + this.copyCompletionTime = new DateTimeRfc1123(copyCompletionTime); + } + return this; + } + + /** + * Get the copyStatusDescription property: The copyStatusDescription + * property. + * + * @return the copyStatusDescription value. + */ + public String copyStatusDescription() { + return this.copyStatusDescription; + } + + /** + * Set the copyStatusDescription property: The copyStatusDescription + * property. + * + * @param copyStatusDescription the copyStatusDescription value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties copyStatusDescription(String copyStatusDescription) { + this.copyStatusDescription = copyStatusDescription; + return this; + } + + /** + * Get the serverEncrypted property: The serverEncrypted property. + * + * @return the serverEncrypted value. + */ + public Boolean serverEncrypted() { + return this.serverEncrypted; + } + + /** + * Set the serverEncrypted property: The serverEncrypted property. + * + * @param serverEncrypted the serverEncrypted value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties serverEncrypted(Boolean serverEncrypted) { + this.serverEncrypted = serverEncrypted; + return this; + } + + /** + * Get the incrementalCopy property: The incrementalCopy property. + * + * @return the incrementalCopy value. + */ + public Boolean incrementalCopy() { + return this.incrementalCopy; + } + + /** + * Set the incrementalCopy property: The incrementalCopy property. + * + * @param incrementalCopy the incrementalCopy value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties incrementalCopy(Boolean incrementalCopy) { + this.incrementalCopy = incrementalCopy; + return this; + } + + /** + * Get the destinationSnapshot property: The destinationSnapshot property. + * + * @return the destinationSnapshot value. + */ + public String destinationSnapshot() { + return this.destinationSnapshot; + } + + /** + * Set the destinationSnapshot property: The destinationSnapshot property. + * + * @param destinationSnapshot the destinationSnapshot value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties destinationSnapshot(String destinationSnapshot) { + this.destinationSnapshot = destinationSnapshot; + return this; + } + + /** + * Get the deletedTime property: The deletedTime property. + * + * @return the deletedTime value. + */ + public OffsetDateTime deletedTime() { + if (this.deletedTime == null) { + return null; + } + return this.deletedTime.dateTime(); + } + + /** + * Set the deletedTime property: The deletedTime property. + * + * @param deletedTime the deletedTime value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties deletedTime(OffsetDateTime deletedTime) { + if (deletedTime == null) { + this.deletedTime = null; + } else { + this.deletedTime = new DateTimeRfc1123(deletedTime); + } + return this; + } + + /** + * Get the remainingRetentionDays property: The remainingRetentionDays + * property. + * + * @return the remainingRetentionDays value. + */ + public Integer remainingRetentionDays() { + return this.remainingRetentionDays; + } + + /** + * Set the remainingRetentionDays property: The remainingRetentionDays + * property. + * + * @param remainingRetentionDays the remainingRetentionDays value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties remainingRetentionDays(Integer remainingRetentionDays) { + this.remainingRetentionDays = remainingRetentionDays; + return this; + } + + /** + * Get the accessTier property: Possible values include: 'P4', 'P6', 'P10', + * 'P20', 'P30', 'P40', 'P50', 'Hot', 'Cool', 'Archive'. + * + * @return the accessTier value. + */ + public AccessTier accessTier() { + return this.accessTier; + } + + /** + * Set the accessTier property: Possible values include: 'P4', 'P6', 'P10', + * 'P20', 'P30', 'P40', 'P50', 'Hot', 'Cool', 'Archive'. + * + * @param accessTier the accessTier value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties accessTier(AccessTier accessTier) { + this.accessTier = accessTier; + return this; + } + + /** + * Get the accessTierInferred property: The accessTierInferred property. + * + * @return the accessTierInferred value. + */ + public Boolean accessTierInferred() { + return this.accessTierInferred; + } + + /** + * Set the accessTierInferred property: The accessTierInferred property. + * + * @param accessTierInferred the accessTierInferred value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties accessTierInferred(Boolean accessTierInferred) { + this.accessTierInferred = accessTierInferred; + return this; + } + + /** + * Get the archiveStatus property: Possible values include: + * 'rehydrate-pending-to-hot', 'rehydrate-pending-to-cool'. + * + * @return the archiveStatus value. + */ + public ArchiveStatus archiveStatus() { + return this.archiveStatus; + } + + /** + * Set the archiveStatus property: Possible values include: + * 'rehydrate-pending-to-hot', 'rehydrate-pending-to-cool'. + * + * @param archiveStatus the archiveStatus value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties archiveStatus(ArchiveStatus archiveStatus) { + this.archiveStatus = archiveStatus; + return this; + } + + /** + * Get the customerProvidedKeySha256 property: The + * customerProvidedKeySha256 property. + * + * @return the customerProvidedKeySha256 value. + */ + public String customerProvidedKeySha256() { + return this.customerProvidedKeySha256; + } + + /** + * Set the customerProvidedKeySha256 property: The + * customerProvidedKeySha256 property. + * + * @param customerProvidedKeySha256 the customerProvidedKeySha256 value to + * set. + * @return the BlobProperties object itself. + */ + public BlobProperties customerProvidedKeySha256(String customerProvidedKeySha256) { + this.customerProvidedKeySha256 = customerProvidedKeySha256; + return this; + } + + /** + * Get the accessTierChangeTime property: The accessTierChangeTime + * property. + * + * @return the accessTierChangeTime value. + */ + public OffsetDateTime accessTierChangeTime() { + if (this.accessTierChangeTime == null) { + return null; + } + return this.accessTierChangeTime.dateTime(); + } + + /** + * Set the accessTierChangeTime property: The accessTierChangeTime + * property. + * + * @param accessTierChangeTime the accessTierChangeTime value to set. + * @return the BlobProperties object itself. + */ + public BlobProperties accessTierChangeTime(OffsetDateTime accessTierChangeTime) { + if (accessTierChangeTime == null) { + this.accessTierChangeTime = null; + } else { + this.accessTierChangeTime = new DateTimeRfc1123(accessTierChangeTime); + } + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRange.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRange.java new file mode 100644 index 0000000000000..183ebbf5664ad --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRange.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import java.util.Locale; + +/** + * This is a representation of a range of bytes on a blob, typically used during a download operation. This type is + * immutable to ensure thread-safety of requests, so changing the values for a different operation requires construction + * of a new object. Passing null as a BlobRange value will default to the entire range of the blob. + */ +public final class BlobRange { + private static final String RANGE_HEADER_FORMAT = "bytes=%d-%d"; + private static final String BEGIN_RANGE_HEADER_FORMAT = "bytes=%d-"; + + private long offset; + private Long count; + + /** + * Specifies the download operation to start from the offset position (zero-based) and download the + * rest of the entire blob to the end. + * + * @param offset + * the zero-based position to start downloading + */ + public BlobRange(long offset) { + if (offset < 0) { + throw new IllegalArgumentException("BlobRange offset must be greater than or equal to 0."); + } + this.offset = offset; + } + + /** + * Specifies the download operation to start from the offset position (zero-based) and download the + * count number of bytes. + * + * @param offset + * the zero-based position to start downloading + * @param count + * the number of bytes to download + */ + public BlobRange(long offset, long count) { + this(offset); + if (count < 0) { + throw new IllegalArgumentException( + "BlobRange count must be greater than or equal to 0 if specified."); + } + this.count = count; + } + + /** + * The start of the range. Must be greater than or equal to 0. + * + * @return the offset for the range + */ + public long offset() { + return offset; + } + + /** + * How many bytes to include in the range. Must be greater than or equal to 0 if specified. + * + * @return the number bytes to include in the range + */ + public Long count() { + return count; + } + + /** + * @return A {@code String} compliant with the format of the Azure Storage x-ms-range and Range headers. + */ + @Override + public String toString() { + if (this.count != null) { + long rangeEnd = this.offset + this.count - 1; + return String.format(Locale.ROOT, RANGE_HEADER_FORMAT, this.offset, rangeEnd); + } + + return String.format(Locale.ROOT, BEGIN_RANGE_HEADER_FORMAT, this.offset); + } + + /** + * @return {@link BlobRange#toString()} if {@code count} isn't {@code null} or {@code offset} isn't 0, otherwise null. + */ + public String toHeaderValue() { + // The default values of a BlobRange + if (this.offset == 0 && this.count == null) { + return null; + } + return this.toString(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobReleaseLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobReleaseLeaseHeaders.java new file mode 100644 index 0000000000000..661e9a24db979 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobReleaseLeaseHeaders.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ReleaseLease operation. + */ +@JacksonXmlRootElement(localName = "Blob-ReleaseLease-Headers") +public final class BlobReleaseLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobReleaseLeaseHeaders object itself. + */ + public BlobReleaseLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRenewLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRenewLeaseHeaders.java new file mode 100644 index 0000000000000..2ee66b3adb36b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobRenewLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for RenewLease operation. + */ +@JacksonXmlRootElement(localName = "Blob-RenewLease-Headers") +public final class BlobRenewLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the blob was last modified. Any operation that + * modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Uniquely identifies a blobs's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the blob was + * last modified. Any operation that modifies the blob, including an update + * of the blob's metadata or properties, changes the last-modified time of + * the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a blobs's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a blobs's lease. + * + * @param leaseId the leaseId value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobRenewLeaseHeaders object itself. + */ + public BlobRenewLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetHTTPHeadersHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetHTTPHeadersHeaders.java new file mode 100644 index 0000000000000..09111d5ae3e17 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetHTTPHeadersHeaders.java @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetHTTPHeaders operation. + */ +@JacksonXmlRootElement(localName = "Blob-SetHTTPHeaders-Headers") +public final class BlobSetHTTPHeadersHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The current sequence number for a page blob. This header is not returned + * for block blobs or append blobs + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobSetHTTPHeadersHeaders object itself. + */ + public BlobSetHTTPHeadersHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetMetadataHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetMetadataHeaders.java new file mode 100644 index 0000000000000..b831d8446cd1a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetMetadataHeaders.java @@ -0,0 +1,276 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "Blob-SetMetadata-Headers") +public final class BlobSetMetadataHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the metadata. + * This header is only returned when the metadata was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the metadata. This header is only returned when the + * metadata was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the metadata. This header is only returned when the + * metadata was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobSetMetadataHeaders object itself. + */ + public BlobSetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetTierHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetTierHeaders.java new file mode 100644 index 0000000000000..d2dd04c235a76 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobSetTierHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for SetTier operation. + */ +@JacksonXmlRootElement(localName = "Blob-SetTier-Headers") +public final class BlobSetTierHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * newer. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobSetTierHeaders object itself. + */ + public BlobSetTierHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and newer. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and newer. + * + * @param version the version value to set. + * @return the BlobSetTierHeaders object itself. + */ + public BlobSetTierHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobSetTierHeaders object itself. + */ + public BlobSetTierHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobStartCopyFromURLHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobStartCopyFromURLHeaders.java new file mode 100644 index 0000000000000..c0059d598cceb --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobStartCopyFromURLHeaders.java @@ -0,0 +1,307 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for StartCopyFromURL operation. + */ +@JacksonXmlRootElement(localName = "Blob-StartCopyFromURL-Headers") +public final class BlobStartCopyFromURLHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies the version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * String identifier for this copy operation. Use with Get Blob Properties + * to check the status of this copy operation, or pass to Abort Copy Blob + * to abort a pending copy. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies the version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @param copyId the copyId value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobStartCopyFromURLHeaders object itself. + */ + public BlobStartCopyFromURLHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobType.java new file mode 100644 index 0000000000000..65c3d499b6d50 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobType.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for BlobType. + */ +public enum BlobType { + /** + * Enum value BlockBlob. + */ + BLOCK_BLOB("BlockBlob"), + + /** + * Enum value PageBlob. + */ + PAGE_BLOB("PageBlob"), + + /** + * Enum value AppendBlob. + */ + APPEND_BLOB("AppendBlob"); + + /** + * The actual serialized value for a BlobType instance. + */ + private final String value; + + BlobType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a BlobType instance. + * + * @param value the serialized value to parse. + * @return the parsed BlobType object, or null if unable to parse. + */ + @JsonCreator + public static BlobType fromString(String value) { + BlobType[] items = BlobType.values(); + for (BlobType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobUndeleteHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobUndeleteHeaders.java new file mode 100644 index 0000000000000..3123885e3af1f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobUndeleteHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Undelete operation. + */ +@JacksonXmlRootElement(localName = "Blob-Undelete-Headers") +public final class BlobUndeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlobUndeleteHeaders object itself. + */ + public BlobUndeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlobUndeleteHeaders object itself. + */ + public BlobUndeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlobUndeleteHeaders object itself. + */ + public BlobUndeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlobUndeleteHeaders object itself. + */ + public BlobUndeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAbortCopyFromURLResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAbortCopyFromURLResponse.java new file mode 100644 index 0000000000000..00f2a2ca97598 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAbortCopyFromURLResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the abortCopyFromURL operation. + */ +public final class BlobsAbortCopyFromURLResponse extends ResponseBase { + /** + * Creates an instance of BlobsAbortCopyFromURLResponse. + * + * @param request the request which resulted in this BlobsAbortCopyFromURLResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsAbortCopyFromURLResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobAbortCopyFromURLHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAcquireLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAcquireLeaseResponse.java new file mode 100644 index 0000000000000..0073deeb63157 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsAcquireLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the acquireLease operation. + */ +public final class BlobsAcquireLeaseResponse extends ResponseBase { + /** + * Creates an instance of BlobsAcquireLeaseResponse. + * + * @param request the request which resulted in this BlobsAcquireLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsAcquireLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobAcquireLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsBreakLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsBreakLeaseResponse.java new file mode 100644 index 0000000000000..9f5f9fda05ea5 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsBreakLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the breakLease operation. + */ +public final class BlobsBreakLeaseResponse extends ResponseBase { + /** + * Creates an instance of BlobsBreakLeaseResponse. + * + * @param request the request which resulted in this BlobsBreakLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsBreakLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobBreakLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsChangeLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsChangeLeaseResponse.java new file mode 100644 index 0000000000000..eb807aceb583c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsChangeLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the changeLease operation. + */ +public final class BlobsChangeLeaseResponse extends ResponseBase { + /** + * Creates an instance of BlobsChangeLeaseResponse. + * + * @param request the request which resulted in this BlobsChangeLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsChangeLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobChangeLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCopyFromURLResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCopyFromURLResponse.java new file mode 100644 index 0000000000000..36220b0bf1be6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCopyFromURLResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the copyFromURL operation. + */ +public final class BlobsCopyFromURLResponse extends ResponseBase { + /** + * Creates an instance of BlobsCopyFromURLResponse. + * + * @param request the request which resulted in this BlobsCopyFromURLResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsCopyFromURLResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobCopyFromURLHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCreateSnapshotResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCreateSnapshotResponse.java new file mode 100644 index 0000000000000..3a76a46d1b72c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsCreateSnapshotResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the createSnapshot operation. + */ +public final class BlobsCreateSnapshotResponse extends ResponseBase { + /** + * Creates an instance of BlobsCreateSnapshotResponse. + * + * @param request the request which resulted in this BlobsCreateSnapshotResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsCreateSnapshotResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobCreateSnapshotHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDeleteResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDeleteResponse.java new file mode 100644 index 0000000000000..0222cdc4676d2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class BlobsDeleteResponse extends ResponseBase { + /** + * Creates an instance of BlobsDeleteResponse. + * + * @param request the request which resulted in this BlobsDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDownloadResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDownloadResponse.java new file mode 100644 index 0000000000000..1101ca18c80ec --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsDownloadResponse.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import io.netty.buffer.ByteBuf; +import java.io.Closeable; +import reactor.core.publisher.Flux; + +/** + * Contains all response data for the download operation. + */ +public final class BlobsDownloadResponse extends ResponseBase> implements Closeable { + /** + * Creates an instance of BlobsDownloadResponse. + * + * @param request the request which resulted in this BlobsDownloadResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the content stream. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsDownloadResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Flux value, BlobDownloadHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the response content stream. + */ + @Override + public Flux value() { + return super.value(); + } + + /** + * Disposes of the connection associated with this stream response. + */ + @Override + public void close() { + value().subscribe(bb -> { }, t -> { }).dispose(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetAccountInfoResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetAccountInfoResponse.java new file mode 100644 index 0000000000000..5b33d4b6f4958 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetAccountInfoResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getAccountInfo operation. + */ +public final class BlobsGetAccountInfoResponse extends ResponseBase { + /** + * Creates an instance of BlobsGetAccountInfoResponse. + * + * @param request the request which resulted in this BlobsGetAccountInfoResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsGetAccountInfoResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobGetAccountInfoHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetPropertiesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetPropertiesResponse.java new file mode 100644 index 0000000000000..de24a1b0b20ac --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class BlobsGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of BlobsGetPropertiesResponse. + * + * @param request the request which resulted in this BlobsGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsReleaseLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsReleaseLeaseResponse.java new file mode 100644 index 0000000000000..f379ead4105b2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsReleaseLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the releaseLease operation. + */ +public final class BlobsReleaseLeaseResponse extends ResponseBase { + /** + * Creates an instance of BlobsReleaseLeaseResponse. + * + * @param request the request which resulted in this BlobsReleaseLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsReleaseLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobReleaseLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsRenewLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsRenewLeaseResponse.java new file mode 100644 index 0000000000000..53dfcb83563a8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsRenewLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the renewLease operation. + */ +public final class BlobsRenewLeaseResponse extends ResponseBase { + /** + * Creates an instance of BlobsRenewLeaseResponse. + * + * @param request the request which resulted in this BlobsRenewLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsRenewLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobRenewLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetHTTPHeadersResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetHTTPHeadersResponse.java new file mode 100644 index 0000000000000..6e52d09d1b8b2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetHTTPHeadersResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setHTTPHeaders operation. + */ +public final class BlobsSetHTTPHeadersResponse extends ResponseBase { + /** + * Creates an instance of BlobsSetHTTPHeadersResponse. + * + * @param request the request which resulted in this BlobsSetHTTPHeadersResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsSetHTTPHeadersResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobSetHTTPHeadersHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetMetadataResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetMetadataResponse.java new file mode 100644 index 0000000000000..e9979fdcb85b7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class BlobsSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of BlobsSetMetadataResponse. + * + * @param request the request which resulted in this BlobsSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobSetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetTierResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetTierResponse.java new file mode 100644 index 0000000000000..d11f828184716 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsSetTierResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setTier operation. + */ +public final class BlobsSetTierResponse extends ResponseBase { + /** + * Creates an instance of BlobsSetTierResponse. + * + * @param request the request which resulted in this BlobsSetTierResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsSetTierResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobSetTierHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsStartCopyFromURLResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsStartCopyFromURLResponse.java new file mode 100644 index 0000000000000..6c7821de05f35 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsStartCopyFromURLResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the startCopyFromURL operation. + */ +public final class BlobsStartCopyFromURLResponse extends ResponseBase { + /** + * Creates an instance of BlobsStartCopyFromURLResponse. + * + * @param request the request which resulted in this BlobsStartCopyFromURLResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsStartCopyFromURLResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobStartCopyFromURLHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsUndeleteResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsUndeleteResponse.java new file mode 100644 index 0000000000000..21cf7a0cbe9f8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlobsUndeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the undelete operation. + */ +public final class BlobsUndeleteResponse extends ResponseBase { + /** + * Creates an instance of BlobsUndeleteResponse. + * + * @param request the request which resulted in this BlobsUndeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlobsUndeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlobUndeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/Block.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Block.java new file mode 100644 index 0000000000000..8fbfcaa8a7abe --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Block.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Represents a single block in a block blob. It describes the block's ID and + * size. + */ +@JacksonXmlRootElement(localName = "Block") +public final class Block { + /* + * The base64 encoded block ID. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The block size in bytes. + */ + @JsonProperty(value = "Size", required = true) + private int size; + + /** + * Get the name property: The base64 encoded block ID. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The base64 encoded block ID. + * + * @param name the name value to set. + * @return the Block object itself. + */ + public Block name(String name) { + this.name = name; + return this; + } + + /** + * Get the size property: The block size in bytes. + * + * @return the size value. + */ + public int size() { + return this.size; + } + + /** + * Set the size property: The block size in bytes. + * + * @param size the size value to set. + * @return the Block object itself. + */ + public Block size(int size) { + this.size = size; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobCommitBlockListHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobCommitBlockListHeaders.java new file mode 100644 index 0000000000000..a2605e19cf430 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobCommitBlockListHeaders.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for CommitBlockList operation. + */ +@JacksonXmlRootElement(localName = "BlockBlob-CommitBlockList-Headers") +public final class BlockBlobCommitBlockListHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies a version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the blob. This + * header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlockBlobCommitBlockListHeaders object itself. + */ + public BlockBlobCommitBlockListHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobGetBlockListHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobGetBlockListHeaders.java new file mode 100644 index 0000000000000..26d77f85abadf --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobGetBlockListHeaders.java @@ -0,0 +1,267 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetBlockList operation. + */ +@JacksonXmlRootElement(localName = "BlockBlob-GetBlockList-Headers") +public final class BlockBlobGetBlockListHeaders { + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * The media type of the body of the response. For Get Block List this is + * 'application/xml' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * The size of the blob in bytes. + */ + @JsonProperty(value = "x-ms-blob-content-length") + private Long blobContentLength; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the contentType property: The media type of the body of the + * response. For Get Block List this is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The media type of the body of the + * response. For Get Block List this is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the blobContentLength property: The size of the blob in bytes. + * + * @return the blobContentLength value. + */ + public Long blobContentLength() { + return this.blobContentLength; + } + + /** + * Set the blobContentLength property: The size of the blob in bytes. + * + * @param blobContentLength the blobContentLength value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders blobContentLength(Long blobContentLength) { + this.blobContentLength = blobContentLength; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlockBlobGetBlockListHeaders object itself. + */ + public BlockBlobGetBlockListHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobItem.java new file mode 100644 index 0000000000000..3d73a020dd93d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobItem.java @@ -0,0 +1,46 @@ +package com.azure.storage.blob.models; + +import com.azure.core.implementation.util.ImplUtils; + +import java.time.OffsetDateTime; + +public class BlockBlobItem { + + private OffsetDateTime lastModified; + + private final byte[] contentMD5; + + private Boolean isServerEncrypted; + + private String encryptionKeySha256; + + public BlockBlobItem(BlockBlobUploadHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + } + + public BlockBlobItem(BlockBlobCommitBlockListHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + } + + public OffsetDateTime lastModified() { + return lastModified; + }; + + public Boolean isServerEncrypted() { + return isServerEncrypted; + } + + public String encryptionKeySha256() { + return encryptionKeySha256; + } + + public byte[] contentMD5() { + return ImplUtils.clone(contentMD5); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockFromURLHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockFromURLHeaders.java new file mode 100644 index 0000000000000..1b434c919342f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockFromURLHeaders.java @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for StageBlockFromURL operation. + */ +@JacksonXmlRootElement(localName = "BlockBlob-StageBlockFromURL-Headers") +public final class BlockBlobStageBlockFromURLHeaders { + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the block. This + * header is only returned when the block was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlockBlobStageBlockFromURLHeaders object itself. + */ + public BlockBlobStageBlockFromURLHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockHeaders.java new file mode 100644 index 0000000000000..40108ad24ec2a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobStageBlockHeaders.java @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for StageBlock operation. + */ +@JacksonXmlRootElement(localName = "BlockBlob-StageBlock-Headers") +public final class BlockBlobStageBlockHeaders { + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the block. This + * header is only returned when the block was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the block. This header is only returned when the + * block was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlockBlobStageBlockHeaders object itself. + */ + public BlockBlobStageBlockHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobUploadHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobUploadHeaders.java new file mode 100644 index 0000000000000..e5430e100e6ea --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobUploadHeaders.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Upload operation. + */ +@JacksonXmlRootElement(localName = "BlockBlob-Upload-Headers") +public final class BlockBlobUploadHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies a version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the blob. This + * header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the BlockBlobUploadHeaders object itself. + */ + public BlockBlobUploadHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsCommitBlockListResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsCommitBlockListResponse.java new file mode 100644 index 0000000000000..e68cbc1f07702 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsCommitBlockListResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the commitBlockList operation. + */ +public final class BlockBlobsCommitBlockListResponse extends ResponseBase { + /** + * Creates an instance of BlockBlobsCommitBlockListResponse. + * + * @param request the request which resulted in this BlockBlobsCommitBlockListResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlockBlobsCommitBlockListResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlockBlobCommitBlockListHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsGetBlockListResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsGetBlockListResponse.java new file mode 100644 index 0000000000000..beddda624e0dc --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsGetBlockListResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getBlockList operation. + */ +public final class BlockBlobsGetBlockListResponse extends ResponseBase { + /** + * Creates an instance of BlockBlobsGetBlockListResponse. + * + * @param request the request which resulted in this BlockBlobsGetBlockListResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlockBlobsGetBlockListResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, BlockList value, BlockBlobGetBlockListHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public BlockList value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockFromURLResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockFromURLResponse.java new file mode 100644 index 0000000000000..848a75fefcb7b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockFromURLResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the stageBlockFromURL operation. + */ +public final class BlockBlobsStageBlockFromURLResponse extends ResponseBase { + /** + * Creates an instance of BlockBlobsStageBlockFromURLResponse. + * + * @param request the request which resulted in this BlockBlobsStageBlockFromURLResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlockBlobsStageBlockFromURLResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlockBlobStageBlockFromURLHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockResponse.java new file mode 100644 index 0000000000000..9a1e5f8a2cbae --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsStageBlockResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the stageBlock operation. + */ +public final class BlockBlobsStageBlockResponse extends ResponseBase { + /** + * Creates an instance of BlockBlobsStageBlockResponse. + * + * @param request the request which resulted in this BlockBlobsStageBlockResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlockBlobsStageBlockResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlockBlobStageBlockHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsUploadResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsUploadResponse.java new file mode 100644 index 0000000000000..aa667bea4116c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockBlobsUploadResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the upload operation. + */ +public final class BlockBlobsUploadResponse extends ResponseBase { + /** + * Creates an instance of BlockBlobsUploadResponse. + * + * @param request the request which resulted in this BlockBlobsUploadResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public BlockBlobsUploadResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, BlockBlobUploadHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockItem.java new file mode 100644 index 0000000000000..4920fd7334a14 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockItem.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +/** + * Represents a single block in a block blob. + */ +public final class BlockItem { + /* Internal block object. */ + private Block block; + + private boolean isCommitted; + + /** + * Creates an instance of a BlobItem. + * @param block the API blob object + * @param isCommitted if the blob is committed + */ + public BlockItem(Block block, boolean isCommitted) { + this.block = block; + this.isCommitted = isCommitted; + } + + /** + * @return the base64 encoded block ID. + */ + public String name() { + return this.block.name(); + } + + /** + * @return the block size in bytes. + */ + public int size() { + return this.block.size(); + } + + /** + * @return if the block has been committed. + */ + public boolean isCommitted() { + return isCommitted; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockList.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockList.java new file mode 100644 index 0000000000000..70a0fb8d312ef --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockList.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * The BlockList model. + */ +@JacksonXmlRootElement(localName = "BlockList") +public final class BlockList { + private static final class CommittedBlocksWrapper { + @JacksonXmlProperty(localName = "Block") + private final List items; + + @JsonCreator + private CommittedBlocksWrapper(@JacksonXmlProperty(localName = "Block") List items) { + this.items = items; + } + } + + /* + * The committedBlocks property. + */ + @JsonProperty(value = "CommittedBlocks") + private CommittedBlocksWrapper committedBlocks; + + private static final class UncommittedBlocksWrapper { + @JacksonXmlProperty(localName = "Block") + private final List items; + + @JsonCreator + private UncommittedBlocksWrapper(@JacksonXmlProperty(localName = "Block") List items) { + this.items = items; + } + } + + /* + * The uncommittedBlocks property. + */ + @JsonProperty(value = "UncommittedBlocks") + private UncommittedBlocksWrapper uncommittedBlocks; + + /** + * Get the committedBlocks property: The committedBlocks property. + * + * @return the committedBlocks value. + */ + public List committedBlocks() { + if (this.committedBlocks == null) { + this.committedBlocks = new CommittedBlocksWrapper(new ArrayList()); + } + return this.committedBlocks.items; + } + + /** + * Set the committedBlocks property: The committedBlocks property. + * + * @param committedBlocks the committedBlocks value to set. + * @return the BlockList object itself. + */ + public BlockList committedBlocks(List committedBlocks) { + this.committedBlocks = new CommittedBlocksWrapper(committedBlocks); + return this; + } + + /** + * Get the uncommittedBlocks property: The uncommittedBlocks property. + * + * @return the uncommittedBlocks value. + */ + public List uncommittedBlocks() { + if (this.uncommittedBlocks == null) { + this.uncommittedBlocks = new UncommittedBlocksWrapper(new ArrayList()); + } + return this.uncommittedBlocks.items; + } + + /** + * Set the uncommittedBlocks property: The uncommittedBlocks property. + * + * @param uncommittedBlocks the uncommittedBlocks value to set. + * @return the BlockList object itself. + */ + public BlockList uncommittedBlocks(List uncommittedBlocks) { + this.uncommittedBlocks = new UncommittedBlocksWrapper(uncommittedBlocks); + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockListType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockListType.java new file mode 100644 index 0000000000000..e02ffbda9026a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockListType.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for BlockListType. + */ +public enum BlockListType { + /** + * Enum value committed. + */ + COMMITTED("committed"), + + /** + * Enum value uncommitted. + */ + UNCOMMITTED("uncommitted"), + + /** + * Enum value all. + */ + ALL("all"); + + /** + * The actual serialized value for a BlockListType instance. + */ + private final String value; + + BlockListType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a BlockListType instance. + * + * @param value the serialized value to parse. + * @return the parsed BlockListType object, or null if unable to parse. + */ + @JsonCreator + public static BlockListType fromString(String value) { + BlockListType[] items = BlockListType.values(); + for (BlockListType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockLookupList.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockLookupList.java new file mode 100644 index 0000000000000..9cc63338a8996 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/BlockLookupList.java @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * The BlockLookupList model. + */ +@JacksonXmlRootElement(localName = "BlockList") +public final class BlockLookupList { + /* + * The committed property. + */ + @JsonProperty("Committed") + private List committed = new ArrayList<>(); + + /* + * The uncommitted property. + */ + @JsonProperty("Uncommitted") + private List uncommitted = new ArrayList<>(); + + /* + * The latest property. + */ + @JsonProperty("Latest") + private List latest = new ArrayList<>(); + + /** + * Get the committed property: The committed property. + * + * @return the committed value. + */ + public List committed() { + return this.committed; + } + + /** + * Set the committed property: The committed property. + * + * @param committed the committed value to set. + * @return the BlockLookupList object itself. + */ + public BlockLookupList committed(List committed) { + this.committed = committed; + return this; + } + + /** + * Get the uncommitted property: The uncommitted property. + * + * @return the uncommitted value. + */ + public List uncommitted() { + return this.uncommitted; + } + + /** + * Set the uncommitted property: The uncommitted property. + * + * @param uncommitted the uncommitted value to set. + * @return the BlockLookupList object itself. + */ + public BlockLookupList uncommitted(List uncommitted) { + this.uncommitted = uncommitted; + return this; + } + + /** + * Get the latest property: The latest property. + * + * @return the latest value. + */ + public List latest() { + return this.latest; + } + + /** + * Set the latest property: The latest property. + * + * @param latest the latest value to set. + * @return the BlockLookupList object itself. + */ + public BlockLookupList latest(List latest) { + this.latest = latest; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ClearRange.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ClearRange.java new file mode 100644 index 0000000000000..cb8d7a208ab3a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ClearRange.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The ClearRange model. + */ +@JacksonXmlRootElement(localName = "ClearRange") +public final class ClearRange { + /* + * The start property. + */ + @JsonProperty(value = "Start", required = true) + private long start; + + /* + * The end property. + */ + @JsonProperty(value = "End", required = true) + private long end; + + /** + * Get the start property: The start property. + * + * @return the start value. + */ + public long start() { + return this.start; + } + + /** + * Set the start property: The start property. + * + * @param start the start value to set. + * @return the ClearRange object itself. + */ + public ClearRange start(long start) { + this.start = start; + return this; + } + + /** + * Get the end property: The end property. + * + * @return the end value. + */ + public long end() { + return this.end; + } + + /** + * Set the end property: The end property. + * + * @param end the end value to set. + * @return the ClearRange object itself. + */ + public ClearRange end(long end) { + this.end = end; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessConditions.java new file mode 100644 index 0000000000000..49346dc686fb4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessConditions.java @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +/** + * This class contains values which will restrict the successful operation of a variety of requests to the conditions + * present. These conditions are entirely optional. The entire object or any of its properties may be set to null when + * passed to a method to indicate that those conditions are not desired. Please refer to the type of each field for more + * information on those particular access conditions. + */ +public final class ContainerAccessConditions { + + private ModifiedAccessConditions modifiedAccessConditions; + + private LeaseAccessConditions leaseAccessConditions; + + /** + * Creates an instance which has fields set to non-null, empty values. + */ + public ContainerAccessConditions() { + this.modifiedAccessConditions = new ModifiedAccessConditions(); + this.leaseAccessConditions = new LeaseAccessConditions(); + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return the modified access conditions + */ + public ModifiedAccessConditions modifiedAccessConditions() { + return modifiedAccessConditions; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @param modifiedAccessConditions the modified access conditions to set + * @return the updated ContainerAccessConditions object + */ + public ContainerAccessConditions modifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) { + this.modifiedAccessConditions = modifiedAccessConditions; + return this; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @return the lease access conditions + */ + public LeaseAccessConditions leaseAccessConditions() { + return leaseAccessConditions; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @param leaseID the lease access conditions to set + * @return the updated ContainerAccessConditions object + */ + public ContainerAccessConditions leaseAccessConditions(LeaseAccessConditions leaseID) { + this.leaseAccessConditions = leaseID; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessPolicies.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessPolicies.java new file mode 100644 index 0000000000000..b9c396c7169ca --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAccessPolicies.java @@ -0,0 +1,21 @@ +package com.azure.storage.blob.models; + +import java.util.List; + +public class ContainerAccessPolicies { + private final PublicAccessType blobAccessType; + private final List identifiers; + + public ContainerAccessPolicies(PublicAccessType blobAccessType, List identifiers) { + this.blobAccessType = blobAccessType; + this.identifiers = identifiers; + } + + public PublicAccessType getBlobAccessType() { + return blobAccessType; + } + + public List getIdentifiers() { + return this.identifiers; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAcquireLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAcquireLeaseHeaders.java new file mode 100644 index 0000000000000..0ba172f04e33a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerAcquireLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AcquireLease operation. + */ +@JacksonXmlRootElement(localName = "Container-AcquireLease-Headers") +public final class ContainerAcquireLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Uniquely identifies a container's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a container's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a container's lease. + * + * @param leaseId the leaseId value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerAcquireLeaseHeaders object itself. + */ + public ContainerAcquireLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerBreakLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerBreakLeaseHeaders.java new file mode 100644 index 0000000000000..98a1106ccc6ef --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerBreakLeaseHeaders.java @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for BreakLease operation. + */ +@JacksonXmlRootElement(localName = "Container-BreakLease-Headers") +public final class ContainerBreakLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Approximate time remaining in the lease period, in seconds. + */ + @JsonProperty(value = "x-ms-lease-time") + private Integer leaseTime; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseTime property: Approximate time remaining in the lease + * period, in seconds. + * + * @return the leaseTime value. + */ + public Integer leaseTime() { + return this.leaseTime; + } + + /** + * Set the leaseTime property: Approximate time remaining in the lease + * period, in seconds. + * + * @param leaseTime the leaseTime value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders leaseTime(Integer leaseTime) { + this.leaseTime = leaseTime; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerBreakLeaseHeaders object itself. + */ + public ContainerBreakLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerChangeLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerChangeLeaseHeaders.java new file mode 100644 index 0000000000000..880214fc46b52 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerChangeLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ChangeLease operation. + */ +@JacksonXmlRootElement(localName = "Container-ChangeLease-Headers") +public final class ContainerChangeLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Uniquely identifies a container's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a container's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a container's lease. + * + * @param leaseId the leaseId value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerChangeLeaseHeaders object itself. + */ + public ContainerChangeLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerCreateHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerCreateHeaders.java new file mode 100644 index 0000000000000..280734c615016 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerCreateHeaders.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "Container-Create-Headers") +public final class ContainerCreateHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerCreateHeaders object itself. + */ + public ContainerCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerDeleteHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerDeleteHeaders.java new file mode 100644 index 0000000000000..52f2623a635d5 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerDeleteHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "Container-Delete-Headers") +public final class ContainerDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerDeleteHeaders object itself. + */ + public ContainerDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerDeleteHeaders object itself. + */ + public ContainerDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerDeleteHeaders object itself. + */ + public ContainerDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerDeleteHeaders object itself. + */ + public ContainerDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccessPolicyHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..4905b3c2949fe --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccessPolicyHeaders.java @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Container-GetAccessPolicy-Headers") +public final class ContainerGetAccessPolicyHeaders { + /* + * Indicated whether data in the container may be accessed publicly and the + * level of access. Possible values include: 'container', 'blob' + */ + @JsonProperty(value = "x-ms-blob-public-access") + private PublicAccessType blobPublicAccess; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the blobPublicAccess property: Indicated whether data in the + * container may be accessed publicly and the level of access. Possible + * values include: 'container', 'blob'. + * + * @return the blobPublicAccess value. + */ + public PublicAccessType blobPublicAccess() { + return this.blobPublicAccess; + } + + /** + * Set the blobPublicAccess property: Indicated whether data in the + * container may be accessed publicly and the level of access. Possible + * values include: 'container', 'blob'. + * + * @param blobPublicAccess the blobPublicAccess value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders blobPublicAccess(PublicAccessType blobPublicAccess) { + this.blobPublicAccess = blobPublicAccess; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerGetAccessPolicyHeaders object itself. + */ + public ContainerGetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccountInfoHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccountInfoHeaders.java new file mode 100644 index 0000000000000..c82baa2c1a6b7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetAccountInfoHeaders.java @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccountInfo operation. + */ +@JacksonXmlRootElement(localName = "Container-GetAccountInfo-Headers") +public final class ContainerGetAccountInfoHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Identifies the sku name of the account. Possible values include: + * 'Standard_LRS', 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', + * 'Premium_LRS' + */ + @JsonProperty(value = "x-ms-sku-name") + private SkuName skuName; + + /* + * Identifies the account kind. Possible values include: 'Storage', + * 'BlobStorage', 'StorageV2' + */ + @JsonProperty(value = "x-ms-account-kind") + private AccountKind accountKind; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @return the skuName value. + */ + public SkuName skuName() { + return this.skuName; + } + + /** + * Set the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @param skuName the skuName value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders skuName(SkuName skuName) { + this.skuName = skuName; + return this; + } + + /** + * Get the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @return the accountKind value. + */ + public AccountKind accountKind() { + return this.accountKind; + } + + /** + * Set the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @param accountKind the accountKind value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders accountKind(AccountKind accountKind) { + this.accountKind = accountKind; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerGetAccountInfoHeaders object itself. + */ + public ContainerGetAccountInfoHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetPropertiesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetPropertiesHeaders.java new file mode 100644 index 0000000000000..b37286c1b7af3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerGetPropertiesHeaders.java @@ -0,0 +1,416 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Container-GetProperties-Headers") +public final class ContainerGetPropertiesHeaders { + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * When a blob is leased, specifies whether the lease is of infinite or + * fixed duration. Possible values include: 'infinite', 'fixed' + */ + @JsonProperty(value = "x-ms-lease-duration") + private LeaseDurationType leaseDuration; + + /* + * Lease state of the blob. Possible values include: 'available', 'leased', + * 'expired', 'breaking', 'broken' + */ + @JsonProperty(value = "x-ms-lease-state") + private LeaseStateType leaseState; + + /* + * The current lease status of the blob. Possible values include: 'locked', + * 'unlocked' + */ + @JsonProperty(value = "x-ms-lease-status") + private LeaseStatusType leaseStatus; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Indicated whether data in the container may be accessed publicly and the + * level of access. Possible values include: 'container', 'blob' + */ + @JsonProperty(value = "x-ms-blob-public-access") + private PublicAccessType blobPublicAccess; + + /* + * Indicates whether the container has an immutability policy set on it. + */ + @JsonProperty(value = "x-ms-has-immutability-policy") + private Boolean hasImmutabilityPolicy; + + /* + * Indicates whether the container has a legal hold. + */ + @JsonProperty(value = "x-ms-has-legal-hold") + private Boolean hasLegalHold; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @return the leaseDuration value. + */ + public LeaseDurationType leaseDuration() { + return this.leaseDuration; + } + + /** + * Set the leaseDuration property: When a blob is leased, specifies whether + * the lease is of infinite or fixed duration. Possible values include: + * 'infinite', 'fixed'. + * + * @param leaseDuration the leaseDuration value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders leaseDuration(LeaseDurationType leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + /** + * Get the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @return the leaseState value. + */ + public LeaseStateType leaseState() { + return this.leaseState; + } + + /** + * Set the leaseState property: Lease state of the blob. Possible values + * include: 'available', 'leased', 'expired', 'breaking', 'broken'. + * + * @param leaseState the leaseState value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders leaseState(LeaseStateType leaseState) { + this.leaseState = leaseState; + return this; + } + + /** + * Get the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @return the leaseStatus value. + */ + public LeaseStatusType leaseStatus() { + return this.leaseStatus; + } + + /** + * Set the leaseStatus property: The current lease status of the blob. + * Possible values include: 'locked', 'unlocked'. + * + * @param leaseStatus the leaseStatus value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders leaseStatus(LeaseStatusType leaseStatus) { + this.leaseStatus = leaseStatus; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the blobPublicAccess property: Indicated whether data in the + * container may be accessed publicly and the level of access. Possible + * values include: 'container', 'blob'. + * + * @return the blobPublicAccess value. + */ + public PublicAccessType blobPublicAccess() { + return this.blobPublicAccess; + } + + /** + * Set the blobPublicAccess property: Indicated whether data in the + * container may be accessed publicly and the level of access. Possible + * values include: 'container', 'blob'. + * + * @param blobPublicAccess the blobPublicAccess value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders blobPublicAccess(PublicAccessType blobPublicAccess) { + this.blobPublicAccess = blobPublicAccess; + return this; + } + + /** + * Get the hasImmutabilityPolicy property: Indicates whether the container + * has an immutability policy set on it. + * + * @return the hasImmutabilityPolicy value. + */ + public Boolean hasImmutabilityPolicy() { + return this.hasImmutabilityPolicy; + } + + /** + * Set the hasImmutabilityPolicy property: Indicates whether the container + * has an immutability policy set on it. + * + * @param hasImmutabilityPolicy the hasImmutabilityPolicy value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders hasImmutabilityPolicy(Boolean hasImmutabilityPolicy) { + this.hasImmutabilityPolicy = hasImmutabilityPolicy; + return this; + } + + /** + * Get the hasLegalHold property: Indicates whether the container has a + * legal hold. + * + * @return the hasLegalHold value. + */ + public Boolean hasLegalHold() { + return this.hasLegalHold; + } + + /** + * Set the hasLegalHold property: Indicates whether the container has a + * legal hold. + * + * @param hasLegalHold the hasLegalHold value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders hasLegalHold(Boolean hasLegalHold) { + this.hasLegalHold = hasLegalHold; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerGetPropertiesHeaders object itself. + */ + public ContainerGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerItem.java new file mode 100644 index 0000000000000..a334568661eb1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerItem.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.Map; + +/** + * An Azure Storage container. + */ +@JacksonXmlRootElement(localName = "Container") +public final class ContainerItem { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The properties property. + */ + @JsonProperty(value = "Properties", required = true) + private ContainerProperties properties; + + /* + * The metadata property. + */ + @JsonProperty(value = "Metadata") + private Map metadata; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the ContainerItem object itself. + */ + public ContainerItem name(String name) { + this.name = name; + return this; + } + + /** + * Get the properties property: The properties property. + * + * @return the properties value. + */ + public ContainerProperties properties() { + return this.properties; + } + + /** + * Set the properties property: The properties property. + * + * @param properties the properties value to set. + * @return the ContainerItem object itself. + */ + public ContainerItem properties(ContainerProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the ContainerItem object itself. + */ + public ContainerItem metadata(Map metadata) { + this.metadata = metadata; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobFlatSegmentHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobFlatSegmentHeaders.java new file mode 100644 index 0000000000000..311c0c6ca66bf --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobFlatSegmentHeaders.java @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListBlobFlatSegment operation. + */ +@JacksonXmlRootElement(localName = "Container-ListBlobFlatSegment-Headers") +public final class ContainerListBlobFlatSegmentHeaders { + /* + * The media type of the body of the response. For List Blobs this is + * 'application/xml' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentType property: The media type of the body of the + * response. For List Blobs this is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The media type of the body of the + * response. For List Blobs this is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the ContainerListBlobFlatSegmentHeaders object itself. + */ + public ContainerListBlobFlatSegmentHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerListBlobFlatSegmentHeaders object itself. + */ + public ContainerListBlobFlatSegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerListBlobFlatSegmentHeaders object itself. + */ + public ContainerListBlobFlatSegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerListBlobFlatSegmentHeaders object itself. + */ + public ContainerListBlobFlatSegmentHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerListBlobFlatSegmentHeaders object itself. + */ + public ContainerListBlobFlatSegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobHierarchySegmentHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobHierarchySegmentHeaders.java new file mode 100644 index 0000000000000..7456e14d89809 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListBlobHierarchySegmentHeaders.java @@ -0,0 +1,168 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListBlobHierarchySegment operation. + */ +@JacksonXmlRootElement(localName = "Container-ListBlobHierarchySegment-Headers") +public final class ContainerListBlobHierarchySegmentHeaders { + /* + * The media type of the body of the response. For List Blobs this is + * 'application/xml' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentType property: The media type of the body of the + * response. For List Blobs this is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The media type of the body of the + * response. For List Blobs this is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the ContainerListBlobHierarchySegmentHeaders object itself. + */ + public ContainerListBlobHierarchySegmentHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerListBlobHierarchySegmentHeaders object itself. + */ + public ContainerListBlobHierarchySegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerListBlobHierarchySegmentHeaders object itself. + */ + public ContainerListBlobHierarchySegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerListBlobHierarchySegmentHeaders object itself. + */ + public ContainerListBlobHierarchySegmentHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerListBlobHierarchySegmentHeaders object itself. + */ + public ContainerListBlobHierarchySegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListDetails.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListDetails.java new file mode 100644 index 0000000000000..f51d897112d5d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerListDetails.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.azure.storage.blob.StorageClient; + +/** + * This type allows users to specify additional information the service should return with each container when listing + * containers in an account (via a {@link StorageClient} object). This type is immutable to ensure thread-safety of + * requests, so changing the details for a different listing operation requires construction of a new object. Null may + * be passed if none of the options are desirable. + */ +public final class ContainerListDetails { + + private boolean metadata; + + public ContainerListDetails() { + + } + + /** + * Whether metadata should be returned. + * + * @return a flag indicating whether metadata should be returned in the listing + */ + public boolean metadata() { + return this.metadata; + } + + /** + * Whether metadata should be returned. + * + * @param metadata Flag indicating whether metadata should be returned + * @return the updated ContainerListDetails object + */ + public ContainerListDetails metadata(boolean metadata) { + this.metadata = metadata; + return this; + } + + /** + * @return the listing flags + */ + public ListContainersIncludeType toIncludeType() { + if (this.metadata) { + return ListContainersIncludeType.METADATA; + } + return null; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerProperties.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerProperties.java new file mode 100644 index 0000000000000..b4844ac52dcfb --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerProperties.java @@ -0,0 +1,242 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Properties of a container. + */ +@JacksonXmlRootElement(localName = "ContainerProperties") +public final class ContainerProperties { + /* + * The lastModified property. + */ + @JsonProperty(value = "Last-Modified", required = true) + private DateTimeRfc1123 lastModified; + + /* + * The etag property. + */ + @JsonProperty(value = "Etag", required = true) + private String etag; + + /* + * Possible values include: 'locked', 'unlocked' + */ + @JsonProperty(value = "LeaseStatus") + private LeaseStatusType leaseStatus; + + /* + * Possible values include: 'available', 'leased', 'expired', 'breaking', + * 'broken' + */ + @JsonProperty(value = "LeaseState") + private LeaseStateType leaseState; + + /* + * Possible values include: 'infinite', 'fixed' + */ + @JsonProperty(value = "LeaseDuration") + private LeaseDurationType leaseDuration; + + /* + * Possible values include: 'container', 'blob' + */ + @JsonProperty(value = "PublicAccess") + private PublicAccessType publicAccess; + + /* + * The hasImmutabilityPolicy property. + */ + @JsonProperty(value = "HasImmutabilityPolicy") + private Boolean hasImmutabilityPolicy; + + /* + * The hasLegalHold property. + */ + @JsonProperty(value = "HasLegalHold") + private Boolean hasLegalHold; + + /** + * Get the lastModified property: The lastModified property. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: The lastModified property. + * + * @param lastModified the lastModified value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the etag property: The etag property. + * + * @return the etag value. + */ + public String etag() { + return this.etag; + } + + /** + * Set the etag property: The etag property. + * + * @param etag the etag value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties etag(String etag) { + this.etag = etag; + return this; + } + + /** + * Get the leaseStatus property: Possible values include: 'locked', + * 'unlocked'. + * + * @return the leaseStatus value. + */ + public LeaseStatusType leaseStatus() { + return this.leaseStatus; + } + + /** + * Set the leaseStatus property: Possible values include: 'locked', + * 'unlocked'. + * + * @param leaseStatus the leaseStatus value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties leaseStatus(LeaseStatusType leaseStatus) { + this.leaseStatus = leaseStatus; + return this; + } + + /** + * Get the leaseState property: Possible values include: 'available', + * 'leased', 'expired', 'breaking', 'broken'. + * + * @return the leaseState value. + */ + public LeaseStateType leaseState() { + return this.leaseState; + } + + /** + * Set the leaseState property: Possible values include: 'available', + * 'leased', 'expired', 'breaking', 'broken'. + * + * @param leaseState the leaseState value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties leaseState(LeaseStateType leaseState) { + this.leaseState = leaseState; + return this; + } + + /** + * Get the leaseDuration property: Possible values include: 'infinite', + * 'fixed'. + * + * @return the leaseDuration value. + */ + public LeaseDurationType leaseDuration() { + return this.leaseDuration; + } + + /** + * Set the leaseDuration property: Possible values include: 'infinite', + * 'fixed'. + * + * @param leaseDuration the leaseDuration value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties leaseDuration(LeaseDurationType leaseDuration) { + this.leaseDuration = leaseDuration; + return this; + } + + /** + * Get the publicAccess property: Possible values include: 'container', + * 'blob'. + * + * @return the publicAccess value. + */ + public PublicAccessType publicAccess() { + return this.publicAccess; + } + + /** + * Set the publicAccess property: Possible values include: 'container', + * 'blob'. + * + * @param publicAccess the publicAccess value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties publicAccess(PublicAccessType publicAccess) { + this.publicAccess = publicAccess; + return this; + } + + /** + * Get the hasImmutabilityPolicy property: The hasImmutabilityPolicy + * property. + * + * @return the hasImmutabilityPolicy value. + */ + public Boolean hasImmutabilityPolicy() { + return this.hasImmutabilityPolicy; + } + + /** + * Set the hasImmutabilityPolicy property: The hasImmutabilityPolicy + * property. + * + * @param hasImmutabilityPolicy the hasImmutabilityPolicy value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties hasImmutabilityPolicy(Boolean hasImmutabilityPolicy) { + this.hasImmutabilityPolicy = hasImmutabilityPolicy; + return this; + } + + /** + * Get the hasLegalHold property: The hasLegalHold property. + * + * @return the hasLegalHold value. + */ + public Boolean hasLegalHold() { + return this.hasLegalHold; + } + + /** + * Set the hasLegalHold property: The hasLegalHold property. + * + * @param hasLegalHold the hasLegalHold value to set. + * @return the ContainerProperties object itself. + */ + public ContainerProperties hasLegalHold(Boolean hasLegalHold) { + this.hasLegalHold = hasLegalHold; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerReleaseLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerReleaseLeaseHeaders.java new file mode 100644 index 0000000000000..b437d814e16ca --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerReleaseLeaseHeaders.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ReleaseLease operation. + */ +@JacksonXmlRootElement(localName = "Container-ReleaseLease-Headers") +public final class ContainerReleaseLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerReleaseLeaseHeaders object itself. + */ + public ContainerReleaseLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerRenewLeaseHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerRenewLeaseHeaders.java new file mode 100644 index 0000000000000..e9a03210ae1a3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerRenewLeaseHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for RenewLease operation. + */ +@JacksonXmlRootElement(localName = "Container-RenewLease-Headers") +public final class ContainerRenewLeaseHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * Uniquely identifies a container's lease + */ + @JsonProperty(value = "x-ms-lease-id") + private String leaseId; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the leaseId property: Uniquely identifies a container's lease. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: Uniquely identifies a container's lease. + * + * @param leaseId the leaseId value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerRenewLeaseHeaders object itself. + */ + public ContainerRenewLeaseHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetAccessPolicyHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..a91ceed6d34d1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetAccessPolicyHeaders.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Container-SetAccessPolicy-Headers") +public final class ContainerSetAccessPolicyHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerSetAccessPolicyHeaders object itself. + */ + public ContainerSetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetMetadataHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetMetadataHeaders.java new file mode 100644 index 0000000000000..082886b7c0b54 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainerSetMetadataHeaders.java @@ -0,0 +1,212 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "Container-SetMetadata-Headers") +public final class ContainerSetMetadataHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ContainerSetMetadataHeaders object itself. + */ + public ContainerSetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersAcquireLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersAcquireLeaseResponse.java new file mode 100644 index 0000000000000..121be655fcb41 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersAcquireLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the acquireLease operation. + */ +public final class ContainersAcquireLeaseResponse extends ResponseBase { + /** + * Creates an instance of ContainersAcquireLeaseResponse. + * + * @param request the request which resulted in this ContainersAcquireLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersAcquireLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerAcquireLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersBreakLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersBreakLeaseResponse.java new file mode 100644 index 0000000000000..c1fd19e3b28f3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersBreakLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the breakLease operation. + */ +public final class ContainersBreakLeaseResponse extends ResponseBase { + /** + * Creates an instance of ContainersBreakLeaseResponse. + * + * @param request the request which resulted in this ContainersBreakLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersBreakLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerBreakLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersChangeLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersChangeLeaseResponse.java new file mode 100644 index 0000000000000..c89bb3bc9d032 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersChangeLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the changeLease operation. + */ +public final class ContainersChangeLeaseResponse extends ResponseBase { + /** + * Creates an instance of ContainersChangeLeaseResponse. + * + * @param request the request which resulted in this ContainersChangeLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersChangeLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerChangeLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersCreateResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersCreateResponse.java new file mode 100644 index 0000000000000..b08eb783c5533 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class ContainersCreateResponse extends ResponseBase { + /** + * Creates an instance of ContainersCreateResponse. + * + * @param request the request which resulted in this ContainersCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersDeleteResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersDeleteResponse.java new file mode 100644 index 0000000000000..62d4bcf04738d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class ContainersDeleteResponse extends ResponseBase { + /** + * Creates an instance of ContainersDeleteResponse. + * + * @param request the request which resulted in this ContainersDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccessPolicyResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccessPolicyResponse.java new file mode 100644 index 0000000000000..8003bad140ac0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccessPolicyResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the getAccessPolicy operation. + */ +public final class ContainersGetAccessPolicyResponse extends ResponseBase> { + /** + * Creates an instance of ContainersGetAccessPolicyResponse. + * + * @param request the request which resulted in this ContainersGetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersGetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, ContainerGetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccountInfoResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccountInfoResponse.java new file mode 100644 index 0000000000000..a4d2a3ab5cc9b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetAccountInfoResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getAccountInfo operation. + */ +public final class ContainersGetAccountInfoResponse extends ResponseBase { + /** + * Creates an instance of ContainersGetAccountInfoResponse. + * + * @param request the request which resulted in this ContainersGetAccountInfoResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersGetAccountInfoResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerGetAccountInfoHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetPropertiesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetPropertiesResponse.java new file mode 100644 index 0000000000000..fecff3635a11c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class ContainersGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ContainersGetPropertiesResponse. + * + * @param request the request which resulted in this ContainersGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobFlatSegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobFlatSegmentResponse.java new file mode 100644 index 0000000000000..30a585890905a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobFlatSegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listBlobFlatSegment operation. + */ +public final class ContainersListBlobFlatSegmentResponse extends ResponseBase { + /** + * Creates an instance of ContainersListBlobFlatSegmentResponse. + * + * @param request the request which resulted in this ContainersListBlobFlatSegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersListBlobFlatSegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListBlobsFlatSegmentResponse value, ContainerListBlobFlatSegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListBlobsFlatSegmentResponse value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobHierarchySegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobHierarchySegmentResponse.java new file mode 100644 index 0000000000000..2077bc46574e8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersListBlobHierarchySegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listBlobHierarchySegment operation. + */ +public final class ContainersListBlobHierarchySegmentResponse extends ResponseBase { + /** + * Creates an instance of ContainersListBlobHierarchySegmentResponse. + * + * @param request the request which resulted in this ContainersListBlobHierarchySegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersListBlobHierarchySegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListBlobsHierarchySegmentResponse value, ContainerListBlobHierarchySegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListBlobsHierarchySegmentResponse value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersReleaseLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersReleaseLeaseResponse.java new file mode 100644 index 0000000000000..d719090a85c84 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersReleaseLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the releaseLease operation. + */ +public final class ContainersReleaseLeaseResponse extends ResponseBase { + /** + * Creates an instance of ContainersReleaseLeaseResponse. + * + * @param request the request which resulted in this ContainersReleaseLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersReleaseLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerReleaseLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersRenewLeaseResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersRenewLeaseResponse.java new file mode 100644 index 0000000000000..64ddebe26aa70 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersRenewLeaseResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the renewLease operation. + */ +public final class ContainersRenewLeaseResponse extends ResponseBase { + /** + * Creates an instance of ContainersRenewLeaseResponse. + * + * @param request the request which resulted in this ContainersRenewLeaseResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersRenewLeaseResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerRenewLeaseHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetAccessPolicyResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetAccessPolicyResponse.java new file mode 100644 index 0000000000000..982160576ba59 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetAccessPolicyResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setAccessPolicy operation. + */ +public final class ContainersSetAccessPolicyResponse extends ResponseBase { + /** + * Creates an instance of ContainersSetAccessPolicyResponse. + * + * @param request the request which resulted in this ContainersSetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersSetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerSetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetMetadataResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetMetadataResponse.java new file mode 100644 index 0000000000000..0fc54a5d1f2c7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ContainersSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class ContainersSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of ContainersSetMetadataResponse. + * + * @param request the request which resulted in this ContainersSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ContainersSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ContainerSetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/CopyStatusType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CopyStatusType.java new file mode 100644 index 0000000000000..2400d668cb58d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CopyStatusType.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for CopyStatusType. + */ +public enum CopyStatusType { + /** + * Enum value pending. + */ + PENDING("pending"), + + /** + * Enum value success. + */ + SUCCESS("success"), + + /** + * Enum value aborted. + */ + ABORTED("aborted"), + + /** + * Enum value failed. + */ + FAILED("failed"); + + /** + * The actual serialized value for a CopyStatusType instance. + */ + private final String value; + + CopyStatusType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a CopyStatusType instance. + * + * @param value the serialized value to parse. + * @return the parsed CopyStatusType object, or null if unable to parse. + */ + @JsonCreator + public static CopyStatusType fromString(String value) { + CopyStatusType[] items = CopyStatusType.values(); + for (CopyStatusType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/CorsRule.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CorsRule.java new file mode 100644 index 0000000000000..fa9035b072c6c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CorsRule.java @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * CORS is an HTTP feature that enables a web application running under one + * domain to access resources in another domain. Web browsers implement a + * security restriction known as same-origin policy that prevents a web page + * from calling APIs in a different domain; CORS provides a secure way to allow + * one domain (the origin domain) to call APIs in another domain. + */ +@JacksonXmlRootElement(localName = "CorsRule") +public final class CorsRule { + /* + * The origin domains that are permitted to make a request against the + * storage service via CORS. The origin domain is the domain from which the + * request originates. Note that the origin must be an exact case-sensitive + * match with the origin that the user age sends to the service. You can + * also use the wildcard character '*' to allow all origin domains to make + * requests via CORS. + */ + @JsonProperty(value = "AllowedOrigins", required = true) + private String allowedOrigins; + + /* + * The methods (HTTP request verbs) that the origin domain may use for a + * CORS request. (comma separated) + */ + @JsonProperty(value = "AllowedMethods", required = true) + private String allowedMethods; + + /* + * the request headers that the origin domain may specify on the CORS + * request. + */ + @JsonProperty(value = "AllowedHeaders", required = true) + private String allowedHeaders; + + /* + * The response headers that may be sent in the response to the CORS + * request and exposed by the browser to the request issuer + */ + @JsonProperty(value = "ExposedHeaders", required = true) + private String exposedHeaders; + + /* + * The maximum amount time that a browser should cache the preflight + * OPTIONS request. + */ + @JsonProperty(value = "MaxAgeInSeconds", required = true) + private int maxAgeInSeconds; + + /** + * Get the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @return the allowedOrigins value. + */ + public String allowedOrigins() { + return this.allowedOrigins; + } + + /** + * Set the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @param allowedOrigins the allowedOrigins value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedOrigins(String allowedOrigins) { + this.allowedOrigins = allowedOrigins; + return this; + } + + /** + * Get the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @return the allowedMethods value. + */ + public String allowedMethods() { + return this.allowedMethods; + } + + /** + * Set the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @param allowedMethods the allowedMethods value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedMethods(String allowedMethods) { + this.allowedMethods = allowedMethods; + return this; + } + + /** + * Get the allowedHeaders property: the request headers that the origin + * domain may specify on the CORS request. + * + * @return the allowedHeaders value. + */ + public String allowedHeaders() { + return this.allowedHeaders; + } + + /** + * Set the allowedHeaders property: the request headers that the origin + * domain may specify on the CORS request. + * + * @param allowedHeaders the allowedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedHeaders(String allowedHeaders) { + this.allowedHeaders = allowedHeaders; + return this; + } + + /** + * Get the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @return the exposedHeaders value. + */ + public String exposedHeaders() { + return this.exposedHeaders; + } + + /** + * Set the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @param exposedHeaders the exposedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule exposedHeaders(String exposedHeaders) { + this.exposedHeaders = exposedHeaders; + return this; + } + + /** + * Get the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @return the maxAgeInSeconds value. + */ + public int maxAgeInSeconds() { + return this.maxAgeInSeconds; + } + + /** + * Set the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @param maxAgeInSeconds the maxAgeInSeconds value to set. + * @return the CorsRule object itself. + */ + public CorsRule maxAgeInSeconds(int maxAgeInSeconds) { + this.maxAgeInSeconds = maxAgeInSeconds; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/CustomHierarchicalListingDeserializer.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CustomHierarchicalListingDeserializer.java new file mode 100644 index 0000000000000..1a6a0652c406f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/CustomHierarchicalListingDeserializer.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.util.ArrayList; + +final class CustomHierarchicalListingDeserializer extends JsonDeserializer { + + @Override + public BlobHierarchyListSegment deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + ArrayList blobItems = new ArrayList<>(); + ArrayList blobPrefixes = new ArrayList<>(); + + JsonDeserializer blobItemDeserializer = + ctxt.findRootValueDeserializer(ctxt.constructType(BlobItem.class)); + JsonDeserializer blobPrefixDeserializer = + ctxt.findRootValueDeserializer(ctxt.constructType(BlobPrefix.class)); + + for (JsonToken currentToken = p.nextToken(); !currentToken.name().equals("END_OBJECT"); + currentToken = p.nextToken()) { + // Get to the root element of the next item. + p.nextToken(); + + if (p.getCurrentName().equals("Blob")) { + blobItems.add((BlobItem)blobItemDeserializer.deserialize(p, ctxt)); + } + else if (p.getCurrentName().equals("BlobPrefix")) { + blobPrefixes.add((BlobPrefix)blobPrefixDeserializer.deserialize(p, ctxt)); + } + } + + return new BlobHierarchyListSegment().blobItems(blobItems).blobPrefixes(blobPrefixes); + } +} + diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/DeleteSnapshotsOptionType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/DeleteSnapshotsOptionType.java new file mode 100644 index 0000000000000..8cfbfd27a66d1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/DeleteSnapshotsOptionType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for DeleteSnapshotsOptionType. + */ +public enum DeleteSnapshotsOptionType { + /** + * Enum value include. + */ + INCLUDE("include"), + + /** + * Enum value only. + */ + ONLY("only"); + + /** + * The actual serialized value for a DeleteSnapshotsOptionType instance. + */ + private final String value; + + DeleteSnapshotsOptionType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a DeleteSnapshotsOptionType instance. + * + * @param value the serialized value to parse. + * @return the parsed DeleteSnapshotsOptionType object, or null if unable to parse. + */ + @JsonCreator + public static DeleteSnapshotsOptionType fromString(String value) { + DeleteSnapshotsOptionType[] items = DeleteSnapshotsOptionType.values(); + for (DeleteSnapshotsOptionType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/EncryptionAlgorithmType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/EncryptionAlgorithmType.java new file mode 100644 index 0000000000000..081f319a2ea47 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/EncryptionAlgorithmType.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for EncryptionAlgorithmType. + */ +public enum EncryptionAlgorithmType { + /** + * Enum value AES256. + */ + AES256("AES256"); + + /** + * The actual serialized value for a EncryptionAlgorithmType instance. + */ + private final String value; + + EncryptionAlgorithmType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a EncryptionAlgorithmType instance. + * + * @param value the serialized value to parse. + * @return the parsed EncryptionAlgorithmType object, or null if unable to parse. + */ + @JsonCreator + public static EncryptionAlgorithmType fromString(String value) { + EncryptionAlgorithmType[] items = EncryptionAlgorithmType.values(); + for (EncryptionAlgorithmType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplication.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplication.java new file mode 100644 index 0000000000000..90cf41b12f07f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplication.java @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Geo-Replication information for the Secondary Storage Service. + */ +@JacksonXmlRootElement(localName = "GeoReplication") +public final class GeoReplication { + /* + * The status of the secondary location. Possible values include: 'live', + * 'bootstrap', 'unavailable' + */ + @JsonProperty(value = "Status", required = true) + private GeoReplicationStatusType status; + + /* + * A GMT date/time value, to the second. All primary writes preceding this + * value are guaranteed to be available for read operations at the + * secondary. Primary writes after this point in time may or may not be + * available for reads. + */ + @JsonProperty(value = "LastSyncTime", required = true) + private DateTimeRfc1123 lastSyncTime; + + /** + * Get the status property: The status of the secondary location. Possible + * values include: 'live', 'bootstrap', 'unavailable'. + * + * @return the status value. + */ + public GeoReplicationStatusType status() { + return this.status; + } + + /** + * Set the status property: The status of the secondary location. Possible + * values include: 'live', 'bootstrap', 'unavailable'. + * + * @param status the status value to set. + * @return the GeoReplication object itself. + */ + public GeoReplication status(GeoReplicationStatusType status) { + this.status = status; + return this; + } + + /** + * Get the lastSyncTime property: A GMT date/time value, to the second. All + * primary writes preceding this value are guaranteed to be available for + * read operations at the secondary. Primary writes after this point in + * time may or may not be available for reads. + * + * @return the lastSyncTime value. + */ + public OffsetDateTime lastSyncTime() { + if (this.lastSyncTime == null) { + return null; + } + return this.lastSyncTime.dateTime(); + } + + /** + * Set the lastSyncTime property: A GMT date/time value, to the second. All + * primary writes preceding this value are guaranteed to be available for + * read operations at the secondary. Primary writes after this point in + * time may or may not be available for reads. + * + * @param lastSyncTime the lastSyncTime value to set. + * @return the GeoReplication object itself. + */ + public GeoReplication lastSyncTime(OffsetDateTime lastSyncTime) { + if (lastSyncTime == null) { + this.lastSyncTime = null; + } else { + this.lastSyncTime = new DateTimeRfc1123(lastSyncTime); + } + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplicationStatusType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplicationStatusType.java new file mode 100644 index 0000000000000..e459bc355f7b4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/GeoReplicationStatusType.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for GeoReplicationStatusType. + */ +public final class GeoReplicationStatusType extends ExpandableStringEnum { + /** + * Static value live for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType LIVE = fromString("live"); + + /** + * Static value bootstrap for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType BOOTSTRAP = fromString("bootstrap"); + + /** + * Static value unavailable for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType UNAVAILABLE = fromString("unavailable"); + + /** + * Creates or finds a GeoReplicationStatusType from its string representation. + * + * @param name a name to look for. + * @return the corresponding GeoReplicationStatusType. + */ + @JsonCreator + public static GeoReplicationStatusType fromString(String name) { + return fromString(name, GeoReplicationStatusType.class); + } + + /** + * @return known GeoReplicationStatusType values. + */ + public static Collection values() { + return values(GeoReplicationStatusType.class); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/KeyInfo.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/KeyInfo.java new file mode 100644 index 0000000000000..d1aa23bbcef7c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/KeyInfo.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Key information. + */ +@JacksonXmlRootElement(localName = "KeyInfo") +public final class KeyInfo { + /* + * The date-time the key is active in ISO 8601 UTC time + */ + @JsonProperty(value = "Start", required = true) + private String start; + + /* + * The date-time the key expires in ISO 8601 UTC time + */ + @JsonProperty(value = "Expiry", required = true) + private String expiry; + + /** + * Get the start property: The date-time the key is active in ISO 8601 UTC + * time. + * + * @return the start value. + */ + public String start() { + return this.start; + } + + /** + * Set the start property: The date-time the key is active in ISO 8601 UTC + * time. + * + * @param start the start value to set. + * @return the KeyInfo object itself. + */ + public KeyInfo start(String start) { + this.start = start; + return this; + } + + /** + * Get the expiry property: The date-time the key expires in ISO 8601 UTC + * time. + * + * @return the expiry value. + */ + public String expiry() { + return this.expiry; + } + + /** + * Set the expiry property: The date-time the key expires in ISO 8601 UTC + * time. + * + * @param expiry the expiry value to set. + * @return the KeyInfo object itself. + */ + public KeyInfo expiry(String expiry) { + this.expiry = expiry; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseAccessConditions.java new file mode 100644 index 0000000000000..eae367a636e25 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseAccessConditions.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Additional parameters for a set of operations. + */ +@JacksonXmlRootElement(localName = "lease-access-conditions") +public final class LeaseAccessConditions { + /* + * If specified, the operation only succeeds if the resource's lease is + * active and matches this ID. + */ + @JsonProperty(value = "leaseId") + private String leaseId; + + /** + * Get the leaseId property: If specified, the operation only succeeds if + * the resource's lease is active and matches this ID. + * + * @return the leaseId value. + */ + public String leaseId() { + return this.leaseId; + } + + /** + * Set the leaseId property: If specified, the operation only succeeds if + * the resource's lease is active and matches this ID. + * + * @param leaseId the leaseId value to set. + * @return the LeaseAccessConditions object itself. + */ + public LeaseAccessConditions leaseId(String leaseId) { + this.leaseId = leaseId; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseDurationType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseDurationType.java new file mode 100644 index 0000000000000..e7b29e0b31e7a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseDurationType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for LeaseDurationType. + */ +public enum LeaseDurationType { + /** + * Enum value infinite. + */ + INFINITE("infinite"), + + /** + * Enum value fixed. + */ + FIXED("fixed"); + + /** + * The actual serialized value for a LeaseDurationType instance. + */ + private final String value; + + LeaseDurationType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a LeaseDurationType instance. + * + * @param value the serialized value to parse. + * @return the parsed LeaseDurationType object, or null if unable to parse. + */ + @JsonCreator + public static LeaseDurationType fromString(String value) { + LeaseDurationType[] items = LeaseDurationType.values(); + for (LeaseDurationType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStateType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStateType.java new file mode 100644 index 0000000000000..816b541907da6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStateType.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for LeaseStateType. + */ +public enum LeaseStateType { + /** + * Enum value available. + */ + AVAILABLE("available"), + + /** + * Enum value leased. + */ + LEASED("leased"), + + /** + * Enum value expired. + */ + EXPIRED("expired"), + + /** + * Enum value breaking. + */ + BREAKING("breaking"), + + /** + * Enum value broken. + */ + BROKEN("broken"); + + /** + * The actual serialized value for a LeaseStateType instance. + */ + private final String value; + + LeaseStateType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a LeaseStateType instance. + * + * @param value the serialized value to parse. + * @return the parsed LeaseStateType object, or null if unable to parse. + */ + @JsonCreator + public static LeaseStateType fromString(String value) { + LeaseStateType[] items = LeaseStateType.values(); + for (LeaseStateType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStatusType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStatusType.java new file mode 100644 index 0000000000000..878b16368817b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/LeaseStatusType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for LeaseStatusType. + */ +public enum LeaseStatusType { + /** + * Enum value locked. + */ + LOCKED("locked"), + + /** + * Enum value unlocked. + */ + UNLOCKED("unlocked"); + + /** + * The actual serialized value for a LeaseStatusType instance. + */ + private final String value; + + LeaseStatusType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a LeaseStatusType instance. + * + * @param value the serialized value to parse. + * @return the parsed LeaseStatusType object, or null if unable to parse. + */ + @JsonCreator + public static LeaseStatusType fromString(String value) { + LeaseStatusType[] items = LeaseStatusType.values(); + for (LeaseStatusType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsFlatSegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsFlatSegmentResponse.java new file mode 100644 index 0000000000000..1807bc8efe364 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsFlatSegmentResponse.java @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * An enumeration of blobs. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListBlobsFlatSegmentResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The containerName property. + */ + @JacksonXmlProperty(localName = "ContainerName", isAttribute = true) + private String containerName; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix", required = true) + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker", required = true) + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults", required = true) + private int maxResults; + + /* + * The delimiter property. + */ + @JsonProperty(value = "Delimiter", required = true) + private String delimiter; + + /* + * The segment property. + */ + @JsonProperty(value = "Blobs", required = true) + private BlobFlatListSegment segment; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the containerName property: The containerName property. + * + * @return the containerName value. + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the containerName property: The containerName property. + * + * @param containerName the containerName value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public int maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse maxResults(int maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the delimiter property: The delimiter property. + * + * @return the delimiter value. + */ + public String delimiter() { + return this.delimiter; + } + + /** + * Set the delimiter property: The delimiter property. + * + * @param delimiter the delimiter value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse delimiter(String delimiter) { + this.delimiter = delimiter; + return this; + } + + /** + * Get the segment property: The segment property. + * + * @return the segment value. + */ + public BlobFlatListSegment segment() { + return this.segment; + } + + /** + * Set the segment property: The segment property. + * + * @param segment the segment value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse segment(BlobFlatListSegment segment) { + this.segment = segment; + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListBlobsFlatSegmentResponse object itself. + */ + public ListBlobsFlatSegmentResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsHierarchySegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsHierarchySegmentResponse.java new file mode 100644 index 0000000000000..f79c285a10796 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsHierarchySegmentResponse.java @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * An enumeration of blobs. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListBlobsHierarchySegmentResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The containerName property. + */ + @JacksonXmlProperty(localName = "ContainerName", isAttribute = true) + private String containerName; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix", required = true) + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker", required = true) + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults", required = true) + private int maxResults; + + /* + * The delimiter property. + */ + @JsonProperty(value = "Delimiter", required = true) + private String delimiter; + + /* + * The segment property. + */ + @JsonProperty(value = "Blobs", required = true) + private BlobHierarchyListSegment segment; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the containerName property: The containerName property. + * + * @return the containerName value. + */ + public String containerName() { + return this.containerName; + } + + /** + * Set the containerName property: The containerName property. + * + * @param containerName the containerName value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse containerName(String containerName) { + this.containerName = containerName; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public int maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse maxResults(int maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the delimiter property: The delimiter property. + * + * @return the delimiter value. + */ + public String delimiter() { + return this.delimiter; + } + + /** + * Set the delimiter property: The delimiter property. + * + * @param delimiter the delimiter value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse delimiter(String delimiter) { + this.delimiter = delimiter; + return this; + } + + /** + * Get the segment property: The segment property. + * + * @return the segment value. + */ + public BlobHierarchyListSegment segment() { + return this.segment; + } + + /** + * Set the segment property: The segment property. + * + * @param segment the segment value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse segment(BlobHierarchyListSegment segment) { + this.segment = segment; + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListBlobsHierarchySegmentResponse object itself. + */ + public ListBlobsHierarchySegmentResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsIncludeItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsIncludeItem.java new file mode 100644 index 0000000000000..47ed4cbfd72f4 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsIncludeItem.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for ListBlobsIncludeItem. + */ +public enum ListBlobsIncludeItem { + /** + * Enum value copy. + */ + COPY("copy"), + + /** + * Enum value deleted. + */ + DELETED("deleted"), + + /** + * Enum value metadata. + */ + METADATA("metadata"), + + /** + * Enum value snapshots. + */ + SNAPSHOTS("snapshots"), + + /** + * Enum value uncommittedblobs. + */ + UNCOMMITTEDBLOBS("uncommittedblobs"); + + /** + * The actual serialized value for a ListBlobsIncludeItem instance. + */ + private final String value; + + ListBlobsIncludeItem(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a ListBlobsIncludeItem instance. + * + * @param value the serialized value to parse. + * @return the parsed ListBlobsIncludeItem object, or null if unable to parse. + */ + @JsonCreator + public static ListBlobsIncludeItem fromString(String value) { + ListBlobsIncludeItem[] items = ListBlobsIncludeItem.values(); + for (ListBlobsIncludeItem item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsOptions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsOptions.java new file mode 100644 index 0000000000000..eb44c946bc013 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListBlobsOptions.java @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.azure.storage.blob.ContainerClient; + +/** + * Defines options available to configure the behavior of a call to listBlobsFlatSegment on a {@link ContainerClient} + * object. See the constructor for details on each of the options. + */ +public final class ListBlobsOptions { + + private BlobListDetails details; + + private String prefix; + + private Integer maxResults; + + public ListBlobsOptions() { + this.details = new BlobListDetails(); + } + + /** + * @return the details for listing specific blobs + */ + public BlobListDetails details() { + return details; + } + + /** + * @param details The details for listing specific blobs + * @return the updated ListBlobsOptions object + */ + public ListBlobsOptions details(BlobListDetails details) { + this.details = details; + return this; + } + + /** + * Filters the results to return only blobs whose names begin with the specified prefix. May be null to return + * all blobs. + * + * @return the prefix that a blob must match to be returned in the listing + */ + public String prefix() { + return prefix; + } + + /** + * Filters the results to return only blobs whose names begin with the specified prefix. May be null to return + * all blobs. + * + * @param prefix A prefix that a blob must match to be returned + * @return the updated ListBlobsOptions object + */ + public ListBlobsOptions prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not + * specify maxResults or specifies a value greater than 5,000, the server will return up to 5,000 items. + * + * @return the number of blobs that will be returned in a single response + */ + public Integer maxResults() { + return maxResults; + } + + /** + * Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not + * specify maxResults or specifies a value greater than 5,000, the server will return up to 5,000 items. + * + * @param maxResults The number of blobs to returned in a single response + * @return the updated ListBlobsOptions object + */ + public ListBlobsOptions maxResults(Integer maxResults) { + if (maxResults != null && maxResults <= 0) { + throw new IllegalArgumentException("MaxResults must be greater than 0."); + } + this.maxResults = maxResults; + return this; + } + + +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersIncludeType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersIncludeType.java new file mode 100644 index 0000000000000..692bdc63286bd --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersIncludeType.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for ListContainersIncludeType. + */ +public enum ListContainersIncludeType { + /** + * Enum value metadata. + */ + METADATA("metadata"); + + /** + * The actual serialized value for a ListContainersIncludeType instance. + */ + private final String value; + + ListContainersIncludeType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a ListContainersIncludeType instance. + * + * @param value the serialized value to parse. + * @return the parsed ListContainersIncludeType object, or null if unable to parse. + */ + @JsonCreator + public static ListContainersIncludeType fromString(String value) { + ListContainersIncludeType[] items = ListContainersIncludeType.values(); + for (ListContainersIncludeType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersOptions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersOptions.java new file mode 100644 index 0000000000000..19d3e61a2c75d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersOptions.java @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.azure.storage.blob.StorageClient; + +/** + * Defines options available to configure the behavior of a call to listContainersSegment on a {@link StorageClient} + * object. See the constructor for details on each of the options. Null may be passed in place of an object of this + * type if no options are desirable. + */ +public final class ListContainersOptions { + + private ContainerListDetails details; + + private String prefix; + + private Integer maxResults; + + public ListContainersOptions() { + this.details = new ContainerListDetails(); + } + + /** + * @return the details for listing specific containers + */ + public ContainerListDetails details() { + return details; + } + + /** + * @param details The details for listing specific containers + * @return the updated ListContainersOptions object + */ + public ListContainersOptions details(ContainerListDetails details) { + this.details = details; + return this; + } + + /** + * Filters the results to return only blobs whose names begin with the specified prefix. + * + * @return the prefix a container must start with to be returned + */ + public String prefix() { + return prefix; + } + + /** + * Filters the results to return only blobs whose names begin with the specified prefix. + * + * @param prefix The prefix that a container must match to be returned + * @return the updated ListContainersOptions object + */ + public ListContainersOptions prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not + * specify maxResults or specifies a value greater than 5,000, the server will return up to 5,000 items. + * + * @return the number of containers to be returned in a single response + */ + public Integer maxResults() { + return maxResults; + } + + /** + * Specifies the maximum number of blobs to return, including all BlobPrefix elements. If the request does not + * specify maxResults or specifies a value greater than 5,000, the server will return up to 5,000 items. + * + * @param maxResults The number of containers to return in a single response + * @return the updated ListContainersOptions object + */ + public ListContainersOptions maxResults(Integer maxResults) { + if (maxResults != null && maxResults <= 0) { + throw new IllegalArgumentException("MaxResults must be greater than 0."); + } + this.maxResults = maxResults; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersSegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersSegmentResponse.java new file mode 100644 index 0000000000000..deafc07a94435 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ListContainersSegmentResponse.java @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * An enumeration of containers. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListContainersSegmentResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix", required = true) + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker") + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults", required = true) + private int maxResults; + + private static final class ContainersWrapper { + @JacksonXmlProperty(localName = "Container") + private final List items; + + @JsonCreator + private ContainersWrapper(@JacksonXmlProperty(localName = "Container") List items) { + this.items = items; + } + } + + /* + * The containerItems property. + */ + @JsonProperty(value = "Containers", required = true) + private ContainersWrapper containerItems; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public int maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse maxResults(int maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the containerItems property: The containerItems property. + * + * @return the containerItems value. + */ + public List containerItems() { + if (this.containerItems == null) { + this.containerItems = new ContainersWrapper(new ArrayList()); + } + return this.containerItems.items; + } + + /** + * Set the containerItems property: The containerItems property. + * + * @param containerItems the containerItems value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse containerItems(List containerItems) { + this.containerItems = new ContainersWrapper(containerItems); + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListContainersSegmentResponse object itself. + */ + public ListContainersSegmentResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/Logging.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Logging.java new file mode 100644 index 0000000000000..e86ad32a0ae74 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Logging.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Azure Analytics Logging settings. + */ +@JacksonXmlRootElement(localName = "Logging") +public final class Logging { + /* + * The version of Storage Analytics to configure. + */ + @JsonProperty(value = "Version", required = true) + private String version; + + /* + * Indicates whether all delete requests should be logged. + */ + @JsonProperty(value = "Delete", required = true) + private boolean delete; + + /* + * Indicates whether all read requests should be logged. + */ + @JsonProperty(value = "Read", required = true) + private boolean read; + + /* + * Indicates whether all write requests should be logged. + */ + @JsonProperty(value = "Write", required = true) + private boolean write; + + /* + * The retentionPolicy property. + */ + @JsonProperty(value = "RetentionPolicy", required = true) + private RetentionPolicy retentionPolicy; + + /** + * Get the version property: The version of Storage Analytics to configure. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: The version of Storage Analytics to configure. + * + * @param version the version value to set. + * @return the Logging object itself. + */ + public Logging version(String version) { + this.version = version; + return this; + } + + /** + * Get the delete property: Indicates whether all delete requests should be + * logged. + * + * @return the delete value. + */ + public boolean delete() { + return this.delete; + } + + /** + * Set the delete property: Indicates whether all delete requests should be + * logged. + * + * @param delete the delete value to set. + * @return the Logging object itself. + */ + public Logging delete(boolean delete) { + this.delete = delete; + return this; + } + + /** + * Get the read property: Indicates whether all read requests should be + * logged. + * + * @return the read value. + */ + public boolean read() { + return this.read; + } + + /** + * Set the read property: Indicates whether all read requests should be + * logged. + * + * @param read the read value to set. + * @return the Logging object itself. + */ + public Logging read(boolean read) { + this.read = read; + return this; + } + + /** + * Get the write property: Indicates whether all write requests should be + * logged. + * + * @return the write value. + */ + public boolean write() { + return this.write; + } + + /** + * Set the write property: Indicates whether all write requests should be + * logged. + * + * @param write the write value to set. + * @return the Logging object itself. + */ + public Logging write(boolean write) { + this.write = write; + return this; + } + + /** + * Get the retentionPolicy property: The retentionPolicy property. + * + * @return the retentionPolicy value. + */ + public RetentionPolicy retentionPolicy() { + return this.retentionPolicy; + } + + /** + * Set the retentionPolicy property: The retentionPolicy property. + * + * @param retentionPolicy the retentionPolicy value to set. + * @return the Logging object itself. + */ + public Logging retentionPolicy(RetentionPolicy retentionPolicy) { + this.retentionPolicy = retentionPolicy; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metadata.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metadata.java new file mode 100644 index 0000000000000..b93413a579509 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metadata.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import java.util.HashMap; +import java.util.Map; + +/** + * Contains metadata key/value pairs to be associated with a storage resource. The user may store any additional + * information about the resource that they like using this map. It is passed to create and setMetadata methods on any + * URL type. Null may be passed to set no metadata. + */ +public final class Metadata extends HashMap { + + // The Metadata is an offshoot of extending HashMap, which implements Serializable. + private static final long serialVersionUID = -6557244540575247796L; + + public Metadata() { + super(); + } + + public Metadata(Map m) { + super(m); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metrics.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metrics.java new file mode 100644 index 0000000000000..c812d6a86a533 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/Metrics.java @@ -0,0 +1,124 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * a summary of request statistics grouped by API in hour or minute aggregates + * for blobs. + */ +@JacksonXmlRootElement(localName = "Metrics") +public final class Metrics { + /* + * The version of Storage Analytics to configure. + */ + @JsonProperty(value = "Version") + private String version; + + /* + * Indicates whether metrics are enabled for the Blob service. + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates whether metrics should generate summary statistics for called + * API operations. + */ + @JsonProperty(value = "IncludeAPIs") + private Boolean includeAPIs; + + /* + * The retentionPolicy property. + */ + @JsonProperty(value = "RetentionPolicy") + private RetentionPolicy retentionPolicy; + + /** + * Get the version property: The version of Storage Analytics to configure. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: The version of Storage Analytics to configure. + * + * @param version the version value to set. + * @return the Metrics object itself. + */ + public Metrics version(String version) { + this.version = version; + return this; + } + + /** + * Get the enabled property: Indicates whether metrics are enabled for the + * Blob service. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether metrics are enabled for the + * Blob service. + * + * @param enabled the enabled value to set. + * @return the Metrics object itself. + */ + public Metrics enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @return the includeAPIs value. + */ + public Boolean includeAPIs() { + return this.includeAPIs; + } + + /** + * Set the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @param includeAPIs the includeAPIs value to set. + * @return the Metrics object itself. + */ + public Metrics includeAPIs(Boolean includeAPIs) { + this.includeAPIs = includeAPIs; + return this; + } + + /** + * Get the retentionPolicy property: The retentionPolicy property. + * + * @return the retentionPolicy value. + */ + public RetentionPolicy retentionPolicy() { + return this.retentionPolicy; + } + + /** + * Set the retentionPolicy property: The retentionPolicy property. + * + * @param retentionPolicy the retentionPolicy value to set. + * @return the Metrics object itself. + */ + public Metrics retentionPolicy(RetentionPolicy retentionPolicy) { + this.retentionPolicy = retentionPolicy; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ModifiedAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ModifiedAccessConditions.java new file mode 100644 index 0000000000000..3636dfd4c290c --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ModifiedAccessConditions.java @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Additional parameters for a set of operations. + */ +@JacksonXmlRootElement(localName = "modified-access-conditions") +public final class ModifiedAccessConditions { + /* + * Specify this header value to operate only on a blob if it has been + * modified since the specified date/time. + */ + @JsonProperty(value = "ifModifiedSince") + private DateTimeRfc1123 ifModifiedSince; + + /* + * Specify this header value to operate only on a blob if it has not been + * modified since the specified date/time. + */ + @JsonProperty(value = "ifUnmodifiedSince") + private DateTimeRfc1123 ifUnmodifiedSince; + + /* + * Specify an ETag value to operate only on blobs with a matching value. + */ + @JsonProperty(value = "ifMatch") + private String ifMatch; + + /* + * Specify an ETag value to operate only on blobs without a matching value. + */ + @JsonProperty(value = "ifNoneMatch") + private String ifNoneMatch; + + /** + * Get the ifModifiedSince property: Specify this header value to operate + * only on a blob if it has been modified since the specified date/time. + * + * @return the ifModifiedSince value. + */ + public OffsetDateTime ifModifiedSince() { + if (this.ifModifiedSince == null) { + return null; + } + return this.ifModifiedSince.dateTime(); + } + + /** + * Set the ifModifiedSince property: Specify this header value to operate + * only on a blob if it has been modified since the specified date/time. + * + * @param ifModifiedSince the ifModifiedSince value to set. + * @return the ModifiedAccessConditions object itself. + */ + public ModifiedAccessConditions ifModifiedSince(OffsetDateTime ifModifiedSince) { + if (ifModifiedSince == null) { + this.ifModifiedSince = null; + } else { + this.ifModifiedSince = new DateTimeRfc1123(ifModifiedSince); + } + return this; + } + + /** + * Get the ifUnmodifiedSince property: Specify this header value to operate + * only on a blob if it has not been modified since the specified + * date/time. + * + * @return the ifUnmodifiedSince value. + */ + public OffsetDateTime ifUnmodifiedSince() { + if (this.ifUnmodifiedSince == null) { + return null; + } + return this.ifUnmodifiedSince.dateTime(); + } + + /** + * Set the ifUnmodifiedSince property: Specify this header value to operate + * only on a blob if it has not been modified since the specified + * date/time. + * + * @param ifUnmodifiedSince the ifUnmodifiedSince value to set. + * @return the ModifiedAccessConditions object itself. + */ + public ModifiedAccessConditions ifUnmodifiedSince(OffsetDateTime ifUnmodifiedSince) { + if (ifUnmodifiedSince == null) { + this.ifUnmodifiedSince = null; + } else { + this.ifUnmodifiedSince = new DateTimeRfc1123(ifUnmodifiedSince); + } + return this; + } + + /** + * Get the ifMatch property: Specify an ETag value to operate only on blobs + * with a matching value. + * + * @return the ifMatch value. + */ + public String ifMatch() { + return this.ifMatch; + } + + /** + * Set the ifMatch property: Specify an ETag value to operate only on blobs + * with a matching value. + * + * @param ifMatch the ifMatch value to set. + * @return the ModifiedAccessConditions object itself. + */ + public ModifiedAccessConditions ifMatch(String ifMatch) { + this.ifMatch = ifMatch; + return this; + } + + /** + * Get the ifNoneMatch property: Specify an ETag value to operate only on + * blobs without a matching value. + * + * @return the ifNoneMatch value. + */ + public String ifNoneMatch() { + return this.ifNoneMatch; + } + + /** + * Set the ifNoneMatch property: Specify an ETag value to operate only on + * blobs without a matching value. + * + * @param ifNoneMatch the ifNoneMatch value to set. + * @return the ModifiedAccessConditions object itself. + */ + public ModifiedAccessConditions ifNoneMatch(String ifNoneMatch) { + this.ifNoneMatch = ifNoneMatch; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobAccessConditions.java new file mode 100644 index 0000000000000..96250a2d60cc5 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobAccessConditions.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +/** + * This class contains values that restrict the successful completion of PageBlob operations to certain conditions. + * It may be set to null if no access conditions are desired. + *

    + * Please refer to the request header section + * here for more conceptual information. + */ +public final class PageBlobAccessConditions { + + private SequenceNumberAccessConditions sequenceNumberAccessConditions; + + private ModifiedAccessConditions modifiedAccessConditions; + + private LeaseAccessConditions leaseAccessConditions; + + /** + * Creates an instance which has fields set to non-null, empty values. + */ + public PageBlobAccessConditions() { + this.sequenceNumberAccessConditions = new SequenceNumberAccessConditions(); + this.modifiedAccessConditions = new ModifiedAccessConditions(); + this.leaseAccessConditions = new LeaseAccessConditions(); + } + + /** + * Access conditions that will fail the request if the sequence number does not meet the provided condition. + * + * @return the sequence number access conditions + */ + public SequenceNumberAccessConditions sequenceNumberAccessConditions() { + return sequenceNumberAccessConditions; + } + + /** + * Access conditions that will fail the request if the sequence number does not meet the provided condition. + * + * @param sequenceNumberAccessConditions the sequence number access conditions to set + * @return the updated PageBlobAccessConditions object + */ + public PageBlobAccessConditions sequenceNumberAccessConditions( + SequenceNumberAccessConditions sequenceNumberAccessConditions) { + this.sequenceNumberAccessConditions = sequenceNumberAccessConditions; + return this; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @return the modified access conditions + */ + public ModifiedAccessConditions modifiedAccessConditions() { + return modifiedAccessConditions; + } + + /** + * Standard HTTP Access conditions related to the modification of data. ETag and LastModifiedTime are used to + * construct conditions related to when the blob was changed relative to the given request. The request + * will fail if the specified condition is not satisfied. + * + * @param modifiedAccessConditions the modified access conditions to set + * @return the updated PageBlobAccessConditions object + */ + public PageBlobAccessConditions modifiedAccessConditions(ModifiedAccessConditions modifiedAccessConditions) { + this.modifiedAccessConditions = modifiedAccessConditions; + return this; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @return the lease access conditions + */ + public LeaseAccessConditions leaseAccessConditions() { + return leaseAccessConditions; + } + + /** + * By setting lease access conditions, requests will fail if the provided lease does not match the active lease on + * the blob. + * + * @param leaseAccessConditions the lease access conditions to set + * @return the updated PageBlobAccessConditions object + */ + public PageBlobAccessConditions leaseAccessConditions(LeaseAccessConditions leaseAccessConditions) { + this.leaseAccessConditions = leaseAccessConditions; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobClearPagesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobClearPagesHeaders.java new file mode 100644 index 0000000000000..45f30cefd53a1 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobClearPagesHeaders.java @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ClearPages operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-ClearPages-Headers") +public final class PageBlobClearPagesHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * The current sequence number for the page blob. + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobClearPagesHeaders object itself. + */ + public PageBlobClearPagesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCopyIncrementalHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCopyIncrementalHeaders.java new file mode 100644 index 0000000000000..3a1ea5cd5f9d7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCopyIncrementalHeaders.java @@ -0,0 +1,275 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for CopyIncremental operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-CopyIncremental-Headers") +public final class PageBlobCopyIncrementalHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * String identifier for this copy operation. Use with Get Blob Properties + * to check the status of this copy operation, or pass to Abort Copy Blob + * to abort a pending copy. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. Use + * with Get Blob Properties to check the status of this copy operation, or + * pass to Abort Copy Blob to abort a pending copy. + * + * @param copyId the copyId value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobCopyIncrementalHeaders object itself. + */ + public PageBlobCopyIncrementalHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCreateHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCreateHeaders.java new file mode 100644 index 0000000000000..215c6f4c934aa --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobCreateHeaders.java @@ -0,0 +1,341 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-Create-Headers") +public final class PageBlobCreateHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that identifies a version + * of the blob. This header is returned for requests made against version + * 2018-11-09 and above. + */ + @JsonProperty(value = "x-ms-version-id") + private String versionId; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the blob. This + * header is only returned when the blob was encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @return the versionId value. + */ + public String versionId() { + return this.versionId; + } + + /** + * Set the versionId property: UTC date/time value generated by the service + * that identifies a version of the blob. This header is returned for + * requests made against version 2018-11-09 and above. + * + * @param versionId the versionId value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders versionId(String versionId) { + this.versionId = versionId; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the blob. This header is only returned when the blob + * was encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobCreateHeaders object itself. + */ + public PageBlobCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesDiffHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesDiffHeaders.java new file mode 100644 index 0000000000000..5f75cf82af768 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesDiffHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetPageRangesDiff operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-GetPageRangesDiff-Headers") +public final class PageBlobGetPageRangesDiffHeaders { + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * The size of the blob in bytes. + */ + @JsonProperty(value = "x-ms-blob-content-length") + private Long blobContentLength; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the blobContentLength property: The size of the blob in bytes. + * + * @return the blobContentLength value. + */ + public Long blobContentLength() { + return this.blobContentLength; + } + + /** + * Set the blobContentLength property: The size of the blob in bytes. + * + * @param blobContentLength the blobContentLength value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders blobContentLength(Long blobContentLength) { + this.blobContentLength = blobContentLength; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobGetPageRangesDiffHeaders object itself. + */ + public PageBlobGetPageRangesDiffHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesHeaders.java new file mode 100644 index 0000000000000..a9004d8dd2c91 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobGetPageRangesHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetPageRanges operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-GetPageRanges-Headers") +public final class PageBlobGetPageRangesHeaders { + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * The size of the blob in bytes. + */ + @JsonProperty(value = "x-ms-blob-content-length") + private Long blobContentLength; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the blobContentLength property: The size of the blob in bytes. + * + * @return the blobContentLength value. + */ + public Long blobContentLength() { + return this.blobContentLength; + } + + /** + * Set the blobContentLength property: The size of the blob in bytes. + * + * @param blobContentLength the blobContentLength value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders blobContentLength(Long blobContentLength) { + this.blobContentLength = blobContentLength; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobGetPageRangesHeaders object itself. + */ + public PageBlobGetPageRangesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobItem.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobItem.java new file mode 100644 index 0000000000000..52f6911c667d2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobItem.java @@ -0,0 +1,76 @@ +package com.azure.storage.blob.models; + +import com.azure.core.implementation.util.ImplUtils; + +import java.time.OffsetDateTime; + +public class PageBlobItem { + + private OffsetDateTime lastModified; + + private byte[] contentMD5; + + private Boolean isServerEncrypted; + + private String encryptionKeySha256; + + private Long blobSequenceNumber; + + public PageBlobItem(PageBlobCreateHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + } + + public PageBlobItem(PageBlobUploadPagesHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.encryptionKeySha256 = generatedHeaders.encryptionKeySha256(); + this.blobSequenceNumber = generatedHeaders.blobSequenceNumber(); + } + + public PageBlobItem(PageBlobUploadPagesFromURLHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.isServerEncrypted = generatedHeaders.isServerEncrypted(); + this.blobSequenceNumber = generatedHeaders.blobSequenceNumber(); + } + + public PageBlobItem(PageBlobClearPagesHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.contentMD5 = generatedHeaders.contentMD5(); + this.blobSequenceNumber = generatedHeaders.blobSequenceNumber(); + } + + public PageBlobItem(PageBlobResizeHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.blobSequenceNumber = generatedHeaders.blobSequenceNumber(); + } + + public PageBlobItem(PageBlobUpdateSequenceNumberHeaders generatedHeaders) { + this.lastModified = generatedHeaders.lastModified(); + this.blobSequenceNumber = generatedHeaders.blobSequenceNumber(); + } + + public OffsetDateTime lastModified() { + return lastModified; + }; + + public Boolean isServerEncrypted() { + return isServerEncrypted; + } + + public String encryptionKeySha256() { + return encryptionKeySha256; + } + + public byte[] contentMD5() { + return ImplUtils.clone(contentMD5); + } + + public Long blobSequenceNumber() { + return blobSequenceNumber; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobResizeHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobResizeHeaders.java new file mode 100644 index 0000000000000..f9396b66835c3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobResizeHeaders.java @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Resize operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-Resize-Headers") +public final class PageBlobResizeHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The current sequence number for a page blob. This header is not returned + * for block blobs or append blobs + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobResizeHeaders object itself. + */ + public PageBlobResizeHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUpdateSequenceNumberHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUpdateSequenceNumberHeaders.java new file mode 100644 index 0000000000000..317c57bb35cea --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUpdateSequenceNumberHeaders.java @@ -0,0 +1,241 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for UpdateSequenceNumber operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-UpdateSequenceNumber-Headers") +public final class PageBlobUpdateSequenceNumberHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The current sequence number for a page blob. This header is not returned + * for block blobs or append blobs + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for a + * page blob. This header is not returned for block blobs or append blobs. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobUpdateSequenceNumberHeaders object itself. + */ + public PageBlobUpdateSequenceNumberHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesFromURLHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesFromURLHeaders.java new file mode 100644 index 0000000000000..ad21b582b509e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesFromURLHeaders.java @@ -0,0 +1,305 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for UploadPagesFromURL operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-UploadPagesFromURL-Headers") +public final class PageBlobUploadPagesFromURLHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * The current sequence number for the page blob. + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobUploadPagesFromURLHeaders object itself. + */ + public PageBlobUploadPagesFromURLHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesHeaders.java new file mode 100644 index 0000000000000..29cf41bae0b8e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobUploadPagesHeaders.java @@ -0,0 +1,337 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.azure.core.implementation.util.ImplUtils; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for UploadPages operation. + */ +@JacksonXmlRootElement(localName = "PageBlob-UploadPages-Headers") +public final class PageBlobUploadPagesHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally. If the request version is 2011-08-18 or newer, the ETag + * value will be in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the container was last modified. Any operation + * that modifies the blob, including an update of the blob's metadata or + * properties, changes the last-modified time of the blob. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * If the blob has an MD5 hash and this operation is to read the full blob, + * this response header is returned so that the client can check for + * message content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * The current sequence number for the page blob. + */ + @JsonProperty(value = "x-ms-blob-sequence-number") + private Long blobSequenceNumber; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The SHA-256 hash of the encryption key used to encrypt the pages. This + * header is only returned when the pages were encrypted with a + * customer-provided key. + */ + @JsonProperty(value = "x-ms-encryption-key-sha256") + private String encryptionKeySha256; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally. If the request version is 2011-08-18 + * or newer, the ETag value will be in quotes. + * + * @param eTag the eTag value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the container + * was last modified. Any operation that modifies the blob, including an + * update of the blob's metadata or properties, changes the last-modified + * time of the blob. + * + * @param lastModified the lastModified value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return ImplUtils.clone(this.contentMD5); + } + + /** + * Set the contentMD5 property: If the blob has an MD5 hash and this + * operation is to read the full blob, this response header is returned so + * that the client can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = ImplUtils.clone(contentMD5); + return this; + } + + /** + * Get the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @return the blobSequenceNumber value. + */ + public Long blobSequenceNumber() { + return this.blobSequenceNumber; + } + + /** + * Set the blobSequenceNumber property: The current sequence number for the + * page blob. + * + * @param blobSequenceNumber the blobSequenceNumber value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders blobSequenceNumber(Long blobSequenceNumber) { + this.blobSequenceNumber = blobSequenceNumber; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the pages. This header is only returned when the + * pages were encrypted with a customer-provided key. + * + * @return the encryptionKeySha256 value. + */ + public String encryptionKeySha256() { + return this.encryptionKeySha256; + } + + /** + * Set the encryptionKeySha256 property: The SHA-256 hash of the encryption + * key used to encrypt the pages. This header is only returned when the + * pages were encrypted with a customer-provided key. + * + * @param encryptionKeySha256 the encryptionKeySha256 value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders encryptionKeySha256(String encryptionKeySha256) { + this.encryptionKeySha256 = encryptionKeySha256; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the PageBlobUploadPagesHeaders object itself. + */ + public PageBlobUploadPagesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsClearPagesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsClearPagesResponse.java new file mode 100644 index 0000000000000..b85c5e2dff902 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsClearPagesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the clearPages operation. + */ +public final class PageBlobsClearPagesResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsClearPagesResponse. + * + * @param request the request which resulted in this PageBlobsClearPagesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsClearPagesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobClearPagesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCopyIncrementalResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCopyIncrementalResponse.java new file mode 100644 index 0000000000000..819c8bbbd8d9b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCopyIncrementalResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the copyIncremental operation. + */ +public final class PageBlobsCopyIncrementalResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsCopyIncrementalResponse. + * + * @param request the request which resulted in this PageBlobsCopyIncrementalResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsCopyIncrementalResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobCopyIncrementalHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCreateResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCreateResponse.java new file mode 100644 index 0000000000000..835d537ff9a8b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class PageBlobsCreateResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsCreateResponse. + * + * @param request the request which resulted in this PageBlobsCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesDiffResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesDiffResponse.java new file mode 100644 index 0000000000000..987b49716aabd --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesDiffResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getPageRangesDiff operation. + */ +public final class PageBlobsGetPageRangesDiffResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsGetPageRangesDiffResponse. + * + * @param request the request which resulted in this PageBlobsGetPageRangesDiffResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsGetPageRangesDiffResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, PageList value, PageBlobGetPageRangesDiffHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public PageList value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesResponse.java new file mode 100644 index 0000000000000..0e90e17142621 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsGetPageRangesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getPageRanges operation. + */ +public final class PageBlobsGetPageRangesResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsGetPageRangesResponse. + * + * @param request the request which resulted in this PageBlobsGetPageRangesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsGetPageRangesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, PageList value, PageBlobGetPageRangesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public PageList value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsResizeResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsResizeResponse.java new file mode 100644 index 0000000000000..27f0cb1c38d31 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsResizeResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the resize operation. + */ +public final class PageBlobsResizeResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsResizeResponse. + * + * @param request the request which resulted in this PageBlobsResizeResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsResizeResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobResizeHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUpdateSequenceNumberResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUpdateSequenceNumberResponse.java new file mode 100644 index 0000000000000..3855cd4a7ba58 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUpdateSequenceNumberResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the updateSequenceNumber operation. + */ +public final class PageBlobsUpdateSequenceNumberResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsUpdateSequenceNumberResponse. + * + * @param request the request which resulted in this PageBlobsUpdateSequenceNumberResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsUpdateSequenceNumberResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobUpdateSequenceNumberHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesFromURLResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesFromURLResponse.java new file mode 100644 index 0000000000000..f21558d5d6bf7 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesFromURLResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the uploadPagesFromURL operation. + */ +public final class PageBlobsUploadPagesFromURLResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsUploadPagesFromURLResponse. + * + * @param request the request which resulted in this PageBlobsUploadPagesFromURLResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsUploadPagesFromURLResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobUploadPagesFromURLHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesResponse.java new file mode 100644 index 0000000000000..4d0c46ce08ca0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageBlobsUploadPagesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the uploadPages operation. + */ +public final class PageBlobsUploadPagesResponse extends ResponseBase { + /** + * Creates an instance of PageBlobsUploadPagesResponse. + * + * @param request the request which resulted in this PageBlobsUploadPagesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public PageBlobsUploadPagesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, PageBlobUploadPagesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageList.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageList.java new file mode 100644 index 0000000000000..cf921ab92646b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageList.java @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * the list of pages. + */ +@JacksonXmlRootElement(localName = "PageList") +public final class PageList { + /* + * The pageRange property. + */ + @JsonProperty("PageRange") + private List pageRange = new ArrayList<>(); + + /* + * The clearRange property. + */ + @JsonProperty("ClearRange") + private List clearRange = new ArrayList<>(); + + /** + * Get the pageRange property: The pageRange property. + * + * @return the pageRange value. + */ + public List pageRange() { + return this.pageRange; + } + + /** + * Set the pageRange property: The pageRange property. + * + * @param pageRange the pageRange value to set. + * @return the PageList object itself. + */ + public PageList pageRange(List pageRange) { + this.pageRange = pageRange; + return this; + } + + /** + * Get the clearRange property: The clearRange property. + * + * @return the clearRange value. + */ + public List clearRange() { + return this.clearRange; + } + + /** + * Set the clearRange property: The clearRange property. + * + * @param clearRange the clearRange value to set. + * @return the PageList object itself. + */ + public PageList clearRange(List clearRange) { + this.clearRange = clearRange; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageRange.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageRange.java new file mode 100644 index 0000000000000..5ce78ebfb0db8 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PageRange.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The PageRange model. + */ +@JacksonXmlRootElement(localName = "PageRange") +public final class PageRange { + /* + * The start property. + */ + @JsonProperty(value = "Start", required = true) + private long start; + + /* + * The end property. + */ + @JsonProperty(value = "End", required = true) + private long end; + + /** + * Get the start property: The start property. + * + * @return the start value. + */ + public long start() { + return this.start; + } + + /** + * Set the start property: The start property. + * + * @param start the start value to set. + * @return the PageRange object itself. + */ + public PageRange start(long start) { + this.start = start; + return this; + } + + /** + * Get the end property: The end property. + * + * @return the end value. + */ + public long end() { + return this.end; + } + + /** + * Set the end property: The end property. + * + * @param end the end value to set. + * @return the PageRange object itself. + */ + public PageRange end(long end) { + this.end = end; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/PublicAccessType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PublicAccessType.java new file mode 100644 index 0000000000000..6bc958765fb81 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/PublicAccessType.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for PublicAccessType. + */ +public final class PublicAccessType extends ExpandableStringEnum { + /** + * Static value container for PublicAccessType. + */ + public static final PublicAccessType CONTAINER = fromString("container"); + + /** + * Static value blob for PublicAccessType. + */ + public static final PublicAccessType BLOB = fromString("blob"); + + /** + * Creates or finds a PublicAccessType from its string representation. + * + * @param name a name to look for. + * @return the corresponding PublicAccessType. + */ + @JsonCreator + public static PublicAccessType fromString(String name) { + return fromString(name, PublicAccessType.class); + } + + /** + * @return known PublicAccessType values. + */ + public static Collection values() { + return values(PublicAccessType.class); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java new file mode 100644 index 0000000000000..b85680617a126 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ReliableDownloadOptions.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob.models; + +import com.azure.storage.blob.DownloadAsyncResponse; + +import java.util.Locale; + +/** + * {@code ReliableDownloadOptions} contains properties which help the {@code Flux} returned from + * {@link DownloadAsyncResponse#body(ReliableDownloadOptions)} determine when to retry. + */ +public final class ReliableDownloadOptions { + private static final String PARAMETER_NOT_IN_RANGE = "The value of the parameter '%s' should be between %s and %s."; + + /* + We use "retry" here because by the time the user passes this type, the initial request, or try, has already been + issued and returned. This is in contrast to the retry policy options, which includes the initial try in its count, + thus the difference in verbiage. + */ + private int maxRetryRequests = 0; + + /** + * Specifies the maximum number of additional HTTP Get requests that will be made while reading the data from a + * response body. + * + * @return the maximum number of retries to attempt before the request finally fails + */ + public int maxRetryRequests() { + return maxRetryRequests; + } + + /** + * Specifies the maximum number of additional HTTP Get requests that will be made while reading the data from a + * response body. + * + * @param maxRetryRequests The number of retries to attempt before the request finally fails + * @return the updated ReliableDownloadOptions object + * @throws IllegalArgumentException If {@code maxRetryRequests} is less than 0 + */ + public ReliableDownloadOptions maxRetryRequests(int maxRetryRequests) { + if (maxRetryRequests < 0) { + throw new IllegalArgumentException(String.format(Locale.ROOT, PARAMETER_NOT_IN_RANGE, + "options.maxRetryRequests", 0, Integer.MAX_VALUE)); + } + + this.maxRetryRequests = maxRetryRequests; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/RetentionPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/RetentionPolicy.java new file mode 100644 index 0000000000000..d6285c64af18f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/RetentionPolicy.java @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * the retention policy which determines how long the associated data should + * persist. + */ +@JacksonXmlRootElement(localName = "RetentionPolicy") +public final class RetentionPolicy { + /* + * Indicates whether a retention policy is enabled for the storage service + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates the number of days that metrics or logging or soft-deleted + * data should be retained. All data older than this value will be deleted + */ + @JsonProperty(value = "Days") + private Integer days; + + /** + * Get the enabled property: Indicates whether a retention policy is + * enabled for the storage service. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether a retention policy is + * enabled for the storage service. + * + * @param enabled the enabled value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the days property: Indicates the number of days that metrics or + * logging or soft-deleted data should be retained. All data older than + * this value will be deleted. + * + * @return the days value. + */ + public Integer days() { + return this.days; + } + + /** + * Set the days property: Indicates the number of days that metrics or + * logging or soft-deleted data should be retained. All data older than + * this value will be deleted. + * + * @param days the days value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy days(Integer days) { + this.days = days; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberAccessConditions.java new file mode 100644 index 0000000000000..df0399ff59123 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberAccessConditions.java @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Additional parameters for a set of operations, such as: + * PageBlobs_uploadPages, PageBlobs_clearPages, PageBlobs_uploadPagesFromURL. + */ +@JacksonXmlRootElement(localName = "sequence-number-access-conditions") +public final class SequenceNumberAccessConditions { + /* + * Specify this header value to operate only on a blob if it has a sequence + * number less than or equal to the specified. + */ + @JsonProperty(value = "ifSequenceNumberLessThanOrEqualTo") + private Long ifSequenceNumberLessThanOrEqualTo; + + /* + * Specify this header value to operate only on a blob if it has a sequence + * number less than the specified. + */ + @JsonProperty(value = "ifSequenceNumberLessThan") + private Long ifSequenceNumberLessThan; + + /* + * Specify this header value to operate only on a blob if it has the + * specified sequence number. + */ + @JsonProperty(value = "ifSequenceNumberEqualTo") + private Long ifSequenceNumberEqualTo; + + /** + * Get the ifSequenceNumberLessThanOrEqualTo property: Specify this header + * value to operate only on a blob if it has a sequence number less than or + * equal to the specified. + * + * @return the ifSequenceNumberLessThanOrEqualTo value. + */ + public Long ifSequenceNumberLessThanOrEqualTo() { + return this.ifSequenceNumberLessThanOrEqualTo; + } + + /** + * Set the ifSequenceNumberLessThanOrEqualTo property: Specify this header + * value to operate only on a blob if it has a sequence number less than or + * equal to the specified. + * + * @param ifSequenceNumberLessThanOrEqualTo the + * ifSequenceNumberLessThanOrEqualTo value to set. + * @return the SequenceNumberAccessConditions object itself. + */ + public SequenceNumberAccessConditions ifSequenceNumberLessThanOrEqualTo(Long ifSequenceNumberLessThanOrEqualTo) { + this.ifSequenceNumberLessThanOrEqualTo = ifSequenceNumberLessThanOrEqualTo; + return this; + } + + /** + * Get the ifSequenceNumberLessThan property: Specify this header value to + * operate only on a blob if it has a sequence number less than the + * specified. + * + * @return the ifSequenceNumberLessThan value. + */ + public Long ifSequenceNumberLessThan() { + return this.ifSequenceNumberLessThan; + } + + /** + * Set the ifSequenceNumberLessThan property: Specify this header value to + * operate only on a blob if it has a sequence number less than the + * specified. + * + * @param ifSequenceNumberLessThan the ifSequenceNumberLessThan value to + * set. + * @return the SequenceNumberAccessConditions object itself. + */ + public SequenceNumberAccessConditions ifSequenceNumberLessThan(Long ifSequenceNumberLessThan) { + this.ifSequenceNumberLessThan = ifSequenceNumberLessThan; + return this; + } + + /** + * Get the ifSequenceNumberEqualTo property: Specify this header value to + * operate only on a blob if it has the specified sequence number. + * + * @return the ifSequenceNumberEqualTo value. + */ + public Long ifSequenceNumberEqualTo() { + return this.ifSequenceNumberEqualTo; + } + + /** + * Set the ifSequenceNumberEqualTo property: Specify this header value to + * operate only on a blob if it has the specified sequence number. + * + * @param ifSequenceNumberEqualTo the ifSequenceNumberEqualTo value to set. + * @return the SequenceNumberAccessConditions object itself. + */ + public SequenceNumberAccessConditions ifSequenceNumberEqualTo(Long ifSequenceNumberEqualTo) { + this.ifSequenceNumberEqualTo = ifSequenceNumberEqualTo; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberActionType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberActionType.java new file mode 100644 index 0000000000000..fa1bff92e415f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SequenceNumberActionType.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for SequenceNumberActionType. + */ +public enum SequenceNumberActionType { + /** + * Enum value max. + */ + MAX("max"), + + /** + * Enum value update. + */ + UPDATE("update"), + + /** + * Enum value increment. + */ + INCREMENT("increment"); + + /** + * The actual serialized value for a SequenceNumberActionType instance. + */ + private final String value; + + SequenceNumberActionType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a SequenceNumberActionType instance. + * + * @param value the serialized value to parse. + * @return the parsed SequenceNumberActionType object, or null if unable to parse. + */ + @JsonCreator + public static SequenceNumberActionType fromString(String value) { + SequenceNumberActionType[] items = SequenceNumberActionType.values(); + for (SequenceNumberActionType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetAccountInfoHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetAccountInfoHeaders.java new file mode 100644 index 0000000000000..b0c6820cf0848 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetAccountInfoHeaders.java @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccountInfo operation. + */ +@JacksonXmlRootElement(localName = "Service-GetAccountInfo-Headers") +public final class ServiceGetAccountInfoHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Identifies the sku name of the account. Possible values include: + * 'Standard_LRS', 'Standard_GRS', 'Standard_RAGRS', 'Standard_ZRS', + * 'Premium_LRS' + */ + @JsonProperty(value = "x-ms-sku-name") + private SkuName skuName; + + /* + * Identifies the account kind. Possible values include: 'Storage', + * 'BlobStorage', 'StorageV2' + */ + @JsonProperty(value = "x-ms-account-kind") + private AccountKind accountKind; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @return the skuName value. + */ + public SkuName skuName() { + return this.skuName; + } + + /** + * Set the skuName property: Identifies the sku name of the account. + * Possible values include: 'Standard_LRS', 'Standard_GRS', + * 'Standard_RAGRS', 'Standard_ZRS', 'Premium_LRS'. + * + * @param skuName the skuName value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders skuName(SkuName skuName) { + this.skuName = skuName; + return this; + } + + /** + * Get the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @return the accountKind value. + */ + public AccountKind accountKind() { + return this.accountKind; + } + + /** + * Set the accountKind property: Identifies the account kind. Possible + * values include: 'Storage', 'BlobStorage', 'StorageV2'. + * + * @param accountKind the accountKind value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders accountKind(AccountKind accountKind) { + this.accountKind = accountKind; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetAccountInfoHeaders object itself. + */ + public ServiceGetAccountInfoHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetPropertiesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetPropertiesHeaders.java new file mode 100644 index 0000000000000..3126a5153421e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetPropertiesHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-GetProperties-Headers") +public final class ServiceGetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetStatisticsHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetStatisticsHeaders.java new file mode 100644 index 0000000000000..34fcda3653a60 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetStatisticsHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetStatistics operation. + */ +@JacksonXmlRootElement(localName = "Service-GetStatistics-Headers") +public final class ServiceGetStatisticsHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetUserDelegationKeyHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetUserDelegationKeyHeaders.java new file mode 100644 index 0000000000000..9c685c2906102 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceGetUserDelegationKeyHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetUserDelegationKey operation. + */ +@JacksonXmlRootElement(localName = "Service-GetUserDelegationKey-Headers") +public final class ServiceGetUserDelegationKeyHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetUserDelegationKeyHeaders object itself. + */ + public ServiceGetUserDelegationKeyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetUserDelegationKeyHeaders object itself. + */ + public ServiceGetUserDelegationKeyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ServiceGetUserDelegationKeyHeaders object itself. + */ + public ServiceGetUserDelegationKeyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetUserDelegationKeyHeaders object itself. + */ + public ServiceGetUserDelegationKeyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceListContainersSegmentHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceListContainersSegmentHeaders.java new file mode 100644 index 0000000000000..d22b9f1febc4f --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceListContainersSegmentHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for ListContainersSegment operation. + */ +@JacksonXmlRootElement(localName = "Service-ListContainersSegment-Headers") +public final class ServiceListContainersSegmentHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceListContainersSegmentHeaders object itself. + */ + public ServiceListContainersSegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceListContainersSegmentHeaders object itself. + */ + public ServiceListContainersSegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceListContainersSegmentHeaders object itself. + */ + public ServiceListContainersSegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceSetPropertiesHeaders.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceSetPropertiesHeaders.java new file mode 100644 index 0000000000000..065e595244fc3 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServiceSetPropertiesHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for SetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-SetProperties-Headers") +public final class ServiceSetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Blob service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Blob service used + * to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetAccountInfoResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetAccountInfoResponse.java new file mode 100644 index 0000000000000..e4817e49e208a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetAccountInfoResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getAccountInfo operation. + */ +public final class ServicesGetAccountInfoResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetAccountInfoResponse. + * + * @param request the request which resulted in this ServicesGetAccountInfoResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetAccountInfoResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ServiceGetAccountInfoHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetPropertiesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetPropertiesResponse.java new file mode 100644 index 0000000000000..8ac29adaf0b79 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetPropertiesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class ServicesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetPropertiesResponse. + * + * @param request the request which resulted in this ServicesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, StorageServiceProperties value, ServiceGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public StorageServiceProperties value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetStatisticsResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetStatisticsResponse.java new file mode 100644 index 0000000000000..e99c9ad3906fb --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetStatisticsResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getStatistics operation. + */ +public final class ServicesGetStatisticsResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetStatisticsResponse. + * + * @param request the request which resulted in this ServicesGetStatisticsResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetStatisticsResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, StorageServiceStats value, ServiceGetStatisticsHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public StorageServiceStats value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetUserDelegationKeyResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetUserDelegationKeyResponse.java new file mode 100644 index 0000000000000..ee7db7122a4f0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesGetUserDelegationKeyResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getUserDelegationKey operation. + */ +public final class ServicesGetUserDelegationKeyResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetUserDelegationKeyResponse. + * + * @param request the request which resulted in this ServicesGetUserDelegationKeyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetUserDelegationKeyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, UserDelegationKey value, ServiceGetUserDelegationKeyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public UserDelegationKey value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesListContainersSegmentResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesListContainersSegmentResponse.java new file mode 100644 index 0000000000000..ab701d9d6139d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesListContainersSegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listContainersSegment operation. + */ +public final class ServicesListContainersSegmentResponse extends ResponseBase { + /** + * Creates an instance of ServicesListContainersSegmentResponse. + * + * @param request the request which resulted in this ServicesListContainersSegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesListContainersSegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListContainersSegmentResponse value, ServiceListContainersSegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListContainersSegmentResponse value() { + return super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesSetPropertiesResponse.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesSetPropertiesResponse.java new file mode 100644 index 0000000000000..aa796b36f142a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/ServicesSetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setProperties operation. + */ +public final class ServicesSetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesSetPropertiesResponse. + * + * @param request the request which resulted in this ServicesSetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesSetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ServiceSetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SignedIdentifier.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SignedIdentifier.java new file mode 100644 index 0000000000000..417f49492e51a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SignedIdentifier.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * signed identifier. + */ +@JacksonXmlRootElement(localName = "SignedIdentifier") +public final class SignedIdentifier { + /* + * a unique id + */ + @JsonProperty(value = "Id", required = true) + private String id; + + /* + * The accessPolicy property. + */ + @JsonProperty(value = "AccessPolicy", required = true) + private AccessPolicy accessPolicy; + + /** + * Get the id property: a unique id. + * + * @return the id value. + */ + public String id() { + return this.id; + } + + /** + * Set the id property: a unique id. + * + * @param id the id value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier id(String id) { + this.id = id; + return this; + } + + /** + * Get the accessPolicy property: The accessPolicy property. + * + * @return the accessPolicy value. + */ + public AccessPolicy accessPolicy() { + return this.accessPolicy; + } + + /** + * Set the accessPolicy property: The accessPolicy property. + * + * @param accessPolicy the accessPolicy value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier accessPolicy(AccessPolicy accessPolicy) { + this.accessPolicy = accessPolicy; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SkuName.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SkuName.java new file mode 100644 index 0000000000000..30cfa3997e5e0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SkuName.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for SkuName. + */ +public enum SkuName { + /** + * Enum value Standard_LRS. + */ + STANDARD_LRS("Standard_LRS"), + + /** + * Enum value Standard_GRS. + */ + STANDARD_GRS("Standard_GRS"), + + /** + * Enum value Standard_RAGRS. + */ + STANDARD_RAGRS("Standard_RAGRS"), + + /** + * Enum value Standard_ZRS. + */ + STANDARD_ZRS("Standard_ZRS"), + + /** + * Enum value Premium_LRS. + */ + PREMIUM_LRS("Premium_LRS"); + + /** + * The actual serialized value for a SkuName instance. + */ + private final String value; + + SkuName(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a SkuName instance. + * + * @param value the serialized value to parse. + * @return the parsed SkuName object, or null if unable to parse. + */ + @JsonCreator + public static SkuName fromString(String value) { + SkuName[] items = SkuName.values(); + for (SkuName item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SourceModifiedAccessConditions.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SourceModifiedAccessConditions.java new file mode 100644 index 0000000000000..84b179bb01812 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SourceModifiedAccessConditions.java @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Additional parameters for a set of operations. + */ +@JacksonXmlRootElement(localName = "source-modified-access-conditions") +public final class SourceModifiedAccessConditions { + /* + * Specify this header value to operate only on a blob if it has been + * modified since the specified date/time. + */ + @JsonProperty(value = "sourceIfModifiedSince") + private DateTimeRfc1123 sourceIfModifiedSince; + + /* + * Specify this header value to operate only on a blob if it has not been + * modified since the specified date/time. + */ + @JsonProperty(value = "sourceIfUnmodifiedSince") + private DateTimeRfc1123 sourceIfUnmodifiedSince; + + /* + * Specify an ETag value to operate only on blobs with a matching value. + */ + @JsonProperty(value = "sourceIfMatch") + private String sourceIfMatch; + + /* + * Specify an ETag value to operate only on blobs without a matching value. + */ + @JsonProperty(value = "sourceIfNoneMatch") + private String sourceIfNoneMatch; + + /** + * Get the sourceIfModifiedSince property: Specify this header value to + * operate only on a blob if it has been modified since the specified + * date/time. + * + * @return the sourceIfModifiedSince value. + */ + public OffsetDateTime sourceIfModifiedSince() { + if (this.sourceIfModifiedSince == null) { + return null; + } + return this.sourceIfModifiedSince.dateTime(); + } + + /** + * Set the sourceIfModifiedSince property: Specify this header value to + * operate only on a blob if it has been modified since the specified + * date/time. + * + * @param sourceIfModifiedSince the sourceIfModifiedSince value to set. + * @return the SourceModifiedAccessConditions object itself. + */ + public SourceModifiedAccessConditions sourceIfModifiedSince(OffsetDateTime sourceIfModifiedSince) { + if (sourceIfModifiedSince == null) { + this.sourceIfModifiedSince = null; + } else { + this.sourceIfModifiedSince = new DateTimeRfc1123(sourceIfModifiedSince); + } + return this; + } + + /** + * Get the sourceIfUnmodifiedSince property: Specify this header value to + * operate only on a blob if it has not been modified since the specified + * date/time. + * + * @return the sourceIfUnmodifiedSince value. + */ + public OffsetDateTime sourceIfUnmodifiedSince() { + if (this.sourceIfUnmodifiedSince == null) { + return null; + } + return this.sourceIfUnmodifiedSince.dateTime(); + } + + /** + * Set the sourceIfUnmodifiedSince property: Specify this header value to + * operate only on a blob if it has not been modified since the specified + * date/time. + * + * @param sourceIfUnmodifiedSince the sourceIfUnmodifiedSince value to set. + * @return the SourceModifiedAccessConditions object itself. + */ + public SourceModifiedAccessConditions sourceIfUnmodifiedSince(OffsetDateTime sourceIfUnmodifiedSince) { + if (sourceIfUnmodifiedSince == null) { + this.sourceIfUnmodifiedSince = null; + } else { + this.sourceIfUnmodifiedSince = new DateTimeRfc1123(sourceIfUnmodifiedSince); + } + return this; + } + + /** + * Get the sourceIfMatch property: Specify an ETag value to operate only on + * blobs with a matching value. + * + * @return the sourceIfMatch value. + */ + public String sourceIfMatch() { + return this.sourceIfMatch; + } + + /** + * Set the sourceIfMatch property: Specify an ETag value to operate only on + * blobs with a matching value. + * + * @param sourceIfMatch the sourceIfMatch value to set. + * @return the SourceModifiedAccessConditions object itself. + */ + public SourceModifiedAccessConditions sourceIfMatch(String sourceIfMatch) { + this.sourceIfMatch = sourceIfMatch; + return this; + } + + /** + * Get the sourceIfNoneMatch property: Specify an ETag value to operate + * only on blobs without a matching value. + * + * @return the sourceIfNoneMatch value. + */ + public String sourceIfNoneMatch() { + return this.sourceIfNoneMatch; + } + + /** + * Set the sourceIfNoneMatch property: Specify an ETag value to operate + * only on blobs without a matching value. + * + * @param sourceIfNoneMatch the sourceIfNoneMatch value to set. + * @return the SourceModifiedAccessConditions object itself. + */ + public SourceModifiedAccessConditions sourceIfNoneMatch(String sourceIfNoneMatch) { + this.sourceIfNoneMatch = sourceIfNoneMatch; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StaticWebsite.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StaticWebsite.java new file mode 100644 index 0000000000000..45971febb06e2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StaticWebsite.java @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The properties that enable an account to host a static website. + */ +@JacksonXmlRootElement(localName = "StaticWebsite") +public final class StaticWebsite { + /* + * Indicates whether this account is hosting a static website + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * The default name of the index page under each directory + */ + @JsonProperty(value = "IndexDocument") + private String indexDocument; + + /* + * The absolute path of the custom 404 page + */ + @JsonProperty(value = "ErrorDocument404Path") + private String errorDocument404Path; + + /** + * Get the enabled property: Indicates whether this account is hosting a + * static website. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether this account is hosting a + * static website. + * + * @param enabled the enabled value to set. + * @return the StaticWebsite object itself. + */ + public StaticWebsite enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the indexDocument property: The default name of the index page under + * each directory. + * + * @return the indexDocument value. + */ + public String indexDocument() { + return this.indexDocument; + } + + /** + * Set the indexDocument property: The default name of the index page under + * each directory. + * + * @param indexDocument the indexDocument value to set. + * @return the StaticWebsite object itself. + */ + public StaticWebsite indexDocument(String indexDocument) { + this.indexDocument = indexDocument; + return this; + } + + /** + * Get the errorDocument404Path property: The absolute path of the custom + * 404 page. + * + * @return the errorDocument404Path value. + */ + public String errorDocument404Path() { + return this.errorDocument404Path; + } + + /** + * Set the errorDocument404Path property: The absolute path of the custom + * 404 page. + * + * @param errorDocument404Path the errorDocument404Path value to set. + * @return the StaticWebsite object itself. + */ + public StaticWebsite errorDocument404Path(String errorDocument404Path) { + this.errorDocument404Path = errorDocument404Path; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageAccountInfo.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageAccountInfo.java new file mode 100644 index 0000000000000..15e0d910c9d7a --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageAccountInfo.java @@ -0,0 +1,33 @@ +package com.azure.storage.blob.models; + +public class StorageAccountInfo { + + private final SkuName skuName; + + private final AccountKind accountKind; + + + public StorageAccountInfo(BlobGetAccountInfoHeaders generatedResponseHeaders) { + this.skuName = generatedResponseHeaders.skuName(); + this.accountKind = generatedResponseHeaders.accountKind(); + } + + public StorageAccountInfo(ContainerGetAccountInfoHeaders generatedResponseHeaders) { + this.skuName = generatedResponseHeaders.skuName(); + this.accountKind = generatedResponseHeaders.accountKind(); + } + + public StorageAccountInfo(ServiceGetAccountInfoHeaders generatedResponseHeaders) { + this.skuName = generatedResponseHeaders.skuName(); + this.accountKind = generatedResponseHeaders.accountKind(); + } + + + public SkuName skuName() { + return skuName; + } + + public AccountKind accountKind() { + return accountKind; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageError.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageError.java new file mode 100644 index 0000000000000..55c96be21c801 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageError.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The StorageError model. + */ +@JacksonXmlRootElement(localName = "StorageError") +public final class StorageError { + /* + * The code property. + */ + @JsonProperty(value = "Code") + private String code; + + /* + * The message property. + */ + @JsonProperty(value = "Message") + private String message; + + /** + * Get the code property: The code property. + * + * @return the code value. + */ + public String code() { + return this.code; + } + + /** + * Set the code property: The code property. + * + * @param code the code value to set. + * @return the StorageError object itself. + */ + public StorageError code(String code) { + this.code = code; + return this; + } + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String message() { + return this.message; + } + + /** + * Set the message property: The message property. + * + * @param message the message value to set. + * @return the StorageError object itself. + */ + public StorageError message(String message) { + this.message = message; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorCode.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorCode.java new file mode 100644 index 0000000000000..5ef1a7209deec --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorCode.java @@ -0,0 +1,557 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for StorageErrorCode. + */ +public final class StorageErrorCode extends ExpandableStringEnum { + /** + * Static value AccountAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_ALREADY_EXISTS = fromString("AccountAlreadyExists"); + + /** + * Static value AccountBeingCreated for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_BEING_CREATED = fromString("AccountBeingCreated"); + + /** + * Static value AccountIsDisabled for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_IS_DISABLED = fromString("AccountIsDisabled"); + + /** + * Static value AuthenticationFailed for StorageErrorCode. + */ + public static final StorageErrorCode AUTHENTICATION_FAILED = fromString("AuthenticationFailed"); + + /** + * Static value AuthorizationFailure for StorageErrorCode. + */ + public static final StorageErrorCode AUTHORIZATION_FAILURE = fromString("AuthorizationFailure"); + + /** + * Static value ConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_HEADERS_NOT_SUPPORTED = fromString("ConditionHeadersNotSupported"); + + /** + * Static value ConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_NOT_MET = fromString("ConditionNotMet"); + + /** + * Static value EmptyMetadataKey for StorageErrorCode. + */ + public static final StorageErrorCode EMPTY_METADATA_KEY = fromString("EmptyMetadataKey"); + + /** + * Static value InsufficientAccountPermissions for StorageErrorCode. + */ + public static final StorageErrorCode INSUFFICIENT_ACCOUNT_PERMISSIONS = fromString("InsufficientAccountPermissions"); + + /** + * Static value InternalError for StorageErrorCode. + */ + public static final StorageErrorCode INTERNAL_ERROR = fromString("InternalError"); + + /** + * Static value InvalidAuthenticationInfo for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_AUTHENTICATION_INFO = fromString("InvalidAuthenticationInfo"); + + /** + * Static value InvalidHeaderValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HEADER_VALUE = fromString("InvalidHeaderValue"); + + /** + * Static value InvalidHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HTTP_VERB = fromString("InvalidHttpVerb"); + + /** + * Static value InvalidInput for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_INPUT = fromString("InvalidInput"); + + /** + * Static value InvalidMd5 for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_MD5 = fromString("InvalidMd5"); + + /** + * Static value InvalidMetadata for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_METADATA = fromString("InvalidMetadata"); + + /** + * Static value InvalidQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_QUERY_PARAMETER_VALUE = fromString("InvalidQueryParameterValue"); + + /** + * Static value InvalidRange for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RANGE = fromString("InvalidRange"); + + /** + * Static value InvalidResourceName for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RESOURCE_NAME = fromString("InvalidResourceName"); + + /** + * Static value InvalidUri for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_URI = fromString("InvalidUri"); + + /** + * Static value InvalidXmlDocument for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_DOCUMENT = fromString("InvalidXmlDocument"); + + /** + * Static value InvalidXmlNodeValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_NODE_VALUE = fromString("InvalidXmlNodeValue"); + + /** + * Static value Md5Mismatch for StorageErrorCode. + */ + public static final StorageErrorCode MD5MISMATCH = fromString("Md5Mismatch"); + + /** + * Static value MetadataTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode METADATA_TOO_LARGE = fromString("MetadataTooLarge"); + + /** + * Static value MissingContentLengthHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_CONTENT_LENGTH_HEADER = fromString("MissingContentLengthHeader"); + + /** + * Static value MissingRequiredQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_QUERY_PARAMETER = fromString("MissingRequiredQueryParameter"); + + /** + * Static value MissingRequiredHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_HEADER = fromString("MissingRequiredHeader"); + + /** + * Static value MissingRequiredXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_XML_NODE = fromString("MissingRequiredXmlNode"); + + /** + * Static value MultipleConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = fromString("MultipleConditionHeadersNotSupported"); + + /** + * Static value OperationTimedOut for StorageErrorCode. + */ + public static final StorageErrorCode OPERATION_TIMED_OUT = fromString("OperationTimedOut"); + + /** + * Static value OutOfRangeInput for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_INPUT = fromString("OutOfRangeInput"); + + /** + * Static value OutOfRangeQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_QUERY_PARAMETER_VALUE = fromString("OutOfRangeQueryParameterValue"); + + /** + * Static value RequestBodyTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_BODY_TOO_LARGE = fromString("RequestBodyTooLarge"); + + /** + * Static value ResourceTypeMismatch for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_TYPE_MISMATCH = fromString("ResourceTypeMismatch"); + + /** + * Static value RequestUrlFailedToParse for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_URL_FAILED_TO_PARSE = fromString("RequestUrlFailedToParse"); + + /** + * Static value ResourceAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_ALREADY_EXISTS = fromString("ResourceAlreadyExists"); + + /** + * Static value ResourceNotFound for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_NOT_FOUND = fromString("ResourceNotFound"); + + /** + * Static value ServerBusy for StorageErrorCode. + */ + public static final StorageErrorCode SERVER_BUSY = fromString("ServerBusy"); + + /** + * Static value UnsupportedHeader for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HEADER = fromString("UnsupportedHeader"); + + /** + * Static value UnsupportedXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_XML_NODE = fromString("UnsupportedXmlNode"); + + /** + * Static value UnsupportedQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_QUERY_PARAMETER = fromString("UnsupportedQueryParameter"); + + /** + * Static value UnsupportedHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HTTP_VERB = fromString("UnsupportedHttpVerb"); + + /** + * Static value AppendPositionConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode APPEND_POSITION_CONDITION_NOT_MET = fromString("AppendPositionConditionNotMet"); + + /** + * Static value BlobAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_ALREADY_EXISTS = fromString("BlobAlreadyExists"); + + /** + * Static value BlobNotFound for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_NOT_FOUND = fromString("BlobNotFound"); + + /** + * Static value BlobOverwritten for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_OVERWRITTEN = fromString("BlobOverwritten"); + + /** + * Static value BlobTierInadequateForContentLength for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_TIER_INADEQUATE_FOR_CONTENT_LENGTH = fromString("BlobTierInadequateForContentLength"); + + /** + * Static value BlockCountExceedsLimit for StorageErrorCode. + */ + public static final StorageErrorCode BLOCK_COUNT_EXCEEDS_LIMIT = fromString("BlockCountExceedsLimit"); + + /** + * Static value BlockListTooLong for StorageErrorCode. + */ + public static final StorageErrorCode BLOCK_LIST_TOO_LONG = fromString("BlockListTooLong"); + + /** + * Static value CannotChangeToLowerTier for StorageErrorCode. + */ + public static final StorageErrorCode CANNOT_CHANGE_TO_LOWER_TIER = fromString("CannotChangeToLowerTier"); + + /** + * Static value CannotVerifyCopySource for StorageErrorCode. + */ + public static final StorageErrorCode CANNOT_VERIFY_COPY_SOURCE = fromString("CannotVerifyCopySource"); + + /** + * Static value ContainerAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode CONTAINER_ALREADY_EXISTS = fromString("ContainerAlreadyExists"); + + /** + * Static value ContainerBeingDeleted for StorageErrorCode. + */ + public static final StorageErrorCode CONTAINER_BEING_DELETED = fromString("ContainerBeingDeleted"); + + /** + * Static value ContainerDisabled for StorageErrorCode. + */ + public static final StorageErrorCode CONTAINER_DISABLED = fromString("ContainerDisabled"); + + /** + * Static value ContainerNotFound for StorageErrorCode. + */ + public static final StorageErrorCode CONTAINER_NOT_FOUND = fromString("ContainerNotFound"); + + /** + * Static value ContentLengthLargerThanTierLimit for StorageErrorCode. + */ + public static final StorageErrorCode CONTENT_LENGTH_LARGER_THAN_TIER_LIMIT = fromString("ContentLengthLargerThanTierLimit"); + + /** + * Static value CopyAcrossAccountsNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode COPY_ACROSS_ACCOUNTS_NOT_SUPPORTED = fromString("CopyAcrossAccountsNotSupported"); + + /** + * Static value CopyIdMismatch for StorageErrorCode. + */ + public static final StorageErrorCode COPY_ID_MISMATCH = fromString("CopyIdMismatch"); + + /** + * Static value FeatureVersionMismatch for StorageErrorCode. + */ + public static final StorageErrorCode FEATURE_VERSION_MISMATCH = fromString("FeatureVersionMismatch"); + + /** + * Static value IncrementalCopyBlobMismatch for StorageErrorCode. + */ + public static final StorageErrorCode INCREMENTAL_COPY_BLOB_MISMATCH = fromString("IncrementalCopyBlobMismatch"); + + /** + * Static value IncrementalCopyOfEralierVersionSnapshotNotAllowed for StorageErrorCode. + */ + public static final StorageErrorCode INCREMENTAL_COPY_OF_ERALIER_VERSION_SNAPSHOT_NOT_ALLOWED = fromString("IncrementalCopyOfEralierVersionSnapshotNotAllowed"); + + /** + * Static value IncrementalCopySourceMustBeSnapshot for StorageErrorCode. + */ + public static final StorageErrorCode INCREMENTAL_COPY_SOURCE_MUST_BE_SNAPSHOT = fromString("IncrementalCopySourceMustBeSnapshot"); + + /** + * Static value InfiniteLeaseDurationRequired for StorageErrorCode. + */ + public static final StorageErrorCode INFINITE_LEASE_DURATION_REQUIRED = fromString("InfiniteLeaseDurationRequired"); + + /** + * Static value InvalidBlobOrBlock for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_BLOB_OR_BLOCK = fromString("InvalidBlobOrBlock"); + + /** + * Static value InvalidBlobTier for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_BLOB_TIER = fromString("InvalidBlobTier"); + + /** + * Static value InvalidBlobType for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_BLOB_TYPE = fromString("InvalidBlobType"); + + /** + * Static value InvalidBlockId for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_BLOCK_ID = fromString("InvalidBlockId"); + + /** + * Static value InvalidBlockList for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_BLOCK_LIST = fromString("InvalidBlockList"); + + /** + * Static value InvalidOperation for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_OPERATION = fromString("InvalidOperation"); + + /** + * Static value InvalidPageRange for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_PAGE_RANGE = fromString("InvalidPageRange"); + + /** + * Static value InvalidSourceBlobType for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_SOURCE_BLOB_TYPE = fromString("InvalidSourceBlobType"); + + /** + * Static value InvalidSourceBlobUrl for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_SOURCE_BLOB_URL = fromString("InvalidSourceBlobUrl"); + + /** + * Static value InvalidVersionForPageBlobOperation for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_VERSION_FOR_PAGE_BLOB_OPERATION = fromString("InvalidVersionForPageBlobOperation"); + + /** + * Static value LeaseAlreadyPresent for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ALREADY_PRESENT = fromString("LeaseAlreadyPresent"); + + /** + * Static value LeaseAlreadyBroken for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ALREADY_BROKEN = fromString("LeaseAlreadyBroken"); + + /** + * Static value LeaseIdMismatchWithBlobOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ID_MISMATCH_WITH_BLOB_OPERATION = fromString("LeaseIdMismatchWithBlobOperation"); + + /** + * Static value LeaseIdMismatchWithContainerOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ID_MISMATCH_WITH_CONTAINER_OPERATION = fromString("LeaseIdMismatchWithContainerOperation"); + + /** + * Static value LeaseIdMismatchWithLeaseOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ID_MISMATCH_WITH_LEASE_OPERATION = fromString("LeaseIdMismatchWithLeaseOperation"); + + /** + * Static value LeaseIdMissing for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_ID_MISSING = fromString("LeaseIdMissing"); + + /** + * Static value LeaseIsBreakingAndCannotBeAcquired for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_IS_BREAKING_AND_CANNOT_BE_ACQUIRED = fromString("LeaseIsBreakingAndCannotBeAcquired"); + + /** + * Static value LeaseIsBreakingAndCannotBeChanged for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_IS_BREAKING_AND_CANNOT_BE_CHANGED = fromString("LeaseIsBreakingAndCannotBeChanged"); + + /** + * Static value LeaseIsBrokenAndCannotBeRenewed for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_IS_BROKEN_AND_CANNOT_BE_RENEWED = fromString("LeaseIsBrokenAndCannotBeRenewed"); + + /** + * Static value LeaseLost for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_LOST = fromString("LeaseLost"); + + /** + * Static value LeaseNotPresentWithBlobOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_NOT_PRESENT_WITH_BLOB_OPERATION = fromString("LeaseNotPresentWithBlobOperation"); + + /** + * Static value LeaseNotPresentWithContainerOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_NOT_PRESENT_WITH_CONTAINER_OPERATION = fromString("LeaseNotPresentWithContainerOperation"); + + /** + * Static value LeaseNotPresentWithLeaseOperation for StorageErrorCode. + */ + public static final StorageErrorCode LEASE_NOT_PRESENT_WITH_LEASE_OPERATION = fromString("LeaseNotPresentWithLeaseOperation"); + + /** + * Static value MaxBlobSizeConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode MAX_BLOB_SIZE_CONDITION_NOT_MET = fromString("MaxBlobSizeConditionNotMet"); + + /** + * Static value NoPendingCopyOperation for StorageErrorCode. + */ + public static final StorageErrorCode NO_PENDING_COPY_OPERATION = fromString("NoPendingCopyOperation"); + + /** + * Static value OperationNotAllowedOnIncrementalCopyBlob for StorageErrorCode. + */ + public static final StorageErrorCode OPERATION_NOT_ALLOWED_ON_INCREMENTAL_COPY_BLOB = fromString("OperationNotAllowedOnIncrementalCopyBlob"); + + /** + * Static value PendingCopyOperation for StorageErrorCode. + */ + public static final StorageErrorCode PENDING_COPY_OPERATION = fromString("PendingCopyOperation"); + + /** + * Static value PreviousSnapshotCannotBeNewer for StorageErrorCode. + */ + public static final StorageErrorCode PREVIOUS_SNAPSHOT_CANNOT_BE_NEWER = fromString("PreviousSnapshotCannotBeNewer"); + + /** + * Static value PreviousSnapshotNotFound for StorageErrorCode. + */ + public static final StorageErrorCode PREVIOUS_SNAPSHOT_NOT_FOUND = fromString("PreviousSnapshotNotFound"); + + /** + * Static value PreviousSnapshotOperationNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode PREVIOUS_SNAPSHOT_OPERATION_NOT_SUPPORTED = fromString("PreviousSnapshotOperationNotSupported"); + + /** + * Static value SequenceNumberConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode SEQUENCE_NUMBER_CONDITION_NOT_MET = fromString("SequenceNumberConditionNotMet"); + + /** + * Static value SequenceNumberIncrementTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode SEQUENCE_NUMBER_INCREMENT_TOO_LARGE = fromString("SequenceNumberIncrementTooLarge"); + + /** + * Static value SnapshotCountExceeded for StorageErrorCode. + */ + public static final StorageErrorCode SNAPSHOT_COUNT_EXCEEDED = fromString("SnapshotCountExceeded"); + + /** + * Static value SnaphotOperationRateExceeded for StorageErrorCode. + */ + public static final StorageErrorCode SNAPHOT_OPERATION_RATE_EXCEEDED = fromString("SnaphotOperationRateExceeded"); + + /** + * Static value SnapshotsPresent for StorageErrorCode. + */ + public static final StorageErrorCode SNAPSHOTS_PRESENT = fromString("SnapshotsPresent"); + + /** + * Static value SourceConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode SOURCE_CONDITION_NOT_MET = fromString("SourceConditionNotMet"); + + /** + * Static value SystemInUse for StorageErrorCode. + */ + public static final StorageErrorCode SYSTEM_IN_USE = fromString("SystemInUse"); + + /** + * Static value TargetConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode TARGET_CONDITION_NOT_MET = fromString("TargetConditionNotMet"); + + /** + * Static value UnauthorizedBlobOverwrite for StorageErrorCode. + */ + public static final StorageErrorCode UNAUTHORIZED_BLOB_OVERWRITE = fromString("UnauthorizedBlobOverwrite"); + + /** + * Static value BlobBeingRehydrated for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_BEING_REHYDRATED = fromString("BlobBeingRehydrated"); + + /** + * Static value BlobArchived for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_ARCHIVED = fromString("BlobArchived"); + + /** + * Static value BlobNotArchived for StorageErrorCode. + */ + public static final StorageErrorCode BLOB_NOT_ARCHIVED = fromString("BlobNotArchived"); + + /** + * Creates or finds a StorageErrorCode from its string representation. + * + * @param name a name to look for. + * @return the corresponding StorageErrorCode. + */ + @JsonCreator + public static StorageErrorCode fromString(String name) { + return fromString(name, StorageErrorCode.class); + } + + /** + * @return known StorageErrorCode values. + */ + public static Collection values() { + return values(StorageErrorCode.class); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorException.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorException.java new file mode 100644 index 0000000000000..11303394c211e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageErrorException.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; + +/** + * Exception thrown for an invalid response with StorageError information. + */ +public final class StorageErrorException extends HttpResponseException { + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + */ + public StorageErrorException(String message, HttpResponse response) { + super(message, response); + } + + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + * @param value the deserialized response value. + */ + public StorageErrorException(String message, HttpResponse response, StorageError value) { + super(message, response, value); + } + + @Override + public StorageError value() { + return (StorageError) super.value(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceProperties.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceProperties.java new file mode 100644 index 0000000000000..79e072ba2b059 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceProperties.java @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Storage Service Properties. + */ +@JacksonXmlRootElement(localName = "StorageServiceProperties") +public final class StorageServiceProperties { + /* + * The logging property. + */ + @JsonProperty(value = "Logging") + private Logging logging; + + /* + * The hourMetrics property. + */ + @JsonProperty(value = "HourMetrics") + private Metrics hourMetrics; + + /* + * The minuteMetrics property. + */ + @JsonProperty(value = "MinuteMetrics") + private Metrics minuteMetrics; + + private static final class CorsWrapper { + @JacksonXmlProperty(localName = "CorsRule") + private final List items; + + @JsonCreator + private CorsWrapper(@JacksonXmlProperty(localName = "CorsRule") List items) { + this.items = items; + } + } + + /* + * The set of CORS rules. + */ + @JsonProperty(value = "Cors") + private CorsWrapper cors; + + /* + * The default version to use for requests to the Blob service if an + * incoming request's version is not specified. Possible values include + * version 2008-10-27 and all more recent versions + */ + @JsonProperty(value = "DefaultServiceVersion") + private String defaultServiceVersion; + + /* + * The deleteRetentionPolicy property. + */ + @JsonProperty(value = "DeleteRetentionPolicy") + private RetentionPolicy deleteRetentionPolicy; + + /* + * The staticWebsite property. + */ + @JsonProperty(value = "StaticWebsite") + private StaticWebsite staticWebsite; + + /** + * Get the logging property: The logging property. + * + * @return the logging value. + */ + public Logging logging() { + return this.logging; + } + + /** + * Set the logging property: The logging property. + * + * @param logging the logging value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties logging(Logging logging) { + this.logging = logging; + return this; + } + + /** + * Get the hourMetrics property: The hourMetrics property. + * + * @return the hourMetrics value. + */ + public Metrics hourMetrics() { + return this.hourMetrics; + } + + /** + * Set the hourMetrics property: The hourMetrics property. + * + * @param hourMetrics the hourMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties hourMetrics(Metrics hourMetrics) { + this.hourMetrics = hourMetrics; + return this; + } + + /** + * Get the minuteMetrics property: The minuteMetrics property. + * + * @return the minuteMetrics value. + */ + public Metrics minuteMetrics() { + return this.minuteMetrics; + } + + /** + * Set the minuteMetrics property: The minuteMetrics property. + * + * @param minuteMetrics the minuteMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties minuteMetrics(Metrics minuteMetrics) { + this.minuteMetrics = minuteMetrics; + return this; + } + + /** + * Get the cors property: The set of CORS rules. + * + * @return the cors value. + */ + public List cors() { + if (this.cors == null) { + this.cors = new CorsWrapper(new ArrayList()); + } + return this.cors.items; + } + + /** + * Set the cors property: The set of CORS rules. + * + * @param cors the cors value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties cors(List cors) { + this.cors = new CorsWrapper(cors); + return this; + } + + /** + * Get the defaultServiceVersion property: The default version to use for + * requests to the Blob service if an incoming request's version is not + * specified. Possible values include version 2008-10-27 and all more + * recent versions. + * + * @return the defaultServiceVersion value. + */ + public String defaultServiceVersion() { + return this.defaultServiceVersion; + } + + /** + * Set the defaultServiceVersion property: The default version to use for + * requests to the Blob service if an incoming request's version is not + * specified. Possible values include version 2008-10-27 and all more + * recent versions. + * + * @param defaultServiceVersion the defaultServiceVersion value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties defaultServiceVersion(String defaultServiceVersion) { + this.defaultServiceVersion = defaultServiceVersion; + return this; + } + + /** + * Get the deleteRetentionPolicy property: The deleteRetentionPolicy + * property. + * + * @return the deleteRetentionPolicy value. + */ + public RetentionPolicy deleteRetentionPolicy() { + return this.deleteRetentionPolicy; + } + + /** + * Set the deleteRetentionPolicy property: The deleteRetentionPolicy + * property. + * + * @param deleteRetentionPolicy the deleteRetentionPolicy value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties deleteRetentionPolicy(RetentionPolicy deleteRetentionPolicy) { + this.deleteRetentionPolicy = deleteRetentionPolicy; + return this; + } + + /** + * Get the staticWebsite property: The staticWebsite property. + * + * @return the staticWebsite value. + */ + public StaticWebsite staticWebsite() { + return this.staticWebsite; + } + + /** + * Set the staticWebsite property: The staticWebsite property. + * + * @param staticWebsite the staticWebsite value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties staticWebsite(StaticWebsite staticWebsite) { + this.staticWebsite = staticWebsite; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceStats.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceStats.java new file mode 100644 index 0000000000000..5eb67c3230645 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/StorageServiceStats.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Stats for the storage service. + */ +@JacksonXmlRootElement(localName = "StorageServiceStats") +public final class StorageServiceStats { + /* + * The geoReplication property. + */ + @JsonProperty(value = "GeoReplication") + private GeoReplication geoReplication; + + /** + * Get the geoReplication property: The geoReplication property. + * + * @return the geoReplication value. + */ + public GeoReplication geoReplication() { + return this.geoReplication; + } + + /** + * Set the geoReplication property: The geoReplication property. + * + * @param geoReplication the geoReplication value to set. + * @return the StorageServiceStats object itself. + */ + public StorageServiceStats geoReplication(GeoReplication geoReplication) { + this.geoReplication = geoReplication; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/SyncCopyStatusType.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SyncCopyStatusType.java new file mode 100644 index 0000000000000..74f8890fcb3b2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/SyncCopyStatusType.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for SyncCopyStatusType. + */ +public enum SyncCopyStatusType { + /** + * Enum value success. + */ + SUCCESS("success"); + + /** + * The actual serialized value for a SyncCopyStatusType instance. + */ + private final String value; + + SyncCopyStatusType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a SyncCopyStatusType instance. + * + * @param value the serialized value to parse. + * @return the parsed SyncCopyStatusType object, or null if unable to parse. + */ + @JsonCreator + public static SyncCopyStatusType fromString(String value) { + SyncCopyStatusType[] items = SyncCopyStatusType.values(); + for (SyncCopyStatusType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/UserDelegationKey.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/UserDelegationKey.java new file mode 100644 index 0000000000000..d267df92d7c29 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/UserDelegationKey.java @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.blob.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * A user delegation key. + */ +@JacksonXmlRootElement(localName = "UserDelegationKey") +public final class UserDelegationKey { + /* + * The Azure Active Directory object ID in GUID format. + */ + @JsonProperty(value = "SignedOid", required = true) + private String signedOid; + + /* + * The Azure Active Directory tenant ID in GUID format + */ + @JsonProperty(value = "SignedTid", required = true) + private String signedTid; + + /* + * The date-time the key is active + */ + @JsonProperty(value = "SignedStart", required = true) + private OffsetDateTime signedStart; + + /* + * The date-time the key expires + */ + @JsonProperty(value = "SignedExpiry", required = true) + private OffsetDateTime signedExpiry; + + /* + * Abbreviation of the Azure Storage service that accepts the key + */ + @JsonProperty(value = "SignedService", required = true) + private String signedService; + + /* + * The service version that created the key + */ + @JsonProperty(value = "SignedVersion", required = true) + private String signedVersion; + + /* + * The key as a base64 string + */ + @JsonProperty(value = "Value", required = true) + private String value; + + /** + * Get the signedOid property: The Azure Active Directory object ID in GUID + * format. + * + * @return the signedOid value. + */ + public String signedOid() { + return this.signedOid; + } + + /** + * Set the signedOid property: The Azure Active Directory object ID in GUID + * format. + * + * @param signedOid the signedOid value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedOid(String signedOid) { + this.signedOid = signedOid; + return this; + } + + /** + * Get the signedTid property: The Azure Active Directory tenant ID in GUID + * format. + * + * @return the signedTid value. + */ + public String signedTid() { + return this.signedTid; + } + + /** + * Set the signedTid property: The Azure Active Directory tenant ID in GUID + * format. + * + * @param signedTid the signedTid value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedTid(String signedTid) { + this.signedTid = signedTid; + return this; + } + + /** + * Get the signedStart property: The date-time the key is active. + * + * @return the signedStart value. + */ + public OffsetDateTime signedStart() { + return this.signedStart; + } + + /** + * Set the signedStart property: The date-time the key is active. + * + * @param signedStart the signedStart value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedStart(OffsetDateTime signedStart) { + this.signedStart = signedStart; + return this; + } + + /** + * Get the signedExpiry property: The date-time the key expires. + * + * @return the signedExpiry value. + */ + public OffsetDateTime signedExpiry() { + return this.signedExpiry; + } + + /** + * Set the signedExpiry property: The date-time the key expires. + * + * @param signedExpiry the signedExpiry value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedExpiry(OffsetDateTime signedExpiry) { + this.signedExpiry = signedExpiry; + return this; + } + + /** + * Get the signedService property: Abbreviation of the Azure Storage + * service that accepts the key. + * + * @return the signedService value. + */ + public String signedService() { + return this.signedService; + } + + /** + * Set the signedService property: Abbreviation of the Azure Storage + * service that accepts the key. + * + * @param signedService the signedService value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedService(String signedService) { + this.signedService = signedService; + return this; + } + + /** + * Get the signedVersion property: The service version that created the + * key. + * + * @return the signedVersion value. + */ + public String signedVersion() { + return this.signedVersion; + } + + /** + * Set the signedVersion property: The service version that created the + * key. + * + * @param signedVersion the signedVersion value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey signedVersion(String signedVersion) { + this.signedVersion = signedVersion; + return this; + } + + /** + * Get the value property: The key as a base64 string. + * + * @return the value value. + */ + public String value() { + return this.value; + } + + /** + * Set the value property: The key as a base64 string. + * + * @param value the value value to set. + * @return the UserDelegationKey object itself. + */ + public UserDelegationKey value(String value) { + this.value = value; + return this; + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/models/package-info.java b/storage/client/blob/src/main/java/com/azure/storage/blob/models/package-info.java new file mode 100644 index 0000000000000..653e8a46d1d67 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/models/package-info.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the data models for AzureBlobStorage. + */ +package com.azure.storage.blob.models; diff --git a/storage/client/blob/src/main/java/com/azure/storage/blob/package-info.java b/storage/client/blob/src/main/java/com/azure/storage/blob/package-info.java new file mode 100644 index 0000000000000..77e28d3d565ae --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/blob/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator + +/** + * This package contains the classes for StorageClient. + * Storage Client. + */ +package com.azure.storage.blob; diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java new file mode 100644 index 0000000000000..fe93273e3f64e --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; + +import java.util.HashMap; + +/** + * Holds a SAS token used for authenticating requests. + */ +public final class SASTokenCredential { + // Required SAS token pieces + private static final String SIGNED_VERSION = "sv"; + private static final String SIGNED_SERVICES = "ss"; + private static final String SIGNED_RESOURCE_TYPES = "srt"; + private static final String SIGNED_PERMISSIONS = "sp"; + private static final String SIGNED_EXPIRY = "se"; + private static final String SIGNATURE = "sig"; + + // Optional SAS token pieces + private static final String SIGNED_START = "st"; + private static final String SIGNED_PROTOCOL = "spr"; + private static final String SIGNED_IP = "sip"; + + private final String sasToken; + + /** + * Creates a SAS token credential from the passed SAS token. + * @param sasToken SAS token used to authenticate requests with the service. + */ + public SASTokenCredential(String sasToken) { + this.sasToken = sasToken; + } + + /** + * @return the SAS token + */ + public String sasToken() { + return sasToken; + } + + /** + * Creates a SAS token credential from the passed URL query string + * @param query URL query used to build the SAS token + * @return a SAS token credential if the query param contains all the necessary pieces + */ + public static SASTokenCredential fromQuery(String query) { + if (ImplUtils.isNullOrEmpty(query)) { + return null; + } + + HashMap queryParams = new HashMap<>(); + for (String queryParam : query.split("&")) { + String key = queryParam.split("=", 2)[0]; + queryParams.put(key, queryParam); + } + + if (queryParams.size() < 6 + || !queryParams.containsKey(SIGNED_VERSION) + || !queryParams.containsKey(SIGNED_SERVICES) + || !queryParams.containsKey(SIGNED_RESOURCE_TYPES) + || !queryParams.containsKey(SIGNED_PERMISSIONS) + || !queryParams.containsKey(SIGNED_EXPIRY) + || !queryParams.containsKey(SIGNATURE)) { + return null; + } + + StringBuilder sasTokenBuilder = new StringBuilder(queryParams.get(SIGNED_VERSION)) + .append("&").append(queryParams.get(SIGNED_SERVICES)) + .append("&").append(queryParams.get(SIGNED_RESOURCE_TYPES)) + .append("&").append(queryParams.get(SIGNED_PERMISSIONS)); + + // SIGNED_START is optional + if (queryParams.containsKey(SIGNED_START)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_START)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_EXPIRY)); + + // SIGNED_IP is optional + if (queryParams.containsKey(SIGNED_IP)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_IP)); + } + + // SIGNED_PROTOCOL is optional + if (queryParams.containsKey(SIGNED_PROTOCOL)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_PROTOCOL)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNATURE)); + + return new SASTokenCredential(sasTokenBuilder.toString()); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java new file mode 100644 index 0000000000000..2f2b0111a91e6 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; +import io.netty.handler.codec.http.QueryStringDecoder; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * SharedKey credential policy that is put into a header to authorize requests. + */ +public final class SharedKeyCredential { + private static final String AUTHORIZATION_HEADER_FORMAT = "SharedKey %s:%s"; + + // Pieces of the connection string that are needed. + private static final String ACCOUNT_NAME = "accountname"; + private static final String ACCOUNT_KEY = "accountkey"; + + private final String accountName; + private final byte[] accountKey; + + /** + * Initializes a new instance of SharedKeyCredential contains an account's name and its primary or secondary + * accountKey. + * + * @param accountName The account name associated with the request. + * @param accountKey The account access key used to authenticate the request. + */ + public SharedKeyCredential(String accountName, String accountKey) { + Objects.requireNonNull(accountName); + Objects.requireNonNull(accountKey); + this.accountName = accountName; + this.accountKey = Base64.getDecoder().decode(accountKey); + } + + /** + * Creates a SharedKey credential from the passed connection string. + * @param connectionString Connection string used to build the SharedKey credential. + * @return a SharedKey credential if the connection string contains AccountName and AccountKey + * @throws IllegalArgumentException If {@code connectionString} doesn't have AccountName or AccountKey. + */ + public static SharedKeyCredential fromConnectionString(String connectionString) { + HashMap connectionStringPieces = new HashMap<>(); + for (String connectionStringPiece : connectionString.split(";")) { + String[] kvp = connectionStringPiece.split("=", 2); + connectionStringPieces.put(kvp[0].toLowerCase(Locale.ROOT), kvp[1]); + } + + String accountName = connectionStringPieces.get(ACCOUNT_NAME); + String accountKey = connectionStringPieces.get(ACCOUNT_KEY); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + return new SharedKeyCredential(accountName, accountKey); + } + + /** + * Gets the account name associated with the request. + * + * @return The account name. + */ + public String accountName() { + return accountName; + } + + /** + * Generates the SharedKey Authorization value from information in the request. + * @param requestURL URL of the request + * @param httpMethod HTTP method being used + * @param headers Headers on the request + * @return the SharedKey authorization value + */ + public String generateAuthorizationHeader(URL requestURL, String httpMethod, Map headers) { + return computeHMACSHA256(buildStringToSign(requestURL, httpMethod, headers)); + } + + /** + * Computes a signature for the specified string using the HMAC-SHA256 algorithm. + * Package-private because it is used to generate SAS signatures. + * + * @param stringToSign The UTF-8-encoded string to sign. + * @return A {@code String} that contains the HMAC-SHA256-encoded signature. + * @throws InvalidKeyException If the accountKey is not a valid Base64-encoded string. + * @throws RuntimeException If the {@code HmacSHA256} algorithm isn't supported. + */ + public String computeHmac256(final String stringToSign) throws InvalidKeyException { + try { + /* + We must get a new instance of the Mac calculator for each signature calculated because the instances are + not threadsafe and there is some suggestion online that they may not even be safe for reuse, so we use a + new one each time to be sure. + */ + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(this.accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + return Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + private String buildStringToSign(URL requestURL, String httpMethod, Map headers) { + String contentLength = headers.get("Content-Length"); + contentLength = contentLength.equals("0") ? "" : contentLength; + + // If the x-ms-header exists ignore the Date header + String dateHeader = (headers.containsKey("x-ms-date")) ? "" : getStandardHeaderValue(headers, "Date"); + + return String.join("\n", + httpMethod, + getStandardHeaderValue(headers, "Content-Encoding"), + getStandardHeaderValue(headers, "Content-Language"), + contentLength, + getStandardHeaderValue(headers, "Content-MD5"), + getStandardHeaderValue(headers, "Content-Type"), + dateHeader, + getStandardHeaderValue(headers, "If-Modified-Since"), + getStandardHeaderValue(headers, "If-Match"), + getStandardHeaderValue(headers, "If-None-Match"), + getStandardHeaderValue(headers, "If-Unmodified-Since"), + getStandardHeaderValue(headers, "Range"), + getAdditionalXmsHeaders(headers), + getCanonicalizedResource(requestURL)); + } + + /* + * Returns an empty string if the header value is null or empty. + */ + private String getStandardHeaderValue(Map headers, String headerName) { + final String headerValue = headers.get(headerName); + + return headerValue == null ? "" : headerValue; + } + + private String getAdditionalXmsHeaders(Map headers) { + // Add only headers that begin with 'x-ms-' + final List xmsHeaderNameArray = headers.entrySet().stream() + .filter(entry -> entry.getKey().toLowerCase(Locale.ROOT).startsWith("x-ms-")) + .filter(entry -> entry.getValue() != null) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + if (xmsHeaderNameArray.isEmpty()) { + return ""; + } + + Collections.sort(xmsHeaderNameArray); + + final StringBuilder canonicalizedHeaders = new StringBuilder(); + for (final String key : xmsHeaderNameArray) { + if (canonicalizedHeaders.length() > 0) { + canonicalizedHeaders.append('\n'); + } + + canonicalizedHeaders.append(key) + .append(':') + .append(headers.get(key)); + } + + return canonicalizedHeaders.toString(); + } + + private String getCanonicalizedResource(URL requestURL) { + + // Resource path + final StringBuilder canonicalizedResource = new StringBuilder("/"); + canonicalizedResource.append(accountName); + + // Note that AbsolutePath starts with a '/'. + if (requestURL.getPath().length() > 0) { + canonicalizedResource.append(requestURL.getPath()); + } else { + canonicalizedResource.append('/'); + } + + // check for no query params and return + if (requestURL.getQuery() == null) { + return canonicalizedResource.toString(); + } + + // The URL object's query field doesn't include the '?'. The QueryStringDecoder expects it. + QueryStringDecoder queryDecoder = new QueryStringDecoder("?" + requestURL.getQuery()); + Map> queryParams = queryDecoder.parameters(); + + ArrayList queryParamNames = new ArrayList<>(queryParams.keySet()); + Collections.sort(queryParamNames); + + for (String queryParamName : queryParamNames) { + final List queryParamValues = queryParams.get(queryParamName); + Collections.sort(queryParamValues); + String queryParamValuesStr = String.join(",", queryParamValues); + canonicalizedResource.append("\n") + .append(queryParamName.toLowerCase(Locale.ROOT)) + .append(":") + .append(queryParamValuesStr); + } + + // append to main string builder the join of completed params with new line + return canonicalizedResource.toString(); + } + + private String computeHMACSHA256(String stringToSign) { + try { + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + String signature = Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + return String.format(AUTHORIZATION_HEADER_FORMAT, accountName, signature); + } catch (NoSuchAlgorithmException | InvalidKeyException ex) { + throw new Error(ex); + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/credentials/package-info.java b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/package-info.java new file mode 100644 index 0000000000000..b03314b4cc0b0 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/credentials/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains credentials used by Azure Storage services. + */ +package com.azure.storage.common.credentials; diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java new file mode 100644 index 0000000000000..80b157bff4716 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import java.util.concurrent.TimeUnit; + +/** + * Options for configuring the {@link RequestRetryPolicy}. Please refer to the Factory for more information. Note + * that there is no option for overall operation timeout. This is because Rx object have a timeout field which provides + * this functionality. + */ +public final class RequestRetryOptions { + + private final int maxTries; + private final int tryTimeout; + private final long retryDelayInMs; + private final long maxRetryDelayInMs; + /** + * A {@link RetryPolicyType} telling the pipeline what kind of retry policy to use. + */ + private RetryPolicyType retryPolicyType; + private String secondaryHost; + + /** + * Constructor with default retry values: Exponential backoff, maxTries=4, tryTimeout=30, retryDelayInMs=4000, + * maxRetryDelayInMs=120000, secondaryHost=null. + */ + public RequestRetryOptions() { + this(RetryPolicyType.EXPONENTIAL, null, + null, null, null, null); + } + + /** + * Configures how the {@link com.azure.core.http.HttpPipeline} should retry requests. + * + * @param retryPolicyType + * A {@link RetryPolicyType} specifying the type of retry pattern to use. A value of {@code null} accepts + * the default. + * @param maxTries + * Specifies the maximum number of attempts an operation will be tried before producing an error. A value of + * {@code null} means that you accept our default policy. A value of 1 means 1 try and no retries. + * @param tryTimeout + * Indicates the maximum time allowed for any single try of an HTTP request. A value of {@code null} means + * that you accept our default. NOTE: When transferring large amounts of data, the default TryTimeout will + * probably not be sufficient. You should override this value based on the bandwidth available to the host + * machine and proximity to the Storage service. A good starting point may be something like (60 seconds per + * MB of anticipated-payload-size). + * @param retryDelayInMs + * Specifies the amount of delay to use before retrying an operation. A value of {@code null} means you + * accept the default value. The delay increases (exponentially or linearly) with each retry up to a maximum + * specified by MaxRetryDelay. If you specify {@code null}, then you must also specify {@code null} for + * MaxRetryDelay. + * @param maxRetryDelayInMs + * Specifies the maximum delay allowed before retrying an operation. A value of {@code null} means you + * accept the default value. If you specify {@code null}, then you must also specify {@code null} for + * RetryDelay. + * @param secondaryHost + * If a secondaryHost is specified, retries will be tried against this host. If secondaryHost is + * {@code null} (the default) then operations are not retried against another host. NOTE: Before setting + * this field, make sure you understand the issues around reading stale and potentially-inconsistent data at + * this webpage + * @throws IllegalArgumentException If {@code retryDelayInMs} and {@code maxRetryDelayInMs} are not both null or non-null + * or {@code retryPolicyType} isn't {@link RetryPolicyType#EXPONENTIAL} or {@link RetryPolicyType#FIXED}. + * + *

    Sample Code

    + * + *

    For more samples, please see the samples file

    + */ + public RequestRetryOptions(RetryPolicyType retryPolicyType, Integer maxTries, Integer tryTimeout, + Long retryDelayInMs, Long maxRetryDelayInMs, String secondaryHost) { + this.retryPolicyType = retryPolicyType == null ? RetryPolicyType.EXPONENTIAL : retryPolicyType; + if (maxTries != null) { + assertInBounds("maxRetries", maxTries, 1, Integer.MAX_VALUE); + this.maxTries = maxTries; + } else { + this.maxTries = 4; + } + + if (tryTimeout != null) { + assertInBounds("tryTimeout", tryTimeout, 1, Integer.MAX_VALUE); + this.tryTimeout = tryTimeout; + } else { + this.tryTimeout = 60; + } + + if ((retryDelayInMs == null && maxRetryDelayInMs != null) + || (retryDelayInMs != null && maxRetryDelayInMs == null)) { + throw new IllegalArgumentException("Both retryDelay and maxRetryDelay must be null or neither can be null"); + } + + if (retryDelayInMs != null && maxRetryDelayInMs != null) { + assertInBounds("maxRetryDelayInMs", maxRetryDelayInMs, 1, Long.MAX_VALUE); + assertInBounds("retryDelayInMs", retryDelayInMs, 1, maxRetryDelayInMs); + this.maxRetryDelayInMs = maxRetryDelayInMs; + this.retryDelayInMs = retryDelayInMs; + } else { + switch (this.retryPolicyType) { + case EXPONENTIAL: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(4); + break; + case FIXED: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(30); + break; + default: + throw new IllegalArgumentException("Unrecognize retry policy type."); + } + this.maxRetryDelayInMs = TimeUnit.SECONDS.toMillis(120); + } + + this.secondaryHost = secondaryHost; + } + + int maxTries() { + return this.maxTries; + } + + int tryTimeout() { + return this.tryTimeout; + } + + String secondaryHost() { + return this.secondaryHost; + } + + long retryDelayInMs() { + return retryDelayInMs; + } + + long maxRetryDelayInMs() { + return maxRetryDelayInMs; + } + + /** + * Calculates how long to delay before sending the next request. + * + * @param tryCount + * An {@code int} indicating which try we are on. + * + * @return A {@code long} value of how many milliseconds to delay. + */ + long calculateDelayInMs(int tryCount) { + long delay = 0; + switch (this.retryPolicyType) { + case EXPONENTIAL: + delay = (pow(2L, tryCount - 1) - 1L) * this.retryDelayInMs; + break; + + case FIXED: + delay = this.retryDelayInMs; + break; + default: + throw new IllegalArgumentException("Invalid retry policy type."); + } + + return Math.min(delay, this.maxRetryDelayInMs); + } + + private long pow(long number, int exponent) { + long result = 1; + for (int i = 0; i < exponent; i++) { + result *= number; + } + + return result; + } + + private static void assertInBounds(final String param, final long value, final long min, final long max) { + if (value < min || value > max) { + throw new IllegalArgumentException(String.format("The value of the parameter '%s' should be between %s and %s.", param, min, max)); + } + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java new file mode 100644 index 0000000000000..774a44999ce76 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + + +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.http.UrlBuilder; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.time.Duration; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeoutException; + +/** + * This is a request policy in an {@link com.azure.core.http.HttpPipeline} for retrying a given HTTP request. The request + * that is retried will be identical each time it is reissued. Retries will try against a secondary if one is specified + * and the type of operation/error indicates that the secondary can handle the request. Exponential and fixed backoff are + * supported. The policy must only be used directly when creating a custom pipeline. + */ +public final class RequestRetryPolicy implements HttpPipelinePolicy { + private final RequestRetryOptions requestRetryOptions; + + /** + * Constructs the policy using the retry options. + * + * @param requestRetryOptions Retry options for the policy. + */ + public RequestRetryPolicy(RequestRetryOptions requestRetryOptions) { + this.requestRetryOptions = requestRetryOptions; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + HttpRequest httpRequest = context.httpRequest(); + boolean considerSecondary = (httpRequest.httpMethod().equals(HttpMethod.GET) + || httpRequest.httpMethod().equals(HttpMethod.HEAD)) + && (this.requestRetryOptions.secondaryHost() != null); + + return this.attemptAsync(httpRequest, next, 1, considerSecondary, 1); + } + + /** + * This method actually attempts to send the request and determines if we should attempt again and, if so, how + * long to wait before sending out the next request. + *

    + * Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) When to retry: connection failure + * or an HTTP status code of 500 or greater, except 501 and 505 If using a secondary: Odd tries go against + * primary; even tries go against the secondary For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, + * 1.2) If secondary gets a 404, don't fail, retry but future retries are only against the primary When retrying + * against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2)) + * + * @param httpRequest + * The request to try. + * @param primaryTry + * This indicates how man tries we've attempted against the primary DC. + * @param considerSecondary + * Before each try, we'll select either the primary or secondary URL if appropriate. + * @param attempt + * This indicates the total number of attempts to send the request. + * + * @return A single containing either the successful response or an error that was not retryable because either + * the maxTries was exceeded or retries will not mitigate the issue. + */ + private Mono attemptAsync(final HttpRequest httpRequest, HttpPipelineNextPolicy next, final int primaryTry, + final boolean considerSecondary, + final int attempt) { + + // Determine which endpoint to try. It's primary if there is no secondary or if it is an odd number attempt. + final boolean tryingPrimary = !considerSecondary || (attempt % 2 != 0); + + // Select the correct host and delay. + long delayMs; + if (tryingPrimary) { + // The first attempt returns 0 delay. + delayMs = this.requestRetryOptions.calculateDelayInMs(primaryTry); + } else { + // Delay with some jitter before trying the secondary. + delayMs = (long) ((ThreadLocalRandom.current().nextFloat() / 2 + 0.8) * 1000); // Add jitter + } + + /* + Clone the original request to ensure that each try starts with the original (unmutated) request. We cannot + simply call httpRequest.buffer() because although the body will start emitting from the beginning of the + stream, the buffers that were emitted will have already been consumed (their position set to their limit), + so it is not a true reset. By adding the map function, we ensure that anything which consumes the + ByteBuffers downstream will only actually consume a duplicate so the original is preserved. This only + duplicates the ByteBuffer object, not the underlying data. + */ + Flux bufferedBody = httpRequest.body() == null + ? null : httpRequest.body().map(ByteBuf::duplicate); + httpRequest.body(bufferedBody); + if (!tryingPrimary) { + UrlBuilder builder = UrlBuilder.parse(httpRequest.url()); + builder.host(this.requestRetryOptions.secondaryHost()); + try { + httpRequest.url(builder.toURL()); + } catch (MalformedURLException e) { + return Mono.error(e); + } + } + + /* + We want to send the request with a given timeout, but we don't want to kickoff that timeout-bound operation + until after the retry backoff delay, so we call delaySubscription. + */ + return next.clone().process() + .timeout(Duration.ofSeconds(this.requestRetryOptions.tryTimeout())) + .delaySubscription(Duration.ofMillis(delayMs)) + .flatMap(response -> { + boolean newConsiderSecondary = considerSecondary; + String action; + int statusCode = response.statusCode(); + + /* + If attempt was against the secondary & it returned a StatusNotFound (404), then the + resource was not found. This may be due to replication delay. So, in this case, + we'll never try the secondary again for this operation. + */ + if (!tryingPrimary && statusCode == 404) { + newConsiderSecondary = false; + action = "Retry: Secondary URL returned 404"; + } else if (statusCode == 503 || statusCode == 500) { + action = "Retry: Temporary error or server timeout"; + } else { + action = "NoRetry: Successful HTTP request"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, newConsiderSecondary, + attempt + 1); + } + return Mono.just(response); + }) + .onErrorResume(throwable -> { + /* + It is likely that many users will not realize that their Flux must be replayable and + get an error upon retries when the provided data length does not match the length of the exact + data. We cannot enforce the desired Flux behavior, so we provide a hint when this is likely + the root cause. + */ + if (throwable instanceof IllegalStateException && attempt > 1) { + return Mono.error(new IllegalStateException("The request failed because the " + + "size of the contents of the provided Flux did not match the provided " + + "data size upon attempting to retry. This is likely caused by the Flux " + + "not being replayable. To support retries, all Fluxes must produce the " + + "same data for each subscriber. Please ensure this behavior.", throwable)); + } + + /* + IOException is a catch-all for IO related errors. Technically it includes many types which may + not be network exceptions, but we should not hit those unless there is a bug in our logic. In + either case, it is better to optimistically retry instead of failing too soon. + A Timeout Exception is a client-side timeout coming from Rx. + */ + String action; + if (throwable instanceof IOException) { + action = "Retry: Network error"; + } else if (throwable instanceof TimeoutException) { + action = "Retry: Client timeout"; + } else { + action = "NoRetry: Unknown error"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, considerSecondary, + attempt + 1); + } + return Mono.error(throwable); + }); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java new file mode 100644 index 0000000000000..bee125775e55d --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +/** + * This type holds possible options for retry backoff algorithms. They may be used with {@link RequestRetryOptions}. + */ +public enum RetryPolicyType { + /** + * Tells the pipeline to use an exponential back-off retry policy. + */ + EXPONENTIAL, + + /** + * Tells the pipeline to use a fixed back-off retry policy. + */ + FIXED +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java new file mode 100644 index 0000000000000..ba2debfcd3620 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.storage.common.credentials.SASTokenCredential; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Policy that adds the SAS token to the request URL's query. + */ +public final class SASTokenCredentialPolicy implements HttpPipelinePolicy { + private final SASTokenCredential credential; + + /** + * Creates a SAS token credential policy that appends the SAS token to the request URL's query. + * @param credential SAS token credential + */ + public SASTokenCredentialPolicy(SASTokenCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + try { + URL requestURL = context.httpRequest().url(); + String delimiter = !ImplUtils.isNullOrEmpty(requestURL.getQuery()) ? "&" : "?"; + + String newURL = requestURL.toString() + delimiter + credential.sasToken(); + context.httpRequest().url(new URL(newURL)); + } catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + + return next.process(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java new file mode 100644 index 0000000000000..8ee1284591dd2 --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.storage.common.credentials.SharedKeyCredential; +import reactor.core.publisher.Mono; + +/** + * Policy that adds the SharedKey into the request's Authorization header. + */ +public final class SharedKeyCredentialPolicy implements HttpPipelinePolicy { + private final SharedKeyCredential credential; + + /** + * Creates a SharedKey pipeline policy that adds the SharedKey into the request's authorization header. + * @param credential the SharedKey credential used to create the policy. + */ + public SharedKeyCredentialPolicy(SharedKeyCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + String authorizationValue = credential.generateAuthorizationHeader(context.httpRequest().url(), + context.httpRequest().httpMethod().toString(), + context.httpRequest().headers().toMap()); + context.httpRequest().header("Authorization", authorizationValue); + return next.process(); + } +} diff --git a/storage/client/blob/src/main/java/com/azure/storage/common/policy/package-info.java b/storage/client/blob/src/main/java/com/azure/storage/common/policy/package-info.java new file mode 100644 index 0000000000000..6f36065ea580b --- /dev/null +++ b/storage/client/blob/src/main/java/com/azure/storage/common/policy/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains policies used by Azure Storage services. + */ +package com.azure.storage.common.policy; diff --git a/storage/client/blob/src/samples/java/AzureIdentityExample.java b/storage/client/blob/src/samples/java/AzureIdentityExample.java new file mode 100644 index 0000000000000..6550c8c02a76d --- /dev/null +++ b/storage/client/blob/src/samples/java/AzureIdentityExample.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.identity.credential.DefaultAzureCredential; +import com.azure.storage.blob.StorageClient; +import com.azure.storage.blob.StorageClientBuilder; + +import java.util.Locale; + +/** + * Creates default DefaultAzureCredential instance to use. This will use AZURE_CLIENT_ID, + * AZURE_CLIENT_SECRET, and AZURE_TENANT_ID environment variables to create a + * ClientSecretCredential. + */ +public class AzureIdentityExample { + + /** + * Entry point into the Azure Identity example for Storage blobs. + * @param args Unused. Arguments to the program. + */ + public static void main(String[] args) { + String accountName = SampleHelper.getAccountName(); + + /* + * From the Azure portal, get your Storage account blob service URL endpoint. + * The URL typically looks like this: + */ + String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName); + + /* + * Create a storage client using the Azure Identity credentials. + */ + StorageClient storageClient = new StorageClientBuilder() + .endpoint(endpoint) + .credential(new DefaultAzureCredential()) + .buildClient(); + + System.out.println("Successfully setup client using the Azure Identity, please check the service version: " + + storageClient.getProperties().value().defaultServiceVersion()); + + } +} diff --git a/storage/client/blob/src/samples/java/BasicExample.java b/storage/client/blob/src/samples/java/BasicExample.java new file mode 100644 index 0000000000000..3f8edbd367cb8 --- /dev/null +++ b/storage/client/blob/src/samples/java/BasicExample.java @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.storage.blob.BlockBlobClient; +import com.azure.storage.blob.ContainerClient; +import com.azure.storage.blob.StorageClient; +import com.azure.storage.blob.StorageClientBuilder; +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Locale; + +/** + * This example shows how to start using the Azure Storage Blob SDK for Java. + */ +public class BasicExample { + + /** + * Entry point into the basic examples for Storage blobs. + * @param args Unused. Arguments to the program. + * @throws IOException If an I/O error occurs + * @throws RuntimeException If the downloaded data doesn't match the uploaded data + */ + public static void main(String[] args) throws IOException { + + /* + * From the Azure portal, get your Storage account's name and account key. + */ + String accountName = SampleHelper.getAccountName(); + String accountKey = SampleHelper.getAccountKey(); + + /* + * Use your Storage account's name and key to create a credential object; this is used to access your account. + */ + SharedKeyCredential credential = new SharedKeyCredential(accountName, accountKey); + + /* + * From the Azure portal, get your Storage account blob service URL endpoint. + * The URL typically looks like this: + */ + String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName); + + /* + * Create a StorageClient object that wraps the service endpoint, credential and a request pipeline. + */ + StorageClient storageClient = new StorageClientBuilder().endpoint(endpoint).credential(credential).buildClient(); + + /* + * This example shows several common operations just to get you started. + */ + + /* + * Create a client that references a to-be-created container in your Azure Storage account. This returns a + * ContainerClient object that wraps the container's endpoint, credential and a request pipeline (inherited from storageClient). + * Note that container names require lowercase. + */ + ContainerClient containerClient = storageClient.getContainerClient("myjavacontainerbasic" + System.currentTimeMillis()); + + /* + * Create a container in Storage blob account. + */ + containerClient.create(); + + /* + * Create a client that references a to-be-created blob in your Azure Storage account's container. + * This returns a BlockBlobClient object that wraps the blob's endpoint, credential and a request pipeline + * (inherited from containerClient). Note that blob names can be mixed case. + */ + BlockBlobClient blobClient = containerClient.getBlockBlobClient("HelloWorld.txt"); + + String data = "Hello world!"; + InputStream dataStream = new ByteArrayInputStream(data.getBytes()); + + /* + * Create the blob with string (plain text) content. + */ + blobClient.upload(dataStream, data.length()); + + dataStream.close(); + + /* + * Download the blob's content to output stream. + */ + int dataSize = (int) blobClient.getProperties().value().blobSize(); + OutputStream outputStream = new ByteArrayOutputStream(dataSize); + blobClient.download(outputStream); + outputStream.close(); + + /* + * Verify that the blob data round-tripped correctly. + */ + if (!data.equals(outputStream.toString())) { + throw new RuntimeException("The downloaded data does not match the uploaded data."); + } + + /* + * Create more blobs before listing. + */ + for (int i = 0; i < 3; i++) { + String sampleData = "Samples"; + InputStream dataInBlobs = new ByteArrayInputStream(sampleData.getBytes(Charset.defaultCharset())); + containerClient.getBlockBlobClient("myblobsforlisting" + System.currentTimeMillis()) + .upload(dataInBlobs, sampleData.length()); + dataInBlobs.close(); + } + + /* + * List the blob(s) in our container. + */ + containerClient.listBlobsFlat() + .forEach(blobItem -> System.out.println("Blob name: " + blobItem.name() + ", Snapshot: " + blobItem.snapshot())); + + /* + * Delete the blob we created earlier. + */ + blobClient.delete(); + + /* + * Delete the container we created earlier. + */ + containerClient.delete(); + } +} diff --git a/storage/client/blob/src/samples/java/FileTransferExample.java b/storage/client/blob/src/samples/java/FileTransferExample.java new file mode 100644 index 0000000000000..ff3b9376bfc50 --- /dev/null +++ b/storage/client/blob/src/samples/java/FileTransferExample.java @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.storage.blob.BlockBlobClient; +import com.azure.storage.blob.ContainerClient; +import com.azure.storage.blob.StorageClient; +import com.azure.storage.blob.StorageClientBuilder; +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Locale; + +/** + * This class shows how to upload the file as fast as possible in parallel using the optimized upload API. + */ +public class FileTransferExample { + private static final String LARGE_TEST_FOLDER = "test-large-files/"; + + /** + * Entry point into the file transfer examples for Storage blobs. + * @param args Unused. Arguments to the program. + * @throws IOException If an I/O error occurs + * @throws NoSuchAlgorithmException If {@code MD5} isn't supported + * @throws RuntimeException If the uploaded or downloaded file wasn't found + */ + public static void main(String[] args) throws IOException, NoSuchAlgorithmException { + + /* + * From the Azure portal, get your Storage account's name and account key. + */ + String accountName = SampleHelper.getAccountName(); + String accountKey = SampleHelper.getAccountKey(); + + /* + * Use your Storage account's name and key to create a credential object; this is used to access your account. + */ + SharedKeyCredential credential = new SharedKeyCredential(accountName, accountKey); + + /* + * From the Azure portal, get your Storage account blob service URL endpoint. + * The URL typically looks like this: + */ + String endPoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName); + + /* + * Create a StorageClient object that wraps the service endpoint, credential and a request pipeline. + * Now you can use the storageClient to perform various container and blob operations. + */ + StorageClient storageClient = new StorageClientBuilder().endpoint(endPoint).credential(credential).buildClient(); + + + /* + * This example shows several common operations just to get you started. + */ + + + /* + * Create a client that references a to-be-created container in your Azure Storage account. This returns a + * ContainerClient uses the same endpoint, credential and pipeline from storageClient. + * Note that container names require lowercase. + */ + ContainerClient containerClient = storageClient.getContainerClient("myjavacontainerparallelupload" + System.currentTimeMillis()); + + /* + * Create a container in Storage blob account. + */ + containerClient.create(); + + /* + * Create a BlockBlobClient object that wraps a blob's endpoint and a default pipeline, the blockBlobClient give us access to upload the file. + */ + String filename = "BigFile.bin"; + BlockBlobClient blobClient = containerClient.getBlockBlobClient(filename); + + /* + * Create the empty uploadFile and downloadFile. + */ + File largeFile = createTempEmptyFile(filename); + + File downloadFile = createTempEmptyFile("downloadFile.bin"); + + /* + * Generate random things to uploadFile, which makes the file with size of 100MB. + */ + long fileSize = 100 * 1024 * 1024L; + createTempFileWithFileSize(largeFile, fileSize); + + /* + * Upload the large file to storage blob. + */ + blobClient.uploadFromFile(largeFile.getPath()); + + /* + * Download the large file from storage blob to the local downloadFile path. + */ + blobClient.downloadToFile(downloadFile.getPath()); + + /* + * Check the files are same after the round-trip. + */ + if (Files.exists(downloadFile.toPath()) && Files.exists(largeFile.toPath())) { + checkTwoFilesAreTheSame(largeFile, downloadFile); + System.out.println("The file we upload is the same as the one we download."); + } else { + throw new RuntimeException("Did not find the upload or download file."); + } + + /* + * Clean up the local files and storage container. + */ + containerClient.delete(); + Files.deleteIfExists(largeFile.toPath()); + Files.deleteIfExists(downloadFile.toPath()); + } + + private static File createTempEmptyFile(String fileName) throws IOException { + URL folderUrl = FileTransferExample.class.getClassLoader().getResource("."); + + File dirPath = new File(folderUrl.getPath() + LARGE_TEST_FOLDER); + + if (dirPath.exists() || dirPath.mkdir()) { + File f = new File(folderUrl.getPath() + LARGE_TEST_FOLDER + fileName); + if (!f.exists()) { + f.createNewFile(); + } + return f; + } else { + throw new RuntimeException("Failed to create the large file dir."); + } + } + + private static void createTempFileWithFileSize(File f, long size) throws FileNotFoundException, IOException { + RandomAccessFile raf = new RandomAccessFile(f, "rw"); + raf.setLength(size); + raf.close(); + } + + private static void checkTwoFilesAreTheSame(File f1, File f2) throws IOException, NoSuchAlgorithmException { + String checksumUpload = getFileChecksum(f1); + String checksumDownload = getFileChecksum(f2); + if (checksumUpload.equals(checksumDownload)) { + throw new RuntimeException("The file upload does not match the file download."); + } + } + + private static String getFileChecksum(File file) throws IOException, NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance("MD5"); + + try (FileInputStream fis = new FileInputStream(file); FileChannel ch = fis.getChannel()) { + final ByteBuffer buf = ByteBuffer.allocateDirect(8192); + int b = ch.read(buf); + while (b != -1 && b != 0) { + buf.flip(); + final byte[] bytes = new byte[b]; + buf.get(bytes); + md.update(bytes, 0, b); + buf.clear(); + b = ch.read(buf); + } + ch.close(); + fis.close(); + return new String(md.digest()); + } + } + + +} diff --git a/storage/client/blob/src/samples/java/ListContainersExample.java b/storage/client/blob/src/samples/java/ListContainersExample.java new file mode 100644 index 0000000000000..ab8c9b3709bc7 --- /dev/null +++ b/storage/client/blob/src/samples/java/ListContainersExample.java @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.storage.blob.StorageClient; +import com.azure.storage.blob.StorageClientBuilder; +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.util.Locale; + +/** + * This example shows how to list all containers with storage client using the Azure Storage Blob SDK for Java. + */ +public class ListContainersExample { + + /** + * Entry point into the list containers examples for Storage blobs. + * @param args Unused. Arguments to the program. + */ + public static void main(String[] args) { + String accountName = SampleHelper.getAccountName(); + String accountKey = SampleHelper.getAccountKey(); + + /* + * Use your Storage account's name and key to create a credential object; this is used to access your account. + */ + SharedKeyCredential credential = new SharedKeyCredential(accountName, accountKey); + + /* + * From the Azure portal, get your Storage account blob service URL endpoint. + * The URL typically looks like this: + */ + String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName); + + /* + * Create a StorageClient object that wraps the service endpoint, credential and a request pipeline. + */ + StorageClient storageClient = new StorageClientBuilder().endpoint(endpoint).credential(credential).buildClient(); + + /* + * Create 3 different containers from the storageClient. + */ + for (int i = 0; i < 3; i++) { + storageClient.createContainer("mycontainersforlisting" + i + System.currentTimeMillis()); + } + + /* + * List the containers' name under the Azure storage account. + */ + storageClient.listContainers().forEach(containerItem -> { + System.out.println("Container name: " + containerItem.name()); + + /* + * Clean up the containers at the same time. + */ + storageClient.getContainerClient(containerItem.name()).delete(); + }); + } +} diff --git a/storage/client/blob/src/samples/java/SampleHelper.java b/storage/client/blob/src/samples/java/SampleHelper.java new file mode 100644 index 0000000000000..d841413f06bc0 --- /dev/null +++ b/storage/client/blob/src/samples/java/SampleHelper.java @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.core.util.configuration.ConfigurationManager; + +/** + * This is a helper class of frequently used methods for sample codes. + */ +class SampleHelper { + static String getAccountName() { + return ConfigurationManager.getConfiguration().get("PRIMARY_STORAGE_ACCOUNT_NAME"); + } + + static String getAccountKey() { + return ConfigurationManager.getConfiguration().get("PRIMARY_STORAGE_ACCOUNT_KEY"); + } +} diff --git a/storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java b/storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java new file mode 100644 index 0000000000000..6b475499eab2c --- /dev/null +++ b/storage/client/blob/src/samples/java/SetMetadataAndHTTPHeadersExample.java @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.storage.blob.BlockBlobClient; +import com.azure.storage.blob.ContainerClient; +import com.azure.storage.blob.StorageClient; +import com.azure.storage.blob.StorageClientBuilder; +import com.azure.storage.blob.models.BlobHTTPHeaders; +import com.azure.storage.blob.models.Metadata; +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collections; +import java.util.Locale; + +/** + * This example shows how to set metadata for containers and blobs and how to set HTTPHeaders for blobs + * using the Azure Storage Blob SDK for Java. + */ +public class SetMetadataAndHTTPHeadersExample { + + /** + * Entry point into the setting metadata examples for Storage blobs. + * @param args Unused. Arguments to the program. + * @throws IOException If an I/O error occurs + */ + public static void main(String[] args) throws IOException { + String accountName = SampleHelper.getAccountName(); + String accountKey = SampleHelper.getAccountKey(); + + /* + * Use your Storage account's name and key to create a credential object; this is used to access your account. + */ + SharedKeyCredential credential = new SharedKeyCredential(accountName, accountKey); + + /* + * From the Azure portal, get your Storage account blob service URL endpoint. + * The URL typically looks like this: + */ + String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName); + + /* + * Create a StorageClient object that wraps the service endpoint, credential and a request pipeline. + */ + StorageClient storageClient = new StorageClientBuilder().endpoint(endpoint).credential(credential).buildClient(); + + /* + * Create a container client from storageClient. + */ + ContainerClient containerClient = storageClient.getContainerClient("mycontainer" + System.currentTimeMillis()); + + /* + * Setup containerMetadata for container. + */ + Metadata containerMetadata = new Metadata(Collections.singletonMap("mycontainermetadata", "sample")); + + /* + * Create a container with the containerMetadata above. + */ + containerClient.create(containerMetadata, null, null); + + /* + * Create a blob client. + */ + BlockBlobClient blobClient = containerClient.getBlockBlobClient("myblob" + System.currentTimeMillis()); + + /* + * Create a blob with blob's blobMetadata and BlobHttpHeaders. + */ + Metadata blobMetadata = new Metadata(Collections.singletonMap("myblobmetadata", "sample")); + BlobHTTPHeaders blobHTTPHeaders = new BlobHTTPHeaders().blobContentDisposition("attachment") + .blobContentType("text/html; charset=utf-8"); + + /* + * Data which will upload to block blob. + */ + String data = "Hello world!"; + InputStream dataStream = new ByteArrayInputStream(data.getBytes()); + blobClient.upload(dataStream, data.length(), blobHTTPHeaders, blobMetadata, null, null); + + /* + * Clean up the container and blob. + */ + blobClient.delete(); + containerClient.delete(); + } +} diff --git a/storage/client/blob/src/samples/java/StorageErrorHandlingExample.java b/storage/client/blob/src/samples/java/StorageErrorHandlingExample.java new file mode 100644 index 0000000000000..50d4e81d600c0 --- /dev/null +++ b/storage/client/blob/src/samples/java/StorageErrorHandlingExample.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.core.http.HttpResponse; +import com.azure.storage.blob.ContainerClient; +import com.azure.storage.blob.ContainerClientBuilder; +import com.azure.storage.blob.StorageException; +import com.azure.storage.blob.models.StorageErrorCode; + +/** + * This example shows how to handle errors thrown by various XxxURL methods. Any client-side error will be + * propagated unmodified. However, any response from the service with an unexpected status code will be wrapped in a + * StorageException. If the pipeline includes the RequestRetryFactory, which is the default, some of these errors + * will be automatically retried if it makes sense to do so. The StorageException type exposes rich error + * information returned by the service. + */ +public class StorageErrorHandlingExample { + + /** + * Entry point into error handling example for Storage blobs. + * @param args Unused. Arguments to the program. + */ + public static void main(String[] args) { + ContainerClient containerClient = new ContainerClientBuilder().endpoint("https://account.blob.core.windows.net/mycontainer") + .buildClient(); + + try { + + /* + * An error occurred while creating the container. + */ + containerClient.create(); + } catch (StorageException e) { + + /* + * StorageErrorCode defines constants corresponding to all error codes returned by the service. + */ + if (e.errorCode() == StorageErrorCode.RESOURCE_NOT_FOUND) { + + /* + * Log more detailed information. + */ + System.out.println("Extended details: " + e.getMessage()); + + /* + * Examine the raw response. + */ + HttpResponse response = e.response(); + System.out.println("Error creating the container with status code: " + response.statusCode()); + } else if (e.errorCode() == StorageErrorCode.CONTAINER_BEING_DELETED) { + + /* + * Log more detailed information. + */ + System.out.println("Extended details: " + e.getMessage()); + + } else if (e.errorCode() == StorageErrorCode.CONTAINER_ALREADY_EXISTS) { + + /* + * Process the error. + */ + System.out.println("The container url is " + containerClient.toString()); + } + } + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/APISpec.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/APISpec.groovy new file mode 100644 index 0000000000000..c59095e5f66c6 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/APISpec.groovy @@ -0,0 +1,572 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.core.http.* +import com.azure.core.http.policy.HttpLogDetailLevel +import com.azure.core.http.policy.HttpPipelinePolicy +import com.azure.core.http.rest.Response +import com.azure.core.util.Context +import com.azure.core.util.configuration.ConfigurationManager +import com.azure.identity.credential.EnvironmentCredential +import com.azure.storage.blob.BlobProperties +import com.azure.storage.blob.models.* +import com.azure.storage.common.credentials.SharedKeyCredential +import org.junit.Assume +import org.spockframework.lang.ISpecificationContext +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono +import spock.lang.Shared +import spock.lang.Specification + +import java.nio.ByteBuffer +import java.nio.charset.Charset +import java.nio.charset.StandardCharsets +import java.time.OffsetDateTime +import java.util.function.Supplier + +class APISpec extends Specification { + static final String RECORD_MODE = "RECORD" + + @Shared + Integer iterationNo = 0 // Used to generate stable container names for recording tests with multiple iterations. + + Integer entityNo = 0 // Used to generate stable container names for recording tests requiring multiple containers. + + @Shared + ContainerClient cu + + // Fields used for conveniently creating blobs with data. + static final String defaultText = "default" + + static final ByteBuffer defaultData = ByteBuffer.wrap(defaultText.getBytes(StandardCharsets.UTF_8)) + + static final Flux defaultFlux = Flux.just(defaultData) + + static final Supplier defaultInputStream = new Supplier() { + @Override + InputStream get() { + return new ByteArrayInputStream(defaultText.getBytes(StandardCharsets.UTF_8)) + } + } + + static defaultDataSize = defaultData.remaining() + + // If debugging is enabled, recordings cannot run as there can only be one proxy at a time. + static boolean enableDebugging = false + + // Prefixes for blobs and containers + static String containerPrefix = "jtc" // java test container + + static String blobPrefix = "javablob" + + /* + The values below are used to create data-driven tests for access conditions. + */ + static final OffsetDateTime oldDate = OffsetDateTime.now().minusDays(1) + + static final OffsetDateTime newDate = OffsetDateTime.now().plusDays(1) + + /* + Note that this value is only used to check if we are depending on the received etag. This value will not actually + be used. + */ + static final String receivedEtag = "received" + + static final String garbageEtag = "garbage" + + /* + Note that this value is only used to check if we are depending on the received etag. This value will not actually + be used. + */ + static final String receivedLeaseID = "received" + + static final String garbageLeaseID = UUID.randomUUID().toString() + + /* + credential for various kinds of accounts. + */ + @Shared + static SharedKeyCredential primaryCreds + + @Shared + static SharedKeyCredential alternateCreds + + /* + URLs to various kinds of accounts. + */ + StorageClient primaryServiceURL + + @Shared + static StorageClient alternateServiceURL + + @Shared + static StorageClient blobStorageServiceURL + + @Shared + static StorageClient premiumServiceURL + + /* + Constants for testing that the context parameter is properly passed to the pipeline. + */ + static final String defaultContextKey = "Key" + + static final String defaultContextValue = "Value" + + static final Context defaultContext = new Context(defaultContextKey, defaultContextValue) + + static String getTestName(ISpecificationContext ctx) { + return ctx.getCurrentFeature().name.replace(' ', '').toLowerCase() + } + + def generateContainerName() { + generateContainerName(specificationContext, iterationNo, entityNo++) + } + + def generateBlobName() { + generateBlobName(specificationContext, iterationNo, entityNo++) + } + + /** + * This function generates an entity name by concatenating the passed prefix, the name of the test requesting the + * entity name, and some unique suffix. This ensures that the entity name is unique for each test so there are + * no conflicts on the service. If we are not recording, we can just use the time. If we are recording, the suffix + * must always be the same so we can match requests. To solve this, we use the entityNo for how many entities have + * already been created by this test so far. This would sufficiently distinguish entities within a recording, but + * could still yield duplicates on the service for data-driven tests. Therefore, we also add the iteration number + * of the data driven tests. + * + * @param specificationContext + * Used to obtain the name of the test running. + * @param prefix + * Used to group all entities created by these tests under common prefixes. Useful for listing. + * @param iterationNo + * Indicates which iteration of a data-driven test is being executed. + * @param entityNo + * Indicates how man entities have been created by the test so far. This distinguishes multiple containers + * or multiple blobs created by the same test. Only used when dealing with recordings. + * @return + */ + static String generateResourceName(ISpecificationContext specificationContext, String prefix, int iterationNo, + int entityNo) { + String suffix = "" + suffix += System.currentTimeMillis() // For uniqueness between runs. + suffix += entityNo // For easy identification of which call created this resource. + return prefix + getTestName(specificationContext).take(63 - suffix.length() - prefix.length()) + suffix + } + + static int updateIterationNo(ISpecificationContext specificationContext, int iterationNo) { + if (specificationContext.currentIteration.estimatedNumIterations > 1) { + return iterationNo + 1 + } else { + return 0 + } + } + + static String generateContainerName(ISpecificationContext specificationContext, int iterationNo, int entityNo) { + return generateResourceName(specificationContext, containerPrefix, iterationNo, entityNo) + } + + static String generateBlobName(ISpecificationContext specificationContext, int iterationNo, int entityNo) { + return generateResourceName(specificationContext, blobPrefix, iterationNo, entityNo) + } + + static getGenericCreds(String accountType) { + String accountName = ConfigurationManager.getConfiguration().get(accountType + "ACCOUNT_NAME") + String accountKey = ConfigurationManager.getConfiguration().get(accountType + "ACCOUNT_KEY") + + if (accountName == null || accountKey == null) { + System.out.println("Account name or key for the " + accountType + " account was null. Test's requiring " + + "these credential will fail.") + return null + } + return new SharedKeyCredential(accountName, accountKey) + } + + static HttpClient getHttpClient() { + if (enableDebugging) { + return HttpClient.createDefault().proxy(new Supplier() { + @Override + ProxyOptions get() { + return new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8888)) + } + }) + } else { + return HttpClient.createDefault() + } + } + + static StorageClient getGenericServiceURL(SharedKeyCredential creds) { + // TODO: logging? + + return new StorageClientBuilder() + .endpoint("https://" + creds.accountName() + ".blob.core.windows.net") + .httpClient(getHttpClient()) + .httpLogDetailLevel(HttpLogDetailLevel.BODY_AND_HEADERS) + .credential(creds) + .buildClient() + } + + static void cleanupContainers() throws MalformedURLException { + StorageClient serviceURL = new StorageClientBuilder() + .endpoint("http://" + primaryCreds.accountName() + ".blob.core.windows.net") + .credential(primaryCreds) + .buildClient() + // There should not be more than 5000 containers from these tests + for (ContainerItem c : serviceURL.listContainers()) { + ContainerClient containerURL = serviceURL.getContainerClient(c.name()) + if (c.properties().leaseState() == LeaseStateType.LEASED) { + containerURL.breakLease(0, null, null) + } + containerURL.delete() + } + } + + static byte[] getRandomByteArray(int size) { + Random rand = new Random(getRandomSeed()) + byte[] data = new byte[size] + rand.nextBytes(data) + return data + } + + /* + Size must be an int because ByteBuffer sizes can only be an int. Long is not supported. + */ + static ByteBuffer getRandomData(int size) { + return ByteBuffer.wrap(getRandomByteArray(size)) + } + + /* + We only allow int because anything larger than 2GB (which would require a long) is left to stress/perf. + */ + static File getRandomFile(int size) { + File file = File.createTempFile(UUID.randomUUID().toString(), ".txt") + file.deleteOnExit() + FileOutputStream fos = new FileOutputStream(file) + fos.write(getRandomData(size).array()) + fos.close() + return file + } + + static long getRandomSeed() { + return System.currentTimeMillis() + } + + def setupSpec() { + /* + We'll let primary creds throw and crash if there are no credential specified because everything else will fail. + */ + primaryCreds = getGenericCreds("PRIMARY_STORAGE_") + + /* + It's feasible someone wants to test a specific subset of tests, so we'll still attempt to create each of the + ServiceURLs separately. We don't really need to take any action here, as we've already reported to the user, + so we just swallow the exception and let the relevant tests fail later. Perhaps we can add annotations or + something in the future. + */ + try { + alternateCreds = getGenericCreds("SECONDARY_STORAGE_") + alternateServiceURL = getGenericServiceURL(alternateCreds) + } + catch (Exception e) { + } + try { + blobStorageServiceURL = getGenericServiceURL(getGenericCreds("BLOB_STORAGE_")) + } + catch (Exception e) { + } + try { + premiumServiceURL = getGenericServiceURL(getGenericCreds("PREMIUM_STORAGE_")) + } + catch (Exception e) { + } + } + + def cleanupSpec() { + Assume.assumeTrue("The test only runs in Live mode.", getTestMode().equalsIgnoreCase(RECORD_MODE)) + cleanupContainers() + } + + def setup() { + Assume.assumeTrue("The test only runs in Live mode.", getTestMode().equalsIgnoreCase(RECORD_MODE)) + String containerName = generateContainerName() + + primaryServiceURL = getGenericServiceURL(primaryCreds) + cu = primaryServiceURL.getContainerClient(containerName) + cu.create() + } + + def cleanup() { + // TODO: Scrub auth header here? + iterationNo = updateIterationNo(specificationContext, iterationNo) + } + + /** + * This will retrieve the etag to be used in testing match conditions. The result will typically be assigned to + * the ifMatch condition when testing success and the ifNoneMatch condition when testing failure. + * + * @param bu + * The URL to the blob to get the etag on. + * @param match + * The ETag value for this test. If {@code receivedEtag} is passed, that will signal that the test is expecting + * the blob's actual etag for this test, so it is retrieved. + * @return + * The appropriate etag value to run the current test. + */ + def setupBlobMatchCondition(BlobClient bu, String match) { + if (match == receivedEtag) { + return bu.getProperties().headers().value("ETag") + } else { + return match + } + } + + /** + * This helper method will acquire a lease on a blob to prepare for testing leaseAccessConditions. We want to test + * against a valid lease in both the success and failure cases to guarantee that the results actually indicate + * proper setting of the header. If we pass null, though, we don't want to acquire a lease, as that will interfere + * with other AC tests. + * + * @param bu + * The blob on which to acquire a lease. + * @param leaseID + * The signalID. Values should only ever be {@code receivedLeaseID}, {@code garbageLeaseID}, or {@code null}. + * @return + * The actual leaseAccessConditions of the blob if recievedLeaseID is passed, otherwise whatever was passed will be + * returned. + */ + def setupBlobLeaseCondition(BlobClient bu, String leaseID) { + String responseLeaseId = null + if (leaseID == receivedLeaseID || leaseID == garbageLeaseID) { + responseLeaseId = bu.acquireLease(null, -1, null, null).value() + } + if (leaseID == receivedLeaseID) { + return responseLeaseId + } else { + return leaseID + } + } + + def setupContainerMatchCondition(ContainerClient cu, String match) { + if (match == receivedEtag) { + return cu.getProperties().headers().value("ETag") + } else { + return match + } + } + + def setupContainerLeaseCondition(ContainerClient cu, String leaseID) { + if (leaseID == receivedLeaseID) { + return cu.acquireLease(null, -1).value() + } else { + return leaseID + } + } + + def getMockRequest() { + HttpHeaders headers = new HttpHeaders() + headers.set(Constants.HeaderConstants.CONTENT_ENCODING, "en-US") + URL url = new URL("http://devtest.blob.core.windows.net/test-container/test-blob") + HttpRequest request = new HttpRequest(HttpMethod.POST, url, headers, null) + return request + } + + def waitForCopy(ContainerClient bu, String status) { + OffsetDateTime start = OffsetDateTime.now() + while (status != CopyStatusType.SUCCESS.toString()) { + status = bu.getProperties().headers().value("x-ms-copy-status") + OffsetDateTime currentTime = OffsetDateTime.now() + if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { + throw new Exception("Copy failed or took too long") + } + sleep(1000) + } + } + + /** + * Validates the presence of headers that are present on a large number of responses. These headers are generally + * random and can really only be checked as not null. + * @param headers + * The object (may be headers object or response object) that has properties which expose these common headers. + * @return + * Whether or not the header values are appropriate. + */ + def validateBasicHeaders(HttpHeaders headers) { + return headers.value("etag") != null && + // Quotes should be scrubbed from etag header values + !headers.value("etag").contains("\"") && + headers.value("last-modified") != null && + headers.value("x-ms-request-id") != null && + headers.value("x-ms-version") != null && + headers.value("date") != null + } + + def validateBlobProperties(Response response, String cacheControl, String contentDisposition, String contentEncoding, + String contentLanguage, byte[] contentMD5, String contentType) { + return response.value().cacheControl() == cacheControl && + response.value().contentDisposition() == contentDisposition && + response.value().contentEncoding() == contentEncoding && + response.value().contentLanguage() == contentLanguage && + response.value().contentMD5() == contentMD5 && + response.headers().value("Content-Type") == (contentType == null ? "application/octet-stream" : contentType) + } + + static Metadata getMetadataFromHeaders(HttpHeaders headers) { + Metadata metadata = new Metadata() + + for (Map.Entry header : headers.toMap()) { + if (header.getKey().startsWith("x-ms-meta-")) { + String metadataKey = header.getKey().substring(10) + metadata.put(metadataKey, header.getValue()) + } + } + + return metadata + } + + def enableSoftDelete() { + primaryServiceURL.setProperties(new StorageServiceProperties() + .deleteRetentionPolicy(new RetentionPolicy().enabled(true).days(2))) + sleep(30000) // Wait for the policy to take effect. + } + + def disableSoftDelete() { + primaryServiceURL.setProperties(new StorageServiceProperties() + .deleteRetentionPolicy(new RetentionPolicy().enabled(false))) + + sleep(30000) // Wait for the policy to take effect. + } + + + + /* + This method returns a stub of an HttpResponse. This is for when we want to test policies in isolation but don't care + about the status code, so we stub a response that always returns a given value for the status code. We never care + about the number or nature of interactions with this stub. + */ + + def getStubResponse(int code) { + return Stub(HttpResponse) { + statusCode() >> code + } + } + + /* + This is for stubbing responses that will actually go through the pipeline and autorest code. Autorest does not seem + to play too nicely with mocked objects and the complex reflection stuff on both ends made it more difficult to work + with than was worth it. + */ + def getStubResponse(int code, HttpRequest request) { + return new HttpResponse() { + + @Override + int statusCode() { + return code + } + + @Override + String headerValue(String s) { + return null + } + + @Override + HttpHeaders headers() { + return new HttpHeaders() + } + + @Override + Flux body() { + return Flux.empty() + } + + @Override + Mono bodyAsByteArray() { + return Mono.just(new byte[0]) + } + + @Override + Mono bodyAsString() { + return Mono.just("") + } + + @Override + Mono bodyAsString(Charset charset) { + return Mono.just("") + } + }.request(request) + } + + /* + This is for stubbing responses that will actually go through the pipeline and autorest code. Autorest does not seem + to play too nicely with mocked objects and the complex reflection stuff on both ends made it more difficult to work + with than was worth it. Because this type is just for BlobDownload, we don't need to accept a header type. + */ + def getStubResponseForBlobDownload(int code, Flux body, String etag) { + return new HttpResponse() { + + @Override + int statusCode() { + return code + } + + @Override + String headerValue(String s) { + return null + } + + @Override + HttpHeaders headers() { + return new HttpHeaders() + } + + @Override + Flux body() { + return body + } + + @Override + Mono bodyAsByteArray() { + return null + } + + @Override + Mono bodyAsString() { + return null + } + + @Override + Mono bodyAsString(Charset charset) { + return null + } + } + } + + def getContextStubPolicy(int successCode, Class responseHeadersType) { + return Mock(HttpPipelinePolicy) { + process(_ as HttpPipelineCallContext, _ as HttpPipelineNextPolicy) >> { + HttpPipelineCallContext context, HttpPipelineNextPolicy next -> + if (!context.getData(defaultContextKey).isPresent()) { + return Mono.error(new RuntimeException("Context key not present.")) + } else { + return Mono.just(getStubResponse(successCode, context.httpRequest())) + } + } + } + } + + def getOAuthServiceURL() { + return new StorageClientBuilder() + .endpoint(String.format("https://%s.blob.core.windows.net/", primaryCreds.accountName())) + .credential(new EnvironmentCredential()) // AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET + .buildClient() + } + + def getTestMode(){ + String testMode = System.getenv("AZURE_TEST_MODE") + if(testMode == null){ + testMode = "PLAYBACK" + } + return testMode + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/AadLoginTest.java b/storage/client/blob/src/test/java/com/azure/storage/blob/AadLoginTest.java new file mode 100644 index 0000000000000..3c2ee324d1967 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/AadLoginTest.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.identity.credential.EnvironmentCredential; +import com.azure.storage.blob.models.ContainerItem; +import org.junit.BeforeClass; + +import java.util.Random; + +public class AadLoginTest { + private static final Random RANDOM = new Random(); + private static StorageClient storageClient; + + @BeforeClass + public static void setup() { + storageClient = new StorageClientBuilder() + .endpoint("https://" + System.getenv("ACCOUNT_NAME") + ".blob.core.windows.net") + .credential(new EnvironmentCredential()) +// .httpClient(HttpClient.createDefault().proxy(() -> new ProxyOptions(Type.HTTP, new InetSocketAddress("localhost", 8888)))) + .buildClient(); + } + + //@Test + public void listContainers() { + for (ContainerItem item : storageClient.listContainers()) { + System.out.println(item.name()); + } + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy new file mode 100644 index 0000000000000..b295c16c976d9 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/AppendBlobAPITest.groovy @@ -0,0 +1,480 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.core.http.rest.Response +import com.azure.storage.blob.models.* +import spock.lang.Unroll + +import java.security.MessageDigest + +class AppendBlobAPITest extends APISpec { + AppendBlobClient bu + + def setup() { + bu = cu.getAppendBlobClient(generateBlobName()) + bu.create() + } + + def "Create defaults"() { + when: + Response createResponse = bu.create() + + then: + createResponse.statusCode() == 201 + validateBasicHeaders(createResponse.headers()) + createResponse.value().contentMD5() == null + createResponse.value().isServerEncrypted() + } + + def "Create min"() { + expect: + bu.create().statusCode() == 201 + } + + def "Create error"() { + when: + bu.create(null, null, + new BlobAccessConditions().modifiedAccessConditions(new ModifiedAccessConditions().ifMatch("garbage")), + null) + + then: + thrown(StorageException) + } + + @Unroll + def "Create headers"() { + setup: + BlobHTTPHeaders headers = new BlobHTTPHeaders().blobCacheControl(cacheControl) + .blobContentDisposition(contentDisposition) + .blobContentEncoding(contentEncoding) + .blobContentLanguage(contentLanguage) + .blobContentMD5(contentMD5) + .blobContentType(contentType) + + when: + bu.create(headers, null, null, null) + Response response = bu.getProperties() + + then: + validateBlobProperties(response, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentMD5, contentType) + + where: + cacheControl | contentDisposition | contentEncoding | contentLanguage | contentMD5 | contentType + null | null | null | null | null | null + "control" | "disposition" | "encoding" | "language" | Base64.getEncoder().encode(MessageDigest.getInstance("MD5").digest(defaultText.getBytes())) | "type" + } + + @Unroll + def "Create metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + when: + bu.create(null, metadata, null, null) + Response response = bu.getProperties(null, null) + + then: + response.value().metadata() == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Create AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions().ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + + expect: + bu.create(null, null, bac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Create AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions().ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.create(null, null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Append block defaults"() { + setup: + Response appendResponse = bu.appendBlock(defaultInputStream.get(), defaultDataSize) + + expect: + ByteArrayOutputStream downloadStream = new ByteArrayOutputStream() + bu.download(downloadStream) + + downloadStream.toByteArray() == defaultData.array() + validateBasicHeaders(appendResponse.headers()) + appendResponse.value().contentMD5() != null + appendResponse.value().blobAppendOffset() != null + appendResponse.value().blobCommittedBlockCount() != null + Integer.parseInt(bu.getProperties().headers().value("x-ms-blob-committed-block-count")) == 1 + } + + def "Append block min"() { + expect: + bu.appendBlock(defaultInputStream.get(), defaultDataSize).statusCode() == 201 + } + + @Unroll + def "Append block IA"() { + when: + bu.appendBlock(data, dataSize) + + then: + def e = thrown(Exception) + exceptionType.isInstance(e) + + where: + data | dataSize | exceptionType + null | defaultDataSize | NullPointerException + defaultInputStream.get() | defaultDataSize + 1 | IndexOutOfBoundsException + // TODO (alzimmer): This doesn't throw an error as the stream is larger than the stated size + //defaultInputStream.get() | defaultDataSize - 1 | StorageException + } + + def "Append block empty body"() { + when: + bu.appendBlock(new ByteArrayInputStream(new byte[0]), 0) + + then: + thrown(StorageException) + } + + def "Append block null body"() { + when: + bu.appendBlock(new ByteArrayInputStream(null), 0) + + then: + thrown(NullPointerException) + } + + @Unroll + def "Append block AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + AppendBlobAccessConditions bac = new AppendBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .appendPositionAccessConditions(new AppendPositionAccessConditions() + .appendPosition(appendPosE) + .maxSize(maxSizeLTE)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + + expect: + bu.appendBlock(defaultInputStream.get(), defaultDataSize, bac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID | appendPosE | maxSizeLTE + null | null | null | null | null | null | null + oldDate | null | null | null | null | null | null + null | newDate | null | null | null | null | null + null | null | receivedEtag | null | null | null | null + null | null | null | garbageEtag | null | null | null + null | null | null | null | receivedLeaseID | null | null + null | null | null | null | null | 0 | null + null | null | null | null | null | null | 100 + } + + @Unroll + def "Append block AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + + AppendBlobAccessConditions bac = new AppendBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .appendPositionAccessConditions(new AppendPositionAccessConditions() + .appendPosition(appendPosE) + .maxSize(maxSizeLTE)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.appendBlock(defaultInputStream.get(), defaultDataSize, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID | appendPosE | maxSizeLTE + newDate | null | null | null | null | null | null + null | oldDate | null | null | null | null | null + null | null | garbageEtag | null | null | null | null + null | null | null | receivedEtag | null | null | null + null | null | null | null | garbageLeaseID | null | null + null | null | null | null | null | 1 | null + null | null | null | null | null | null | 1 + } + + def "Append block error"() { + setup: + bu = cu.getAppendBlobClient(generateBlobName()) + + when: + bu.appendBlock(defaultInputStream.get(), defaultDataSize) + + then: + thrown(StorageException) + } + + def "Append block from URL min"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + byte[] data = getRandomByteArray(1024) + bu.appendBlock(new ByteArrayInputStream(data), data.length) + + AppendBlobClient destURL = cu.getAppendBlobClient(generateBlobName()) + destURL.create() + + BlobRange blobRange = new BlobRange(0, (long) PageBlobClient.PAGE_BYTES) + + when: + Response response = destURL.appendBlockFromUrl(bu.getBlobUrl(), blobRange) + + then: + response.statusCode() == 201 + validateBasicHeaders(response.headers()) + } + + def "Append block from URL range"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + byte[] data = getRandomByteArray(4 * 1024) + bu.appendBlock(new ByteArrayInputStream(data), data.length) + + AppendBlobClient destURL = cu.getAppendBlobClient(generateBlobName()) + destURL.create() + + when: + destURL.appendBlockFromUrl(bu.getBlobUrl(), new BlobRange(2 * 1024, 1024)) + + then: + ByteArrayOutputStream downloadStream = new ByteArrayOutputStream(1024) + destURL.download(downloadStream) + downloadStream.toByteArray() == Arrays.copyOfRange(data, 2 * 1024, 3 * 1024) + } + + def "Append block from URL MD5"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + byte[] data = getRandomByteArray(1024) + bu.appendBlock(new ByteArrayInputStream(data), data.length) + + AppendBlobClient destURL = cu.getAppendBlobClient(generateBlobName()) + destURL.create() + + when: + destURL.appendBlockFromUrl(bu.getBlobUrl(), null, MessageDigest.getInstance("MD5").digest(data), + null, null, null) + + then: + notThrown(StorageException) + } + + def "Append block from URL MD5 fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + byte[] data = getRandomByteArray(1024) + bu.appendBlock(new ByteArrayInputStream(data), data.length) + + def destURL = cu.getAppendBlobClient(generateBlobName()) + destURL.create() + + when: + destURL.appendBlockFromUrl(bu.getBlobUrl(), null, MessageDigest.getInstance("MD5").digest("garbage".getBytes()), + null, null, null) + + then: + thrown(StorageException) + } + + @Unroll + def "Append block from URL destination AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + def bac = new AppendBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .appendPositionAccessConditions(new AppendPositionAccessConditions() + .appendPosition(appendPosE) + .maxSize(maxSizeLTE)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + def sourceURL = cu.getAppendBlobClient(generateBlobName()) + sourceURL.create() + sourceURL.appendBlock(defaultInputStream.get(), defaultDataSize).statusCode() + + expect: + bu.appendBlockFromUrl(sourceURL.getBlobUrl(), null, null, bac, null, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID | appendPosE | maxSizeLTE + null | null | null | null | null | null | null + oldDate | null | null | null | null | null | null + null | newDate | null | null | null | null | null + null | null | receivedEtag | null | null | null | null + null | null | null | garbageEtag | null | null | null + null | null | null | null | receivedLeaseID | null | null + null | null | null | null | null | 0 | null + null | null | null | null | null | null | 100 + } + + @Unroll + def "Append block from URL AC destination fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + + def bac = new AppendBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .appendPositionAccessConditions(new AppendPositionAccessConditions() + .appendPosition(appendPosE) + .maxSize(maxSizeLTE)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + def sourceURL = cu.getAppendBlobClient(generateBlobName()) + sourceURL.create() + sourceURL.appendBlock(defaultInputStream.get(), defaultDataSize).statusCode() + + when: + bu.appendBlockFromUrl(sourceURL.getBlobUrl(), null, null, bac, null, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID | appendPosE | maxSizeLTE + newDate | null | null | null | null | null | null + null | oldDate | null | null | null | null | null + null | null | garbageEtag | null | null | null | null + null | null | null | receivedEtag | null | null | null + null | null | null | null | garbageLeaseID | null | null + null | null | null | null | null | 1 | null + null | null | null | null | null | null | 1 + } + + @Unroll + def "Append block from URL source AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + + def sourceURL = cu.getAppendBlobClient(generateBlobName()) + sourceURL.create() + sourceURL.appendBlock(defaultInputStream.get(), defaultDataSize).statusCode() + + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(setupBlobMatchCondition(sourceURL, sourceIfMatch)) + .sourceIfNoneMatch(sourceIfNoneMatch) + + expect: + bu.appendBlockFromUrl(sourceURL.getBlobUrl(), null, null, null, smac, null).statusCode() == 201 + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Append block from URL AC source fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + + def sourceURL = cu.getAppendBlobClient(generateBlobName()) + sourceURL.create() + sourceURL.appendBlock(defaultInputStream.get(), defaultDataSize).statusCode() + + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(sourceIfMatch) + .sourceIfNoneMatch(setupBlobMatchCondition(sourceURL, sourceIfNoneMatch)) + + when: + bu.appendBlockFromUrl(sourceURL.getBlobUrl(), null, null, null, smac, null) + + then: + thrown(StorageException) + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy new file mode 100644 index 0000000000000..0cf250d85d174 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobAPITest.groovy @@ -0,0 +1,1885 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.core.http.HttpHeaders +import com.azure.core.http.rest.Response +import com.azure.core.http.rest.VoidResponse +import com.azure.core.implementation.util.ImplUtils +import com.azure.storage.blob.BlobProperties +import com.azure.storage.blob.models.* +import spock.lang.Unroll + +import java.nio.ByteBuffer +import java.security.MessageDigest +import java.time.OffsetDateTime + +class BlobAPITest extends APISpec { + BlobClient bu + + def setup() { + bu = cu.getBlockBlobClient(generateBlobName()) + bu.upload(defaultInputStream.get(), defaultDataSize) + } + + def "Download all null"() { + when: + ByteArrayOutputStream stream = new ByteArrayOutputStream() + VoidResponse response = bu.download(stream) + ByteBuffer body = ByteBuffer.wrap(stream.toByteArray()) + HttpHeaders headers = response.headers() + + then: + body == defaultData + ImplUtils.isNullOrEmpty(getMetadataFromHeaders(headers)) + headers.value("Content-Length") != null + headers.value("Content-Type") != null + headers.value("Content-Range") == null + headers.value("Content-MD5") != null + headers.value("Content-Encoding") == null + headers.value("Cache-Control") == null + headers.value("Content-Disposition") == null + headers.value("Content-Language") == null + headers.value("x-ms-blob-sequence-number") == null + headers.value("x-ms-blob-type") == BlobType.BLOCK_BLOB.toString() + headers.value("x-ms-copy-completion-time") == null + headers.value("x-ms-copy-status-description") == null + headers.value("x-ms-copy-id") == null + headers.value("x-ms-copy-progress") == null + headers.value("x-ms-copy-source") == null + headers.value("x-ms-copy-status") == null + headers.value("x-ms-lease-duration") == null + headers.value("x-ms-lease-state") == LeaseStateType.AVAILABLE.toString() + headers.value("x-ms-lease-status") == LeaseStatusType.UNLOCKED.toString() + headers.value("Accept-Ranges") == "bytes" + headers.value("x-ms-blob-committed-block-count") == null + headers.value("x-ms-server-encrypted") != null + headers.value("x-ms-blob-content-md5") == null + } + + def "Download empty file"() { + setup: + bu = cu.getAppendBlobClient("emptyAppendBlob") + bu.create() + + when: + def outStream = new ByteArrayOutputStream() + bu.download(outStream) + def result = outStream.toByteArray() + + then: + notThrown(StorageException) + result.length == 0 + } + + /* + This is to test the appropriate integration of DownloadResponse, including setting the correct range values on + HTTPGetterInfo. + */ +// def "Download with retry range"() { +// /* +// We are going to make a request for some range on a blob. The Flux returned will throw an exception, forcing +// a retry per the ReliableDownloadOptions. The next request should have the same range header, which was generated +// from the count and offset values in HTTPGetterInfo that was constructed on the initial call to download. We +// don't need to check the data here, but we want to ensure that the correct range is set each time. This will +// test the correction of a bug that was found which caused HTTPGetterInfo to have an incorrect offset when it was +// constructed in BlobClient.download(). +// */ +// setup: +// HttpPipelinePolicy mockPolicy = Mock(HttpPipelinePolicy) { +// process(_ as HttpPipelineCallContext, _ as HttpPipelineNextPolicy) >> { +// HttpPipelineCallContext context, HttpPipelineNextPolicy next -> +// HttpRequest request = context.httpRequest() +// if (request.headers().value("x-ms-range") != "bytes=2-6") { +// return Mono.error(new IllegalArgumentException("The range header was not set correctly on retry.")) +// } +// else { +// // ETag can be a dummy value. It's not validated, but DownloadResponse requires one +// // TODO stub responses failing azure.core.implementation checks; too many nulls +// return Mono.just(getStubResponseForBlobDownload(206, Flux.error(new IOException()), "etag")) +// } +// } +// } +// +// BlobClient bu2 = new BlobClientBuilder() +// .endpoint(bu.getBlobUrl().toString()) +// .credential(primaryCreds) +// .addPolicy(mockPolicy) +// .buildClient() +// +// when: +// def range = new BlobRange(2, 5L) +// def options = new ReliableDownloadOptions().maxRetryRequests(3) +// bu2.download(new ByteArrayOutputStream(), options, range, null, false, null) +// +// then: +// /* +// Because the dummy Flux always throws an error. This will also validate that an IllegalArgumentException is +// NOT thrown because the types would not match. +// */ +// def e = thrown(RuntimeException) +// e.getCause() instanceof IOException +// } + + def "Download min"() { + when: + def outStream = new ByteArrayOutputStream() + bu.download(outStream) + byte[] result = outStream.toByteArray() + + then: + result == defaultData.array() + } + + @Unroll + def "Download range"() { + setup: + BlobRange range = (count == null) ? new BlobRange(offset) : new BlobRange(offset, count) + + when: + def outStream = new ByteArrayOutputStream() + bu.download(outStream, null, range, null, false, null) + String bodyStr = outStream.toString() + + then: + bodyStr == expectedData + + where: + offset | count || expectedData + 0 | null || defaultText + 0 | 5L || defaultText.substring(0, 5) + 3 | 2L || defaultText.substring(3, 3 + 2) + } + + @Unroll + def "Download AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions().ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + def response = bu.download(new ByteArrayOutputStream(), null, null, bac, false, null) + + then: + response.statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Download AC fail"() { + setup: + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.download(new ByteArrayOutputStream(), null, null, bac, false, null).statusCode() == 206 + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Download md5"() { + when: + VoidResponse response = bu.download(new ByteArrayOutputStream(), null, new BlobRange(0 ,3), null, true, null) + byte[] contentMD5 = response.headers().value("content-md5").getBytes() + + then: + contentMD5 == Base64.getEncoder().encode(MessageDigest.getInstance("MD5").digest(defaultText.substring(0, 3).getBytes())) + } + + def "Download error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.download(null, null, null, null, false, null) + + then: + thrown(StorageException) + } + + def "Download snapshot"() { + when: + ByteArrayOutputStream originalStream = new ByteArrayOutputStream() + bu.download(originalStream) + + String snapshot = bu.createSnapshot().value() + BlockBlobClient bu2 = bu.asBlockBlobClient() + bu2.upload(new ByteArrayInputStream("ABC".getBytes()), 3) + + then: + BlobClient bu3 = new BlobClientBuilder() + .endpoint(bu.getBlobUrl().toString()) + .snapshot(snapshot) + .credential(primaryCreds) + .buildClient() + ByteArrayOutputStream snapshotStream = new ByteArrayOutputStream() + bu3.download(snapshotStream) + snapshotStream.toByteArray() == originalStream.toByteArray() + } + + def "Get properties default"() { + when: + Response response = bu.getProperties(null, null) + HttpHeaders headers = response.headers() + + then: + validateBasicHeaders(headers) + ImplUtils.isNullOrEmpty(getMetadataFromHeaders(headers)) + headers.value("x-ms-blob-type") == BlobType.BLOCK_BLOB.toString() + headers.value("x-ms-copy-completion-time") == null // tested in "copy" + headers.value("x-ms-copy-status-description") == null // only returned when the service has errors; cannot validate. + headers.value("x-ms-copy-id") == null // tested in "abort copy" + headers.value("x-ms-copy-progress") == null // tested in "copy" + headers.value("x-ms-copy-source") == null // tested in "copy" + headers.value("x-ms-copy-status") == null // tested in "copy" + headers.value("x-ms-incremental-copy") == null // tested in PageBlob."start incremental copy" + headers.value("x-ms-copy-destination-snapshot") == null // tested in PageBlob."start incremental copy" + headers.value("x-ms-lease-duration") == null // tested in "acquire lease" + headers.value("x-ms-lease-state") == LeaseStateType.AVAILABLE.toString() + headers.value("x-ms-lease-status") == LeaseStatusType.UNLOCKED.toString() + headers.value("Content-Length") != null + headers.value("Content-Type") != null + headers.value("Content-MD5") != null + headers.value("Content-Encoding") == null // tested in "set HTTP headers" + headers.value("Content-Disposition") == null // tested in "set HTTP headers" + headers.value("Content-Language") == null // tested in "set HTTP headers" + headers.value("Cache-Control") == null // tested in "set HTTP headers" + headers.value("x-ms-blob-sequence-number") == null // tested in PageBlob."create sequence number" + headers.value("Accept-Ranges") == "bytes" + headers.value("x-ms-blob-committed-block-count") == null // tested in AppendBlob."append block" + Boolean.parseBoolean(headers.value("x-ms-server-encrypted")) + headers.value("x-ms-access-tier") == AccessTier.HOT.toString() + Boolean.parseBoolean(headers.value("x-ms-access-tier-inferred")) + headers.value("x-ms-archive-status") == null + headers.value("x-ms-creation-time") != null + } + + def "Get properties min"() { + expect: + bu.getProperties().statusCode() == 200 + } + + @Unroll + def "Get properties AC"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + + expect: + bu.getProperties(bac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Get properties AC fail"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.getProperties(bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Get properties error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.getProperties(null, null) + + then: + thrown(StorageException) + } + + def "Set HTTP headers null"() { + setup: + VoidResponse response = bu.setHTTPHeaders(null) + + expect: + response.statusCode() == 200 + validateBasicHeaders(response.headers()) + } + + // TODO (alzimmer): Figure out why getProperties returns null after setHTTPHeaders + /*def "Set HTTP headers min"() { + when: + BlobProperties properties = bu.getProperties().value() + BlobHTTPHeaders headers = new BlobHTTPHeaders() + .blobContentEncoding(properties.contentEncoding()) + .blobContentDisposition(properties.contentDisposition()) + .blobContentType("type") + .blobCacheControl(properties.cacheControl()) + .blobContentLanguage(properties.contentLanguage()) + .blobContentMD5(Base64.getDecoder().decode(properties.contentMD5())) + + bu.setHTTPHeaders(headers) + + then: + bu.getProperties().headers().value("x-ms-blob-content-type") == "type" + }*/ + + /*@Unroll + def "Set HTTP headers headers"() { + setup: + BlobHTTPHeaders putHeaders = new BlobHTTPHeaders().blobCacheControl(cacheControl) + .blobContentDisposition(contentDisposition) + .blobContentEncoding(contentEncoding) + .blobContentLanguage(contentLanguage) + .blobContentMD5(contentMD5) + .blobContentType(contentType) + + bu.setHTTPHeaders(putHeaders) + + Response response = bu.getProperties() + + expect: + validateBlobProperties(response, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentMD5, contentType) + + where: + cacheControl | contentDisposition | contentEncoding | contentLanguage | contentMD5 | contentType + null | null | null | null | null | null + "control" | "disposition" | "encoding" | "language" | Base64.getEncoder().encode(MessageDigest.getInstance("MD5").digest(defaultData.array())) | "type" + }*/ + + + @Unroll + def "Set HTTP headers AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + expect: + bu.setHTTPHeaders(null, bac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Set HTTP headers AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.setHTTPHeaders(null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Set HTTP headers error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.setHTTPHeaders(null, null, null) + + then: + thrown(StorageException) + } + + def "Set metadata all null"() { + setup: + VoidResponse response = bu.setMetadata(null, null, null) + + expect: + bu.getProperties(null, null).value().metadata().size() == 0 + response.statusCode() == 200 + validateBasicHeaders(response.headers()) + Boolean.parseBoolean(response.headers().value("x-ms-request-server-encrypted")) + } + + def "Set metadata min"() { + setup: + Metadata metadata = new Metadata() + metadata.put("foo", "bar") + + when: + bu.setMetadata(metadata) + + then: + bu.getProperties().value().metadata() == metadata + } + + @Unroll + def "Set metadata metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null && value1 != null) { + metadata.put(key1, value1) + } + if (key2 != null && value2 != null) { + metadata.put(key2, value2) + } + + expect: + bu.setMetadata(metadata, null, null).statusCode() == statusCode + bu.getProperties(null, null).value().metadata() == metadata + + where: + key1 | value1 | key2 | value2 || statusCode + null | null | null | null || 200 + "foo" | "bar" | "fizz" | "buzz" || 200 + } + + @Unroll + def "Set metadata AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + expect: + bu.setMetadata(null, bac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Set metadata AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.setMetadata(null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Set metadata error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.setMetadata(null, null, null) + + then: + thrown(StorageException) + } + + @Unroll + def "Acquire lease"() { + setup: + String leaseId = bu.acquireLease(proposedID, leaseTime, null, null).value() + + when: + HttpHeaders headers = bu.getProperties(null, null).headers() + + then: + headers.value("x-ms-lease-state") == leaseState.toString() + headers.value("x-ms-lease-duration") == leaseDuration.toString() + leaseId != null + validateBasicHeaders(headers) + + where: + proposedID | leaseTime || leaseState | leaseDuration + null | -1 || LeaseStateType.LEASED | LeaseDurationType.INFINITE + null | 25 || LeaseStateType.LEASED | LeaseDurationType.FIXED + UUID.randomUUID().toString() | -1 || LeaseStateType.LEASED | LeaseDurationType.INFINITE + } + + def "Acquire lease min"() { + setup: + bu.acquireLease(null, -1).statusCode() == 201 + } + + @Unroll + def "Acquire lease AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu.acquireLease(null, -1, mac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Acquire lease AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu.acquireLease(null, -1, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Acquire lease error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.acquireLease(null, 20, null, null) + + then: + thrown(StorageException) + } + + def "Renew lease"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + Thread.sleep(16000) // Wait for the lease to expire to ensure we are actually renewing it + Response renewLeaseResponse = bu.renewLease(leaseID, null, null) + + expect: + bu.getProperties(null, null).headers().value("x-ms-lease-state") == LeaseStateType.LEASED.toString() + validateBasicHeaders(renewLeaseResponse.headers()) + renewLeaseResponse.value() != null + } + + def "Renew lease min"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + expect: + bu.renewLease(leaseID).statusCode() == 200 + } + + @Unroll + def "Renew lease AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu.renewLease(leaseID, mac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Renew lease AC fail"() { + noneMatch = setupBlobMatchCondition(bu, noneMatch) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu.renewLease(leaseID, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Renew lease error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.renewLease("id", null, null) + + then: + thrown(StorageException) + } + + def "Release lease"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + HttpHeaders headers = bu.releaseLease(leaseID, null, null).headers() + + expect: + bu.getProperties(null, null).headers().value("x-ms-lease-state") == LeaseStateType.AVAILABLE.toString() + validateBasicHeaders(headers) + } + + def "Release lease min"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + expect: + bu.releaseLease(leaseID).statusCode() == 200 + } + + @Unroll + def "Release lease AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu.releaseLease(leaseID, mac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Release lease AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu.releaseLease(leaseID, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Release lease error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.releaseLease("id", null, null) + + then: + thrown(StorageException) + } + + @Unroll + def "Break lease"() { + setup: + bu.acquireLease(UUID.randomUUID().toString(), leaseTime, null, null) + + Response breakLeaseResponse = bu.breakLease(breakPeriod, null, null) + String leaseState = bu.getProperties(null, null).headers().value("x-ms-lease-state") + + expect: + leaseState == LeaseStateType.BROKEN.toString() || leaseState == LeaseStateType.BREAKING.toString() + breakLeaseResponse.value() <= remainingTime + validateBasicHeaders(breakLeaseResponse.headers()) + + where: + leaseTime | breakPeriod | remainingTime + -1 | null | 0 + -1 | 20 | 25 + 20 | 15 | 16 + } + + def "Break lease min"() { + setup: + setupBlobLeaseCondition(bu, receivedLeaseID) + + expect: + bu.breakLease().statusCode() == 202 + } + + @Unroll + def "Break lease AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu.breakLease(null, mac, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Break lease AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu.breakLease(null, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Break lease error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.breakLease(null, null, null) + + then: + thrown(StorageException) + } + + def "Change lease"() { + setup: + Response acquireLeaseResponse = bu.acquireLease(UUID.randomUUID().toString(), 15) + Response changeLeaseResponse = bu.changeLease(acquireLeaseResponse.value(), UUID.randomUUID().toString()) + + expect: + bu.releaseLease(changeLeaseResponse.value(), null, null).statusCode() == 200 + validateBasicHeaders(changeLeaseResponse.headers()) + } + + def "Change lease min"() { + setup: + def leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + expect: + bu.changeLease(leaseID, UUID.randomUUID().toString()).statusCode() == 200 + } + + @Unroll + def "Change lease AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu.changeLease(leaseID, UUID.randomUUID().toString(), mac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Change lease AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu.changeLease(leaseID, UUID.randomUUID().toString(), mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Change lease error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.changeLease("id", "id", null, null) + + then: + thrown(StorageException) + } + + def "Snapshot"() { + when: + Response snapshotResponse = bu.createSnapshot() + BlobClient bu2 = new BlobClientBuilder() + .endpoint(bu.getBlobUrl().toString()) + .credential(primaryCreds) + .snapshot(snapshotResponse.value()) + .buildClient() + + then: + bu2.getProperties().statusCode() == 200 + validateBasicHeaders(snapshotResponse.headers()) + } + + def "Snapshot min"() { + expect: + bu.createSnapshot().statusCode() == 201 + } + + @Unroll + def "Snapshot metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null && value1 != null) { + metadata.put(key1, value1) + } + if (key2 != null && value2 != null) { + metadata.put(key2, value2) + } + + Response response = bu.createSnapshot(metadata, null, null) + BlobClient bu2 = new BlobClientBuilder() + .endpoint(bu.getBlobUrl().toString()) + .credential(primaryCreds) + .snapshot(response.value()) + .buildClient() + + expect: + response.statusCode() == 201 + bu2.getProperties().value().metadata() == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Snapshot AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + expect: + bu.createSnapshot(null, bac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Snapshot AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + when: + bu.createSnapshot(null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Snapshot error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.createSnapshot(null, null, null) + + then: + thrown(StorageException) + } + + def "Copy"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + HttpHeaders headers = + bu2.startCopyFromURL(bu.getBlobUrl(), null, null, null, null).headers() + + when: + while (bu2.getProperties(null, null).headers().value("x-ms-copy-status") == CopyStatusType.PENDING.toString()) { + sleep(1000) + } + HttpHeaders headers2 = bu2.getProperties(null, null).headers() + + then: + headers2.value("x-ms-copy-status") == CopyStatusType.SUCCESS.toString() + headers2.value("x-ms-copy-completion-time") != null + headers2.value("x-ms-copy-progress") != null + headers2.value("x-ms-copy-source") != null + validateBasicHeaders(headers) + headers.value("x-ms-copy-id") != null + } + + def "Copy min"() { + expect: + bu.startCopyFromURL(bu.getBlobUrl()).statusCode() == 202 + } + + @Unroll + def "Copy metadata"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + Metadata metadata = new Metadata() + if (key1 != null && value1 != null) { + metadata.put(key1, value1) + } + if (key2 != null && value2 != null) { + metadata.put(key2, value2) + } + + String status = + bu2.startCopyFromURL(bu.getBlobUrl(), metadata, null, null, null) + .headers().value("x-ms-copy-status") + + OffsetDateTime start = OffsetDateTime.now() + while (status != CopyStatusType.SUCCESS.toString()) { + sleep(1000) + status = bu2.getProperties().headers().value("x-ms-copy-status") + OffsetDateTime currentTime = OffsetDateTime.now() + if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { + throw new Exception("Copy failed or took too long") + } + } + + expect: + getMetadataFromHeaders(bu2.getProperties().headers()) == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Copy source AC"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + match = setupBlobMatchCondition(bu, match) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu2.startCopyFromURL(bu.getBlobUrl(), null, mac, null, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Copy source AC fail"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + noneMatch = setupBlobMatchCondition(bu, noneMatch) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu2.startCopyFromURL(bu.getBlobUrl(), null, mac, null, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + @Unroll + def "Copy dest AC"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + match = setupBlobMatchCondition(bu2, match) + leaseID = setupBlobLeaseCondition(bu2, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + expect: + bu2.startCopyFromURL(bu.getBlobUrl(), null, null, bac, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Copy dest AC fail"() { + setup: + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + noneMatch = setupBlobMatchCondition(bu2, noneMatch) + setupBlobLeaseCondition(bu2, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu2.startCopyFromURL(bu.getBlobUrl(), null, null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Abort copy lease fail"() { + // Data has to be large enough and copied between accounts to give us enough time to abort + bu.asBlockBlobClient() + .upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + // So we don't have to create a SAS. + cu.setAccessPolicy(PublicAccessType.BLOB, null) + + ContainerClient cu2 = alternateServiceURL.getContainerClient(generateBlobName()) + cu2.create() + BlockBlobClient bu2 = cu2.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + String leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) + + when: + String copyID = + bu2.startCopyFromURL(bu.getBlobUrl(), null, null, + new BlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)), null).value() + bu2.abortCopyFromURL(copyID, new LeaseAccessConditions().leaseId(garbageLeaseID), null) + + then: + def e = thrown(StorageException) + e.statusCode() == 412 + cu2.delete() + } + + def "Abort copy"() { + setup: + // Data has to be large enough and copied between accounts to give us enough time to abort + bu.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + // So we don't have to create a SAS. + cu.setAccessPolicy(PublicAccessType.BLOB, null) + + ContainerClient cu2 = alternateServiceURL.getContainerClient(generateBlobName()) + cu2.create() + BlobClient bu2 = cu2.getBlobClient(generateBlobName()) + + when: + String copyID = bu2.startCopyFromURL(bu.getBlobUrl()).value() + VoidResponse response = bu2.abortCopyFromURL(copyID) + HttpHeaders headers = response.headers() + + then: + response.statusCode() == 204 + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + headers.value("Date") != null + // Normal test cleanup will not clean up containers in the alternate account. + cu2.delete().statusCode() == 202 + } + + def "Abort copy min"() { + setup: + // Data has to be large enough and copied between accounts to give us enough time to abort + bu.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + // So we don't have to create a SAS. + cu.setAccessPolicy(PublicAccessType.BLOB, null) + + ContainerClient cu2 = alternateServiceURL.getContainerClient(generateBlobName()) + cu2.create() + BlobClient bu2 = cu2.getBlobClient(generateBlobName()) + + when: + String copyID = + bu2.startCopyFromURL(bu.getBlobUrl()).value() + + then: + bu2.abortCopyFromURL(copyID).statusCode() == 204 + } + + def "Abort copy lease"() { + setup: + // Data has to be large enough and copied between accounts to give us enough time to abort + bu.asBlockBlobClient().upload(new ByteArrayInputStream(getRandomByteArray(8 * 1024 * 1024)), 8 * 1024 * 1024) + // So we don't have to create a SAS. + cu.setAccessPolicy(PublicAccessType.BLOB, null) + + ContainerClient cu2 = alternateServiceURL.getContainerClient(generateContainerName()) + cu2.create() + BlockBlobClient bu2 = cu2.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + String leaseID = setupBlobLeaseCondition(bu2, receivedLeaseID) + + when: + String copyID = + bu2.startCopyFromURL(bu.getBlobUrl(), null, null, + new BlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)), null).value() + + then: + bu2.abortCopyFromURL(copyID, new LeaseAccessConditions().leaseId(leaseID), null).statusCode() == 204 + // Normal test cleanup will not clean up containers in the alternate account. + cu2.delete() + } + + def "Copy error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.startCopyFromURL(new URL("http://www.error.com")) + + then: + thrown(StorageException) + } + + def "Abort copy error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.abortCopyFromURL("id") + + then: + thrown(StorageException) + } + + def "Sync copy"() { + setup: + // Sync copy is a deep copy, which requires either sas or public access. + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + HttpHeaders headers = bu2.copyFromURL(bu.getBlobUrl(), null, null,null, null).headers() + + expect: + headers.value("x-ms-copy-status") == SyncCopyStatusType.SUCCESS.toString() + headers.value("x-ms-copy-id") != null + validateBasicHeaders(headers) + } + + def "Sync copy min"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + + expect: + bu2.copyFromURL(bu.getBlobUrl()).statusCode() == 202 + } + + @Unroll + def "Sync copy metadata"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + Metadata metadata = new Metadata() + if (key1 != null && value1 != null) { + metadata.put(key1, value1) + } + if (key2 != null && value2 != null) { + metadata.put(key2, value2) + } + + when: + bu2.copyFromURL(bu.getBlobUrl(), metadata, null, null, null) + + then: + getMetadataFromHeaders(bu2.getProperties().headers()) == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Sync copy source AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + match = setupBlobMatchCondition(bu, match) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu2.copyFromURL(bu.getBlobUrl(), null, mac, null, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Sync copy source AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + noneMatch = setupBlobMatchCondition(bu, noneMatch) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu2.copyFromURL(bu.getBlobUrl(), null, mac, null, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + @Unroll + def "Sync copy dest AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + match = setupBlobMatchCondition(bu2, match) + leaseID = setupBlobLeaseCondition(bu2, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + expect: + bu2.copyFromURL(bu.getBlobUrl(), null, null, bac, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Sync copy dest AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + BlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + noneMatch = setupBlobMatchCondition(bu2, noneMatch) + setupBlobLeaseCondition(bu2, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu2.copyFromURL(bu.getBlobUrl(), null, null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Sync copy error"() { + setup: + def bu2 = cu.getBlockBlobClient(generateBlobName()) + + when: + bu2.copyFromURL(bu.getBlobUrl()) + + then: + thrown(StorageException) + } + + def "Delete"() { + when: + VoidResponse response = bu.delete() + HttpHeaders headers = response.headers() + + then: + response.statusCode() == 202 + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + headers.value("Date") != null + } + + def "Delete min"() { + expect: + bu.delete().statusCode() == 202 + } + + @Unroll + def "Delete options"() { + setup: + bu.createSnapshot() + // Create an extra blob so the list isn't empty (null) when we delete base blob, too + BlockBlobClient bu2 = cu.getBlockBlobClient(generateBlobName()) + bu2.upload(defaultInputStream.get(), defaultDataSize) + + when: + bu.delete(option, null, null) + + then: + Iterator blobs = cu.listBlobsFlat().iterator() + + int blobCount = 0 + for ( ; blobs.hasNext(); blobCount++ ) + blobs.next() + + blobCount == blobsRemaining + + where: + option | blobsRemaining + DeleteSnapshotsOptionType.INCLUDE | 1 + DeleteSnapshotsOptionType.ONLY | 2 + } + + @Unroll + def "Delete AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + expect: + bu.delete(DeleteSnapshotsOptionType.INCLUDE, bac, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Delete AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.delete(DeleteSnapshotsOptionType.INCLUDE, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Blob delete error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.delete(null, null, null) + + then: + thrown(StorageException) + } + + @Unroll + def "Set tier block blob"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateContainerName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultData.remaining()) + + when: + VoidResponse initialResponse = bu.setTier(tier) + HttpHeaders headers = initialResponse.headers() + + then: + initialResponse.statusCode() == 200 || initialResponse.statusCode() == 202 + headers.value("x-ms-version") != null + headers.value("x-ms-request-id") != null + bu.getProperties().headers().value("x-ms-access-tier") == tier.toString() + cu.listBlobsFlat().iterator().next().properties().accessTier() == tier + + where: + tier | _ + AccessTier.HOT | _ + AccessTier.COOL | _ + AccessTier.ARCHIVE | _ + } + + @Unroll + def "Set tier page blob"() { + setup: + ContainerClient cu = premiumServiceURL.getContainerClient(generateContainerName()) + cu.create() + + PageBlobClient bu = cu.getPageBlobClient(generateBlobName()) + bu.create(512) + + when: + bu.setTier(tier, null, null) + + then: + bu.getProperties().headers().value("x-ms-access-tier") == tier.toString() + cu.listBlobsFlat().iterator().next().properties().accessTier() == tier + cu.delete() + + where: + tier | _ + AccessTier.P4 | _ + AccessTier.P6 | _ + AccessTier.P10 | _ + AccessTier.P20 | _ + AccessTier.P30 | _ + AccessTier.P40 | _ + AccessTier.P50 | _ + } + + def "Set tier min"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateContainerName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultData.remaining()) + + when: + int statusCode = bu.setTier(AccessTier.HOT).statusCode() + + then: + statusCode == 200 || statusCode == 202 + } + + def "Set tier inferred"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateBlobName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultDataSize) + + when: + boolean inferred1 = Boolean.parseBoolean(bu.getProperties().headers().value("x-ms-access-tier-inferred")) + Boolean inferredList1 = cu.listBlobsFlat().iterator().next().properties().accessTierInferred() + + bu.setTier(AccessTier.HOT) + + boolean inferred2 = Boolean.parseBoolean(bu.getProperties().headers().value("x-ms-access-tier-inferred")) + Boolean inferredList2 = cu.listBlobsFlat().iterator().next().properties().accessTierInferred() + + then: + inferred1 + inferredList1 + !inferred2 + inferredList2 == null + } + + @Unroll + def "Set tier archive status"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateBlobName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultDataSize) + + when: + bu.setTier(sourceTier) + bu.setTier(destTier) + + then: + bu.getProperties().headers().value("x-ms-archive-status") == status.toString() + cu.listBlobsFlat().iterator().next().properties().archiveStatus() == status + + where: + sourceTier | destTier | status + AccessTier.ARCHIVE | AccessTier.COOL | ArchiveStatus.REHYDRATE_PENDING_TO_COOL + AccessTier.ARCHIVE | AccessTier.HOT | ArchiveStatus.REHYDRATE_PENDING_TO_HOT + } + + def "Set tier error"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateBlobName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultDataSize) + + when: + bu.setTier(AccessTier.fromString("garbage")) + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.INVALID_HEADER_VALUE + } + + def "Set tier illegal argument"() { + when: + bu.setTier(null) + + then: + thrown(IllegalArgumentException) + } + + def "Set tier lease"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateBlobName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultDataSize) + def leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + when: + bu.setTier(AccessTier.HOT, new LeaseAccessConditions().leaseId(leaseID), null) + + then: + notThrown(StorageException) + } + + def "Set tier lease fail"() { + setup: + ContainerClient cu = blobStorageServiceURL.getContainerClient(generateBlobName()) + BlockBlobClient bu = cu.getBlockBlobClient(generateBlobName()) + cu.create() + bu.upload(defaultInputStream.get(), defaultDataSize) + + when: + bu.setTier(AccessTier.HOT, new LeaseAccessConditions().leaseId("garbage"), null) + + then: + thrown(StorageException) + } + + def "Undelete"() { + setup: + enableSoftDelete() + bu.delete() + + when: + HttpHeaders headers = bu.undelete().headers() + bu.getProperties() + + then: + notThrown(StorageException) + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + headers.value("Date") != null + + disableSoftDelete() == null + } + + def "Undelete min"() { + setup: + enableSoftDelete() + bu.delete() + + expect: + bu.undelete().statusCode() == 200 + } + + def "Undelete error"() { + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.undelete() + + then: + thrown(StorageException) + } + + def "Get account info"() { + when: + Response response = primaryServiceURL.getAccountInfo() + + then: + response.headers().value("Date") != null + response.headers().value("x-ms-request-id") != null + response.headers().value("x-ms-version") != null + response.value().accountKind() != null + response.value().skuName() != null + } + + def "Get account info min"() { + expect: + bu.getAccountInfo().statusCode() == 200 + } + + def "Get account info error"() { + when: + StorageClient serviceURL = new StorageClientBuilder() + .endpoint(primaryServiceURL.getAccountUrl().toString()) + .buildClient() + serviceURL.getContainerClient(generateContainerName()).getBlobClient(generateBlobName()) + .getAccountInfo(null) + + then: + thrown(StorageException) + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.java b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.java new file mode 100644 index 0000000000000..7ebc5e8487cf2 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/BlobOutputStreamTest.java @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.common.credentials.SharedKeyCredential; +import org.junit.Assert; +import org.junit.BeforeClass; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class BlobOutputStreamTest { + private static final Random RANDOM = new Random(); + private static StorageClient storageClient; + private static ContainerClient containerClient; + + @BeforeClass + public static void setup() { + storageClient = new StorageClientBuilder() + .endpoint("https://" + System.getenv("ACCOUNT_NAME") + ".blob.core.windows.net") + .credential(new SharedKeyCredential(System.getenv("ACCOUNT_NAME"), System.getenv("ACCOUNT_KEY"))) +// .httpClient(HttpClient.createDefault().proxy(() -> new ProxyOptions(Type.HTTP, new InetSocketAddress("localhost", 8888)))) + .buildClient(); + String containerName = "testcontainer" + RANDOM.nextInt(1000); + containerClient = storageClient.getContainerClient(containerName); + if (!containerClient.exists().value()) { + containerClient.create(); + } + } + +// @Test + public void testBlockBlobOutputStream() throws Exception { + String blobName = "testblob" + RANDOM.nextInt(1000); + int length = 100 * Constants.MB; + byte[] randomBytes = new byte[length]; + RANDOM.nextBytes(randomBytes); + + BlockBlobClient blockBlobClient = containerClient.getBlockBlobClient(blobName); + BlobOutputStream outStream = blockBlobClient.getBlobOutputStream(); + outStream.write(randomBytes); + outStream.close(); + + Assert.assertEquals(length, blockBlobClient.getProperties().value().blobSize()); + BlobInputStream blobInputStream = blockBlobClient.openInputStream(); + byte[] downloaded = convertInputStreamToByteArray(blobInputStream); + Assert.assertArrayEquals(randomBytes, downloaded); + } + +// @Test + public void testPageBlobOutputStream() throws Exception { + int length = 1024 * Constants.MB - 512; + String blobName = "testblob" + RANDOM.nextInt(1000); + byte[] randomBytes = new byte[length]; + RANDOM.nextBytes(randomBytes); + + PageBlobClient pageBlobClient = containerClient.getPageBlobClient(blobName); + pageBlobClient.create(length); + BlobOutputStream outStream = pageBlobClient.getBlobOutputStream(length); + outStream.write(randomBytes); + outStream.close(); + + BlobInputStream blobInputStream = pageBlobClient.openInputStream(); + byte[] downloaded = convertInputStreamToByteArray(blobInputStream); + Assert.assertArrayEquals(randomBytes, downloaded); + } + +// @Test + public void testAppendBlobOutputStream() throws Exception { + int length = 0; + String blobName = "testblob" + RANDOM.nextInt(1000); + List randomBytes = new ArrayList<>(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + for (int i = 0; i != 64; ++i) { + int subLength = RANDOM.nextInt(4 * Constants.MB); + length += subLength; + byte[] bytes = new byte[subLength]; + RANDOM.nextBytes(bytes); + randomBytes.add(bytes); + stream.write(bytes); + } + + byte[] uploaded = stream.toByteArray(); + + AppendBlobClient appendBlobClient = containerClient.getAppendBlobClient(blobName); + appendBlobClient.create(); + BlobOutputStream outStream = appendBlobClient.getBlobOutputStream(); + for (int i = 0; i != 64; i++) { + outStream.write(randomBytes.get(i)); + } + outStream.close(); + + Assert.assertEquals(length, appendBlobClient.getProperties().value().blobSize()); + BlobInputStream blobInputStream = appendBlobClient.openInputStream(); + byte[] downloaded = convertInputStreamToByteArray(blobInputStream); + Assert.assertArrayEquals(uploaded, downloaded); + } + + private byte[] convertInputStreamToByteArray(InputStream inputStream) { + int b; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try { + while ((b = inputStream.read()) != -1) { + outputStream.write(b); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + + return outputStream.toByteArray(); + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy new file mode 100644 index 0000000000000..63ec8837697b1 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobAPITest.groovy @@ -0,0 +1,735 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.core.http.HttpHeaders +import com.azure.core.http.rest.Response +import com.azure.core.http.rest.VoidResponse +import com.azure.storage.blob.models.* +import spock.lang.Unroll + +import java.nio.ByteBuffer +import java.nio.charset.StandardCharsets +import java.security.MessageDigest + +class BlockBlobAPITest extends APISpec { + BlockBlobClient bu + + def setup() { + bu = cu.getBlockBlobClient(generateBlobName()) + bu.upload(defaultInputStream.get(), defaultDataSize) + } + + def getBlockID() { + return Base64.encoder.encodeToString(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8)) + } + + def "Stage block"() { + setup: + VoidResponse response = bu.stageBlock(getBlockID(), defaultInputStream.get(), defaultDataSize) + HttpHeaders headers = response.headers() + + expect: + response.statusCode() == 201 + headers.value("Content-MD5") != null + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + headers.value("Date") != null + Boolean.parseBoolean(headers.value("x-ms-request-server-encrypted")) + } + + def "Stage block min"() { + expect: + bu.stageBlock(getBlockID(), defaultInputStream.get(), defaultDataSize).statusCode() == 201 + } + + @Unroll + def "Stage block illegal arguments"() { + when: + bu.stageBlock(blockID, data == null ? null : data.get(), dataSize) + + then: + def e = thrown(Exception) + exceptionType.isInstance(e) + + where: + blockID | data | dataSize | exceptionType + null | defaultInputStream | defaultDataSize | StorageException + getBlockID() | null | defaultDataSize | NullPointerException + getBlockID() | defaultInputStream | defaultDataSize + 1 | IndexOutOfBoundsException + // TODO (alzimmer): This doesn't throw an error as the stream is larger than the stated size + //getBlockID() | defaultInputStream | defaultDataSize - 1 | IllegalArgumentException + } + + def "Stage block empty body"() { + when: + bu.stageBlock(getBlockID(), new ByteArrayInputStream(new byte[0]), 0) + + then: + thrown(StorageException) + } + + def "Stage block null body"() { + when: + bu.stageBlock(getBlockID(), null, 0) + + then: + thrown(StorageException) + } + + def "Stage block lease"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + expect: + bu.stageBlock(getBlockID(), defaultInputStream.get(), defaultDataSize, new LeaseAccessConditions().leaseId(leaseID), + null).statusCode() == 201 + } + + def "Stage block lease fail"() { + setup: + setupBlobLeaseCondition(bu, receivedLeaseID) + + when: + bu.stageBlock(getBlockID(), defaultInputStream.get(), defaultDataSize, new LeaseAccessConditions() + .leaseId(garbageLeaseID), null) + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.LEASE_ID_MISMATCH_WITH_BLOB_OPERATION + } + + def "Stage block error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.stageBlock("id", defaultInputStream.get(), defaultDataSize) + + then: + thrown(StorageException) + } + + def "Stage block from url"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def bu2 = cu.getBlockBlobClient(generateBlobName()) + def blockID = getBlockID() + + when: + HttpHeaders headers = bu2.stageBlockFromURL(blockID, bu.getBlobUrl(), null).headers() + Iterator listResponse = bu2.listBlocks(BlockListType.ALL).iterator() + BlockItem block = listResponse.next() + bu2.commitBlockList(Arrays.asList(blockID)) + ByteArrayOutputStream outputStream = new ByteArrayOutputStream() + bu2.download(outputStream) + + then: + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + headers.value("Content-MD5") != null + headers.value("x-ms-request-server-encrypted") != null + + + block.name() == blockID + !block.isCommitted() + !listResponse.hasNext() + + ByteBuffer.wrap(outputStream.toByteArray()) == defaultData + } + + def "Stage block from url min"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def bu2 = cu.getBlockBlobClient(generateBlobName()) + def blockID = getBlockID() + + expect: + bu2.stageBlockFromURL(blockID, bu.getBlobUrl(), null).statusCode() == 201 + } + + @Unroll + def "Stage block from URL IA"() { + when: + bu.stageBlockFromURL(blockID, sourceURL, null) + + then: + thrown(StorageException) + + where: + blockID | sourceURL + null | new URL("http://www.example.com") + getBlockID() | null + } + + def "Stage block from URL range"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def destURL = cu.getBlockBlobClient(generateBlobName()) + + when: + destURL.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), new BlobRange(2, 3)) + Iterator uncommittedBlock = destURL.listBlocks(BlockListType.UNCOMMITTED).iterator() + + then: + uncommittedBlock.hasNext() + uncommittedBlock.hasNext() + uncommittedBlock.hasNext() + } + + def "Stage block from URL MD5"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def destURL = cu.getBlockBlobClient(generateBlobName()) + + when: + destURL.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), null, + MessageDigest.getInstance("MD5").digest(defaultData.array()), null, null, null) + + then: + notThrown(StorageException) + } + + def "Stage block from URL MD5 fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def destURL = cu.getBlockBlobClient(generateBlobName()) + + when: + destURL.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), null, "garbage".getBytes(), + null, null, null) + + then: + thrown(StorageException) + } + + def "Stage block from URL lease"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def lease = new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, receivedLeaseID)) + + when: + bu.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), null, null, lease, null, null) + + then: + notThrown(StorageException) + } + + def "Stage block from URL lease fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def lease = new LeaseAccessConditions().leaseId("garbage") + + when: + bu.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), null, null, lease, null, null) + + then: + thrown(StorageException) + } + + def "Stage block from URL error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.stageBlockFromURL(getBlockID(), bu.getBlobUrl(), null) + + then: + thrown(StorageException) + } + + @Unroll + def "Stage block from URL source AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def blockID = getBlockID() + + def sourceURL = cu.getBlockBlobClient(generateBlobName()) + sourceURL.upload(defaultInputStream.get(), defaultDataSize) + + sourceIfMatch = setupBlobMatchCondition(sourceURL, sourceIfMatch) + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(sourceIfMatch) + .sourceIfNoneMatch(sourceIfNoneMatch) + + expect: + bu.stageBlockFromURL(blockID, sourceURL.getBlobUrl(), null, null, null, smac, null).statusCode() == 201 + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Stage block from URL source AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def blockID = getBlockID() + + def sourceURL = cu.getBlockBlobClient(generateBlobName()) + sourceURL.upload(defaultInputStream.get(), defaultDataSize) + + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(sourceIfMatch) + .sourceIfNoneMatch(setupBlobMatchCondition(sourceURL, sourceIfNoneMatch)) + + when: + bu.stageBlockFromURL(blockID, sourceURL.getBlobUrl(), null, null, null, smac, null).statusCode() == 201 + + then: + thrown(StorageException) + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Commit block list"() { + setup: + String blockID = getBlockID() + bu.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) + ArrayList ids = new ArrayList<>() + ids.add(blockID) + + when: + Response response = bu.commitBlockList(ids) + HttpHeaders headers = response.headers() + + then: + response.statusCode() == 201 + validateBasicHeaders(headers) + headers.value("Content-MD5") + Boolean.parseBoolean(headers.value("x-ms-request-server-encrypted")) + } + + def "Commit block list min"() { + setup: + String blockID = getBlockID() + bu.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) + ArrayList ids = new ArrayList<>() + ids.add(blockID) + + expect: + bu.commitBlockList(ids).value() != null + } + + def "Commit block list null"() { + expect: + bu.commitBlockList(null).statusCode() == 201 + } + + @Unroll + def "Commit block list headers"() { + setup: + String blockID = getBlockID() + bu.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) + ArrayList ids = new ArrayList<>() + ids.add(blockID) + BlobHTTPHeaders headers = new BlobHTTPHeaders().blobCacheControl(cacheControl) + .blobContentDisposition(contentDisposition) + .blobContentEncoding(contentEncoding) + .blobContentLanguage(contentLanguage) + .blobContentMD5(contentMD5) + .blobContentType(contentType) + + when: + bu.commitBlockList(ids, headers, null, null, null) + Response response = bu.getProperties() + + then: + validateBlobProperties(response, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentMD5, contentType) + + where: + cacheControl | contentDisposition | contentEncoding | contentLanguage | contentMD5 | contentType + null | null | null | null | null | null + // "control" | "disposition" | "encoding" | "language" | MessageDigest.getInstance("MD5").digest(defaultData.array()) | "type" TODO (alzimmer): Figure out why getProperties returns null for this one + } + + @Unroll + def "Commit block list metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + when: + bu.commitBlockList(null, null, metadata, null, null) + Response response = bu.getProperties() + + then: + response.statusCode() == 200 + getMetadataFromHeaders(response.headers()) == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Commit block list AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + expect: + bu.commitBlockList(null, null, null, bac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Commit block list AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.commitBlockList(null, null, null, bac, null) + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.CONDITION_NOT_MET || + e.errorCode() == StorageErrorCode.LEASE_ID_MISMATCH_WITH_BLOB_OPERATION + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Commit block list error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.commitBlockList(new ArrayList(), null, null, + new BlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId("garbage")), null) + + then: + thrown(StorageException) + } + + def "Get block list"() { + setup: + List committedBlocks = Arrays.asList(getBlockID(), getBlockID()) + bu.stageBlock(committedBlocks.get(0), defaultInputStream.get(), defaultDataSize) + bu.stageBlock(committedBlocks.get(1), defaultInputStream.get(), defaultDataSize) + bu.commitBlockList(committedBlocks) + + List uncommittedBlocks = Arrays.asList(getBlockID(), getBlockID()) + bu.stageBlock(uncommittedBlocks.get(0), defaultInputStream.get(), defaultDataSize) + bu.stageBlock(uncommittedBlocks.get(1), defaultInputStream.get(), defaultDataSize) + uncommittedBlocks.sort(true) + + when: + Iterable response = bu.listBlocks(BlockListType.ALL) + + then: + for (BlockItem block : response) { + assert committedBlocks.contains(block.name()) || uncommittedBlocks.contains(block.name()) + assert block.size() == defaultDataSize + } +// for (int i = 0; i < committedBlocks.size(); i++) { +// assert response.body().committedBlocks().get(i).name() == committedBlocks.get(i) +// assert response.body().committedBlocks().get(i).size() == defaultDataSize +// assert response.body().uncommittedBlocks().get(i).name() == uncommittedBlocks.get(i) +// assert response.body().uncommittedBlocks().get(i).size() == defaultDataSize +// } +// validateBasicHeaders(response.headers()) +// response.headers().contentType() != null +// response.headers().blobContentLength() == defaultDataSize * 2L + } + + def "Get block list min"() { + when: + bu.listBlocks(BlockListType.ALL) + + then: + notThrown(StorageErrorException) + } + + @Unroll + def "Get block list type"() { + setup: + String blockID = getBlockID() + bu.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) + ArrayList ids = new ArrayList<>() + ids.add(blockID) + bu.commitBlockList(ids) + blockID = new String(getBlockID()) + bu.stageBlock(blockID, defaultInputStream.get(), defaultDataSize) + + when: + Iterable response = bu.listBlocks(type) + + then: + int committed = 0 + int uncommitted = 0 + for (BlockItem item : response) { + if (item.isCommitted()) { + committed ++ + } else { + uncommitted ++ + } + } + committed == committedCount + uncommitted == uncommittedCount + + where: + type | committedCount | uncommittedCount + BlockListType.ALL | 1 | 1 + BlockListType.COMMITTED | 1 | 0 + BlockListType.UNCOMMITTED | 0 | 1 + } + + def "Get block list type null"() { + when: + bu.listBlocks(null).iterator().hasNext() + + then: + notThrown(IllegalArgumentException) + } + + def "Get block list lease"() { + setup: + String leaseID = setupBlobLeaseCondition(bu, receivedLeaseID) + + when: + bu.listBlocks(BlockListType.ALL, new LeaseAccessConditions().leaseId(leaseID), null).iterator().hasNext() + + then: + notThrown(StorageException) + } + + def "Get block list lease fail"() { + setup: + setupBlobLeaseCondition(bu, garbageLeaseID) + + when: + bu.listBlocks(BlockListType.ALL, new LeaseAccessConditions().leaseId(garbageLeaseID), null).iterator().hasNext() + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.LEASE_ID_MISMATCH_WITH_BLOB_OPERATION + } + + def "Get block list error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.listBlocks(BlockListType.ALL).iterator().hasNext() + + then: + thrown(StorageException) + } + + def "Upload"() { + when: + Response response = bu.upload(defaultInputStream.get(), defaultDataSize) + HttpHeaders headers = response.headers() + + then: + response.statusCode() == 201 + def outStream = new ByteArrayOutputStream() + bu.download(outStream) + outStream.toByteArray() == "default".getBytes(StandardCharsets.UTF_8) + validateBasicHeaders(headers) + headers.value("Content-MD5") != null + Boolean.parseBoolean(headers.value("x-ms-request-server-encrypted")) + } + + def "Upload min"() { + expect: + bu.upload(defaultInputStream.get(), defaultDataSize).statusCode() == 201 + } + + @Unroll + def "Upload illegal argument"() { + when: + bu.upload(data, dataSize) + + then: + def e = thrown(Exception) + exceptionType.isInstance(e) + + where: + data | dataSize | exceptionType + null | defaultDataSize | NullPointerException + defaultInputStream.get() | defaultDataSize + 1 | IndexOutOfBoundsException + // This doesn't error as it isn't reading the entire stream which is valid in the new client + // defaultInputStream.get() | defaultDataSize - 1 | StorageErrorException + } + + def "Upload empty body"() { + expect: + bu.upload(new ByteArrayInputStream(new byte[0]), 0).statusCode() == 201 + } + + def "Upload null body"() { + expect: + bu.upload(null, 0).statusCode() == 201 + } + + // TODO (alzimmer): Determine why getProperties returns null + /*@Unroll + def "Upload headers"() { + setup: + BlobHTTPHeaders headers = new BlobHTTPHeaders().blobCacheControl(cacheControl) + .blobContentDisposition(contentDisposition) + .blobContentEncoding(contentEncoding) + .blobContentLanguage(contentLanguage) + .blobContentMD5(contentMD5) + .blobContentType(contentType) + + when: + bu.upload(defaultInputStream.get(), defaultDataSize, headers, null, null, null) + Response response = bu.getProperties() + + then: + validateBlobProperties(response, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentMD5, contentType) + + where: + cacheControl | contentDisposition | contentEncoding | contentLanguage | contentMD5 | contentType + null | null | null | null | null | null + "control" | "disposition" | "encoding" | "language" | MessageDigest.getInstance("MD5").digest(defaultData.array()) | "type" + }*/ + + @Unroll + def "Upload metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + when: + bu.upload(defaultInputStream.get(), defaultDataSize, null, metadata, null, null) + Response response = bu.getProperties() + + then: + response.statusCode() == 200 + response.value().metadata() == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Upload AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + expect: + bu.upload(defaultInputStream.get(), defaultDataSize, null, null, bac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Upload AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + when: + bu.upload(defaultInputStream.get(), defaultDataSize, null, null, bac, null) + + then: + def e = thrown(StorageException) + e.errorCode() == StorageErrorCode.CONDITION_NOT_MET || + e.errorCode() == StorageErrorCode.LEASE_ID_MISMATCH_WITH_BLOB_OPERATION + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Upload error"() { + setup: + bu = cu.getBlockBlobClient(generateBlobName()) + + when: + bu.upload(defaultInputStream.get(), defaultDataSize, null, null, + new BlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId("id")), + null) + + then: + thrown(StorageException) + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy new file mode 100644 index 0000000000000..7e2e44ef221a8 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/BlockBlobInputOutputStreamTest.groovy @@ -0,0 +1,34 @@ +package com.azure.storage.blob + +class BlockBlobInputOutputStreamTest extends APISpec { + BlockBlobClient bu + + def setup() { + bu = cu.getBlockBlobClient(generateBlobName()) + } + + def "Upload download"() { + when: + int length = 30 * Constants.MB + byte[] randomBytes = new byte[length] + (new Random()).nextBytes(randomBytes) + + BlobOutputStream outStream = bu.getBlobOutputStream() + outStream.write(randomBytes) + outStream.close() + + then: + BlobInputStream inputStream = bu.openInputStream() + int b + ByteArrayOutputStream outputStream = new ByteArrayOutputStream() + try { + while ((b = inputStream.read()) != -1) { + outputStream.write(b) + } + } catch (IOException ex) { + throw new UncheckedIOException(ex) + } + byte[] randomBytes2 = outputStream.toByteArray() + assert randomBytes2 == randomBytes + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy new file mode 100644 index 0000000000000..9b28d87cd7b31 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/ContainerAPITest.groovy @@ -0,0 +1,1636 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + + +import com.azure.core.http.rest.Response +import com.azure.core.http.rest.VoidResponse +import com.azure.storage.blob.models.* +import spock.lang.Unroll + +import java.time.Duration +import java.time.OffsetDateTime +import java.time.ZoneId + +class ContainerAPITest extends APISpec { + + def "Create all null"() { + setup: + // Overwrite the existing cu, which has already been created + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + VoidResponse response = cu.create() + + then: + response.statusCode() == 201 + validateBasicHeaders(response.headers()) + } + + def "Create min"() { + expect: + primaryServiceURL.createContainer(generateContainerName()).statusCode() == 201 + } + + @Unroll + def "Create metadata"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + when: + cu.create(metadata, null, null) + Response response = cu.getProperties() + + then: + getMetadataFromHeaders(response.headers()) == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Create publicAccess"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.create(null, publicAccess, null) + PublicAccessType access = cu.getProperties().value().blobPublicAccess() + + then: + access.toString() == publicAccess.toString() + + where: + publicAccess | _ + PublicAccessType.BLOB | _ + PublicAccessType.CONTAINER | _ + null | _ + } + + def "Create error"() { + when: + cu.create() + + then: + def e = thrown(StorageException) + e.response().statusCode() == 409 + e.errorCode() == StorageErrorCode.CONTAINER_ALREADY_EXISTS + e.message().contains("The specified container already exists.") + } + + def "Get properties null"() { + when: + Response response = cu.getProperties() + + then: + validateBasicHeaders(response.headers()) + response.value().blobPublicAccess() == null + !response.value().hasImmutabilityPolicy() + !response.value().hasLegalHold() + response.headers().value("x-ms-lease-duration") == null + response.headers().value("x-ms-lease-state") == LeaseStateType.AVAILABLE.toString() + response.headers().value("x-ms-lease-status") == LeaseStatusType.UNLOCKED.toString() + getMetadataFromHeaders(response.headers()).size() == 0 + } + + def "Get properties min"() { + expect: + cu.getProperties().statusCode() == 200 + } + + def "Get properties lease"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.getProperties(new LeaseAccessConditions().leaseId(leaseID), null).statusCode() == 200 + } + + def "Get properties lease fail"() { + when: + cu.getProperties(new LeaseAccessConditions().leaseId("garbage"), null) + + then: + thrown(StorageException) + } + + def "Get properties error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.getProperties(null, null) + + then: + thrown(StorageException) + } + + def "Set metadata"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + Metadata metadata = new Metadata() + metadata.put("key", "value") + cu.create(metadata, null, null) + VoidResponse response = cu.setMetadata(null) + + expect: + response.statusCode() == 200 + validateBasicHeaders(response.headers()) + getMetadataFromHeaders(cu.getProperties().headers()).size() == 0 + } + + def "Set metadata min"() { + setup: + Metadata metadata = new Metadata() + metadata.put("foo", "bar") + + when: + cu.setMetadata(metadata) + + then: + getMetadataFromHeaders(cu.getProperties().headers()) == metadata + } + + @Unroll + def "Set metadata metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + expect: + cu.setMetadata(metadata).statusCode() == 200 + getMetadataFromHeaders(cu.getProperties().headers()) == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Set metadata AC"() { + setup: + leaseID = setupContainerLeaseCondition(cu, leaseID) + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified)) + + expect: + cu.setMetadata(null, cac, null).statusCode() == 200 + + where: + modified | leaseID + null | null + oldDate | null + null | receivedLeaseID + } + + @Unroll + def "Set metadata AC fail"() { + setup: + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified)) + + when: + cu.setMetadata(null, cac, null) + + then: + thrown(StorageException) + + where: + modified | leaseID + newDate | null + null | garbageLeaseID + } + + @Unroll + def "Set metadata AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions() + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + cu.setMetadata(null, new ContainerAccessConditions().modifiedAccessConditions(mac), null) + + then: + thrown(UnsupportedOperationException) + + where: + unmodified | match | noneMatch + newDate | null | null + null | receivedEtag | null + null | null | garbageEtag + } + + def "Set metadata error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.setMetadata(null) + + then: + thrown(StorageException) + } + + @Unroll + def "Set access policy"() { + setup: + def response = cu.setAccessPolicy(access, null, null, null) + + expect: + validateBasicHeaders(response.headers()) + cu.getProperties().value().blobPublicAccess() == access + + where: + access | _ + PublicAccessType.BLOB | _ + PublicAccessType.CONTAINER | _ + null | _ + } + + def "Set access policy min access"() { + when: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + + then: + cu.getProperties().value().blobPublicAccess() == PublicAccessType.CONTAINER + } + + def "Set access policy min ids"() { + setup: + SignedIdentifier identifier = new SignedIdentifier() + .id("0000") + .accessPolicy(new AccessPolicy() + .start(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime()) + .expiry(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime() + .plusDays(1)) + .permission("r")) + + List ids = new ArrayList<>() + ids.push(identifier) + + when: + cu.setAccessPolicy(null, ids) + + then: + cu.getAccessPolicy().value().getIdentifiers().get(0).id() == "0000" + } + + def "Set access policy ids"() { + setup: + SignedIdentifier identifier = new SignedIdentifier() + .id("0000") + .accessPolicy(new AccessPolicy() + .start(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime()) + .expiry(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime() + .plusDays(1)) + .permission("r")) + SignedIdentifier identifier2 = new SignedIdentifier() + .id("0001") + .accessPolicy(new AccessPolicy() + .start(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime()) + .expiry(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime() + .plusDays(2)) + .permission("w")) + List ids = new ArrayList<>() + ids.push(identifier) + ids.push(identifier2) + + when: + VoidResponse response = cu.setAccessPolicy(null, ids, null, null) + List receivedIdentifiers = cu.getAccessPolicy().value().getIdentifiers() + + then: + response.statusCode() == 200 + validateBasicHeaders(response.headers()) + receivedIdentifiers.get(0).accessPolicy().expiry() == identifier.accessPolicy().expiry() + receivedIdentifiers.get(0).accessPolicy().start() == identifier.accessPolicy().start() + receivedIdentifiers.get(0).accessPolicy().permission() == identifier.accessPolicy().permission() + receivedIdentifiers.get(1).accessPolicy().expiry() == identifier2.accessPolicy().expiry() + receivedIdentifiers.get(1).accessPolicy().start() == identifier2.accessPolicy().start() + receivedIdentifiers.get(1).accessPolicy().permission() == identifier2.accessPolicy().permission() + } + + @Unroll + def "Set access policy AC"() { + setup: + leaseID = setupContainerLeaseCondition(cu, leaseID) + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified)) + + expect: + cu.setAccessPolicy(null, null, cac, null).statusCode() == 200 + + where: + modified | unmodified | leaseID + null | null | null + oldDate | null | null + null | newDate | null + null | null | receivedLeaseID + } + + @Unroll + def "Set access policy AC fail"() { + setup: + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified)) + + when: + cu.setAccessPolicy(null, null, cac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | leaseID + newDate | null | null + null | oldDate | null + null | null | garbageLeaseID + } + + @Unroll + def "Set access policy AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.setAccessPolicy(null, null, new ContainerAccessConditions().modifiedAccessConditions(mac), null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Set access policy error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.setAccessPolicy(null, null, null, null) + + then: + thrown(StorageException) + } + + def "Get access policy"() { + setup: + SignedIdentifier identifier = new SignedIdentifier() + .id("0000") + .accessPolicy(new AccessPolicy() + .start(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime()) + .expiry(OffsetDateTime.now().atZoneSameInstant(ZoneId.of("UTC")).toOffsetDateTime() + .plusDays(1)) + .permission("r")) + List ids = new ArrayList<>() + ids.push(identifier) + cu.setAccessPolicy(PublicAccessType.BLOB, ids) + Response response = cu.getAccessPolicy() + + expect: + response.statusCode() == 200 + response.value().getBlobAccessType() == PublicAccessType.BLOB + validateBasicHeaders(response.headers()) + response.value().getIdentifiers().get(0).accessPolicy().expiry() == identifier.accessPolicy().expiry() + response.value().getIdentifiers().get(0).accessPolicy().start() == identifier.accessPolicy().start() + response.value().getIdentifiers().get(0).accessPolicy().permission() == identifier.accessPolicy().permission() + } + + def "Get access policy lease"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.getAccessPolicy(new LeaseAccessConditions().leaseId(leaseID), null).statusCode() == 200 + } + + def "Get access policy lease fail"() { + when: + cu.getAccessPolicy(new LeaseAccessConditions().leaseId(garbageLeaseID), null) + + then: + thrown(StorageException) + } + + def "Get access policy error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.getAccessPolicy() + + then: + thrown(StorageException) + } + + def "Delete"() { + when: + VoidResponse response = cu.delete() + + then: + response.statusCode() == 202 + response.headers().value("x-ms-request-id") != null + response.headers().value("x-ms-version") != null + response.headers().value("Date") != null + } + + def "Delete min"() { + expect: + cu.delete().statusCode() == 202 + } + + @Unroll + def "Delete AC"() { + setup: + leaseID = setupContainerLeaseCondition(cu, leaseID) + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified)) + + expect: + cu.delete(cac, null).statusCode() == 202 + + where: + modified | unmodified | leaseID + null | null | null + oldDate | null | null + null | newDate | null + null | null | receivedLeaseID + } + + @Unroll + def "Delete AC fail"() { + setup: + ContainerAccessConditions cac = new ContainerAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified)) + + when: + cu.delete(cac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | leaseID + newDate | null | null + null | oldDate | null + null | null | garbageLeaseID + } + + @Unroll + def "Delete AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.delete(new ContainerAccessConditions().modifiedAccessConditions(mac), null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Delete error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.delete(null, null) + + then: + thrown(StorageException) + } + + def "List blobs flat"() { + setup: + String name = generateBlobName() + PageBlobClient bu = cu.getPageBlobClient(name) + bu.create(512) + + when: + Iterator blobs = cu.listBlobsFlat().iterator() + + //ContainerListBlobFlatSegmentHeaders headers = response.headers() + //List blobs = responseiterator()() + + then: +// response.statusCode() == 200 +// headers.contentType() != null +// headers.requestId() != null +// headers.version() != null +// headers.date() != null + BlobItem blob = blobs.next() + !blobs.hasNext() + blob.name() == name + blob.properties().blobType() == BlobType.PAGE_BLOB + blob.properties().copyCompletionTime() == null + blob.properties().copyStatusDescription() == null + blob.properties().copyId() == null + blob.properties().copyProgress() == null + blob.properties().copySource() == null + blob.properties().copyStatus() == null + blob.properties().incrementalCopy() == null + blob.properties().destinationSnapshot() == null + blob.properties().leaseDuration() == null + blob.properties().leaseState() == LeaseStateType.AVAILABLE + blob.properties().leaseStatus() == LeaseStatusType.UNLOCKED + blob.properties().contentLength() != null + blob.properties().contentType() != null + blob.properties().contentMD5() == null + blob.properties().contentEncoding() == null + blob.properties().contentDisposition() == null + blob.properties().contentLanguage() == null + blob.properties().cacheControl() == null + blob.properties().blobSequenceNumber() == 0 + blob.properties().serverEncrypted() + blob.properties().accessTierInferred() + blob.properties().accessTier() == AccessTier.HOT + blob.properties().archiveStatus() == null + blob.properties().creationTime() != null + } + + def "List blobs flat min"() { + when: + cu.listBlobsFlat().iterator().hasNext() + + then: + notThrown(StorageException) + } + + def setupListBlobsTest(String normalName, String copyName, String metadataName, String uncommittedName) { + PageBlobClient normal = cu.getPageBlobClient(normalName) + normal.create(512) + + PageBlobClient copyBlob = cu.getPageBlobClient(copyName) + + String status = copyBlob.startCopyFromURL(normal.getBlobUrl()).value() + OffsetDateTime start = OffsetDateTime.now() + while (status != CopyStatusType.SUCCESS.toString()) { + status = copyBlob.getProperties().headers().value("x-ms-copy-status") + OffsetDateTime currentTime = OffsetDateTime.now() + if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { + throw new Exception("Copy failed or took too long") + } + sleep(1000) + } + + PageBlobClient metadataBlob = cu.getPageBlobClient(metadataName) + Metadata values = new Metadata() + values.put("foo", "bar") + metadataBlob.create(512, null, null, values, null, null) + + String snapshotTime = normal.createSnapshot().value() + + BlockBlobClient uncommittedBlob = cu.getBlockBlobClient(uncommittedName) + + uncommittedBlob.stageBlock("0000", defaultInputStream.get(), defaultData.remaining()) + + return snapshotTime + } + + def blobListResponseToList(Iterator blobs) { + ArrayList blobQueue = new ArrayList<>() + while (blobs.hasNext()) { + blobQueue.add(blobs.next()) + } + + return blobQueue + } + + def "List blobs flat options copy"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().copy(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsFlat(options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(1).name() == copyName + blobs.get(1).properties().copyId() != null + // Comparing the urls isn't reliable because the service may use https. + blobs.get(1).properties().copySource().contains(normalName) + blobs.get(1).properties().copyStatus() == CopyStatusType.SUCCESS // We waited for the copy to complete. + blobs.get(1).properties().copyProgress() != null + blobs.get(1).properties().copyCompletionTime() != null + blobs.size() == 3 // Normal, copy, metadata + } + + def "List blobs flat options metadata"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().metadata(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsFlat(options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(1).name() == copyName + blobs.get(1).properties().copyCompletionTime() == null + blobs.get(2).name() == metadataName + blobs.get(2).metadata().get("foo") == "bar" + blobs.size() == 3 // Normal, copy, metadata + } + + def "List blobs flat options snapshots"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().snapshots(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + String snapshotTime = setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsFlat(options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(0).snapshot() == snapshotTime + blobs.get(1).name() == normalName + blobs.size() == 4 // Normal, snapshot, copy, metadata + } + + def "List blobs flat options uncommitted"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().uncommittedBlobs(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsFlat(options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(3).name() == uncommittedName + blobs.size() == 4 // Normal, copy, metadata, uncommitted + } + + def "List blobs flat options deleted"() { + setup: + enableSoftDelete() + String name = generateBlobName() + AppendBlobClient bu = cu.getAppendBlobClient(name) + bu.create() + bu.delete() + + when: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().deletedBlobs(true)) + Iterator blobs = cu.listBlobsFlat(options, null).iterator() + + then: + blobs.next().name() == name + !blobs.hasNext() + + disableSoftDelete() == null // Must produce a true value or test will fail. + } + + def "List blobs flat options prefix"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().prefix("a") + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + Iterator blobs = cu.listBlobsFlat(options, null).iterator() + + then: + blobs.next().name() == normalName + !blobs.hasNext() // Normal + } + + // TODO (alzimmer): Turn this on once paged responses are available + /*def "List blobs flat options maxResults"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().copy(true) + .snapshots(true).uncommittedBlobs(true)).maxResults(2) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + Iterator blobs = cu.listBlobsFlat(options, null).iterator() + + then: + blobs.size() == 2 + }*/ + + def "List blobs flat options fail"() { + when: + new ListBlobsOptions().maxResults(0) + + then: + thrown(IllegalArgumentException) + } + + // TODO (alzimmer): Turn this on once paged responses are available + /*def "List blobs flat marker"() { + setup: + for (int i = 0; i < 10; i++) { + PageBlobClient bu = cu.getPageBlobClient(generateBlobName()) + bu.create(512) + } + + Iterator response = cu.listBlobsFlat(new ListBlobsOptions().maxResults(6), null) + + String marker = response.body().nextMarker() + int firstSegmentSize = response.iterator().size() + response = cu.listBlobsFlat(marker, null, null) + + expect: + firstSegmentSize == 6 + response.body().nextMarker() == null + responseiterator()().size() == 4 + }*/ + + def "List blobs flat error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.listBlobsFlat().iterator().hasNext() + + then: + thrown(StorageException) + } + + def "List blobs hierarchy"() { + setup: + String name = generateBlobName() + PageBlobClient bu = cu.getPageBlobClient(name) + bu.create(512) + + when: + Iterator blobs = cu.listBlobsHierarchy(null).iterator() + + then: +// response.statusCode() == 200 +// headers.contentType() != null +// headers.requestId() != null +// headers.version() != null +// headers.date() != null + blobs.next().name() == name + !blobs.hasNext() + } + + def "List blobs hierarchy min"() { + when: + cu.listBlobsHierarchy("/").iterator().hasNext() + + then: + notThrown(StorageException) + } + + def "List blobs hier options copy"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().copy(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsHierarchy("", options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(1).name() == copyName + blobs.get(1).properties().copyId() != null + // Comparing the urls isn't reliable because the service may use https. + blobs.get(1).properties().copySource().contains(normalName) + blobs.get(1).properties().copyStatus() == CopyStatusType.SUCCESS // We waited for the copy to complete. + blobs.get(1).properties().copyProgress() != null + blobs.get(1).properties().copyCompletionTime() != null + blobs.size() == 3 // Normal, copy, metadata + } + + def "List blobs hier options metadata"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().metadata(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsHierarchy("", options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(1).name() == copyName + blobs.get(1).properties().copyCompletionTime() == null + blobs.get(2).name() == metadataName + blobs.get(2).metadata().get("foo") == "bar" + blobs.size() == 3 // Normal, copy, metadata + } + + def "List blobs hier options uncommitted"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().uncommittedBlobs(true)) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + List blobs = blobListResponseToList(cu.listBlobsHierarchy("", options, null).iterator()) + + then: + blobs.get(0).name() == normalName + blobs.get(3).name() == uncommittedName + blobs.size() == 4 // Normal, copy, metadata, uncommitted + } + + def "List blobs hier options deleted"() { + setup: + enableSoftDelete() + String name = generateBlobName() + AppendBlobClient bu = cu.getAppendBlobClient(name) + bu.create() + bu.delete() + + when: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().deletedBlobs(true)) + Iterator blobs = cu.listBlobsHierarchy("", options, null).iterator() + + then: + blobs.next().name() == name + !blobs.hasNext() + + disableSoftDelete() == null + } + + def "List blobs hier options prefix"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().prefix("a") + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + Iterator blobs = cu.listBlobsHierarchy("", options, null).iterator() + + then: + blobs.next().name() == normalName + !blobs.hasNext() // Normal + } + + // TODO (alzimmer): Turn this on when paged responses becomes available + /*def "List blobs hier options maxResults"() { + setup: + ListBlobsOptions options = new ListBlobsOptions().details(new BlobListDetails().copy(true) + .uncommittedBlobs(true)).maxResults(1) + String normalName = "a" + generateBlobName() + String copyName = "c" + generateBlobName() + String metadataName = "m" + generateBlobName() + String uncommittedName = "u" + generateBlobName() + setupListBlobsTest(normalName, copyName, metadataName, uncommittedName) + + when: + Iterator blobs = cu.listBlobsHierarchy("", options, null).iterator() + + then: + blobs.size() == 1 + }*/ + + @Unroll + def "List blobs hier options fail"() { + when: + def options = new ListBlobsOptions().details(new BlobListDetails().snapshots(snapshots)) + .maxResults(maxResults) + cu.listBlobsHierarchy(null, options, null).iterator().hasNext() + + then: + def e = thrown(Exception) + exceptionType.isInstance(e) + + where: + snapshots | maxResults | exceptionType + true | 5 | UnsupportedOperationException + false | 0 | IllegalArgumentException + } + + def "List blobs hier delim"() { + setup: + def blobNames = Arrays.asList("a", "b/a", "c", "d/a", "e", "f", "g/a") + for (String blobName : blobNames) { + def bu = cu.getAppendBlobClient(blobName) + bu.create() + } + + when: + Iterator blobs = cu.listBlobsHierarchy(null).iterator() + + and: + ArrayDeque expectedBlobs = new ArrayDeque<>() + expectedBlobs.add("a") + expectedBlobs.add("c") + expectedBlobs.add("e") + expectedBlobs.add("f") + + ArrayDeque expectedPrefixes = new ArrayDeque<>() + expectedPrefixes.add("b/") + expectedPrefixes.add("d/") + expectedPrefixes.add("g/") + + then: + while (blobs.hasNext()) { + BlobItem blob = blobs.next() + + if (blob.isPrefix()) { + blob.name() == expectedPrefixes.pop() + } else { + blob.name() == expectedBlobs.pop() + } + } + + expectedPrefixes.isEmpty() + expectedBlobs.isEmpty() + } + + // TODO (alzimmer): Turn this on when paged response become available + /*def "List blobs hier marker"() { + setup: + for (int i = 0; i < 10; i++) { + PageBlobClient bu = cu.getPageBlobClient(generateBlobName()) + bu.create(512) + } + + ContainerListBlobHierarchySegmentResponse response = cu.listBlobsHierarchySegment(null, "/", + new ListBlobsOptions().maxResults(6), null) + + String marker = response.body().nextMarker() + int firstSegmentSize = responseiterator()().size() + response = cu.listBlobsHierarchySegment(marker, "/", null, null) + + expect: + firstSegmentSize == 6 + response.body().nextMarker() == null + response.iterator().size() == 4 + }*/ + + def "List blobs flat simple"() { + setup: + // Create 10 page blobs in the container + for (int i = 0; i < 10; i++) { + PageBlobClient bu = cu.getPageBlobClient(generateBlobName()) + bu.create(512) + } + // Setting maxResult limits the number of items per page, this way we validate + // that blob.size() make multiple calls - one call per page to retrieve all 10 blobs. + // + Iterable blobs = cu.listBlobsFlat(new ListBlobsOptions().maxResults(3), null) + int size = blobs.size() + + expect: + size == 10 + } + + def "List blobs hier error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.listBlobsHierarchy(".").iterator().hasNext() + + then: + thrown(StorageException) + } + + @Unroll + def "Acquire lease"() { + setup: + Response leaseResponse = cu.acquireLease(proposedID, leaseTime) + + when: + Response propertiesResponse = cu.getProperties() + + then: + leaseResponse.value() != null + validateBasicHeaders(leaseResponse.headers()) + propertiesResponse.headers().value("x-ms-lease-state") == leaseState.toString() + propertiesResponse.headers().value("x-ms-lease-duration") == leaseDuration.toString() + + where: + proposedID | leaseTime || leaseState | leaseDuration + null | -1 || LeaseStateType.LEASED | LeaseDurationType.INFINITE + null | 25 || LeaseStateType.LEASED | LeaseDurationType.FIXED + UUID.randomUUID().toString() | -1 || LeaseStateType.LEASED | LeaseDurationType.INFINITE + } + + def "Acquire lease min"() { + expect: + cu.acquireLease(null, -1).statusCode() == 201 + } + + @Unroll + def "Acquire lease AC"() { + setup: + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + expect: + cu.acquireLease(null, -1, mac, null).statusCode() == 201 + + where: + modified | unmodified + null | null + oldDate | null + null | newDate + } + + @Unroll + def "Acquire lease AC fail"() { + setup: + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + when: + cu.acquireLease(null, -1, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified + newDate | null + null | oldDate + } + + @Unroll + def "Acquire lease AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.acquireLease(null, -1, mac, null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Acquire lease error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.acquireLease(null, 50, null, null) + + then: + thrown(StorageException) + } + + def "Renew lease"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + Thread.sleep(16000) // Wait for the lease to expire to ensure we are actually renewing it + Response renewLeaseResponse = cu.renewLease(leaseID) + + expect: + renewLeaseResponse.value() != null + cu.getProperties().headers().value("x-ms-lease-state") == LeaseStateType.LEASED.toString() + validateBasicHeaders(renewLeaseResponse.headers()) + } + + def "Renew lease min"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.renewLease(leaseID).statusCode() == 200 + } + + @Unroll + def "Renew lease AC"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + expect: + cu.renewLease(leaseID, mac, null).statusCode() == 200 + + where: + modified | unmodified + null | null + oldDate | null + null | newDate + } + + @Unroll + def "Renew lease AC fail"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + when: + cu.renewLease(leaseID, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified + newDate | null + null | oldDate + } + + @Unroll + def "Renew lease AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.renewLease(receivedLeaseID, mac, null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Renew lease error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.renewLease("id") + + then: + thrown(StorageException) + } + + def "Release lease"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + VoidResponse releaseLeaseResponse = cu.releaseLease(leaseID) + + expect: + cu.getProperties().headers().value("x-ms-lease-state") == LeaseStateType.AVAILABLE.toString() + validateBasicHeaders(releaseLeaseResponse.headers()) + } + + def "Release lease min"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.releaseLease(leaseID).statusCode() == 200 + } + + @Unroll + def "Release lease AC"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + expect: + cu.releaseLease(leaseID, mac, null).statusCode() == 200 + + where: + modified | unmodified + null | null + oldDate | null + null | newDate + } + + @Unroll + def "Release lease AC fail"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + when: + cu.releaseLease(leaseID, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified + newDate | null + null | oldDate + } + + @Unroll + def "Release lease AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.releaseLease(receivedLeaseID, mac, null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Release lease error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.releaseLease("id") + + then: + thrown(StorageException) + } + + @Unroll + def "Break lease"() { + setup: + cu.acquireLease(UUID.randomUUID().toString(), leaseTime) + + Response breakLeaseResponse = cu.breakLease(breakPeriod, null, null) + LeaseStateType state = LeaseStateType.fromString(cu.getProperties().headers().value("x-ms-lease-state")) + + expect: + state == LeaseStateType.BROKEN || state == LeaseStateType.BREAKING + breakLeaseResponse.value().getSeconds() <= remainingTime + validateBasicHeaders(breakLeaseResponse.headers()) + if (breakPeriod != null) { + sleep(breakPeriod * 1000) // so we can delete the container after the test completes + } + + where: + leaseTime | breakPeriod | remainingTime + -1 | null | 0 + -1 | 20 | 25 + 20 | 15 | 16 + + } + + def "Break lease min"() { + setup: + setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.breakLease().statusCode() == 202 + } + + @Unroll + def "Break lease AC"() { + setup: + setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + expect: + cu.breakLease(null, mac, null).statusCode() == 202 + + where: + modified | unmodified + null | null + oldDate | null + null | newDate + } + + @Unroll + def "Break lease AC fail"() { + setup: + setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + when: + cu.breakLease(null, mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified + newDate | null + null | oldDate + } + + @Unroll + def "Break lease AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.breakLease(null, mac, null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Break lease error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.breakLease() + + then: + thrown(StorageException) + } + + def "Change lease"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + Response changeLeaseResponse = cu.changeLease(leaseID, UUID.randomUUID().toString()) + leaseID = changeLeaseResponse.value() + + expect: + cu.releaseLease(leaseID).statusCode() == 200 + validateBasicHeaders(changeLeaseResponse.headers()) + } + + def "Change lease min"() { + setup: + def leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + + expect: + cu.changeLease(leaseID, UUID.randomUUID().toString()).statusCode() == 200 + } + + @Unroll + def "Change lease AC"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + expect: + cu.changeLease(leaseID, UUID.randomUUID().toString(), mac, null).statusCode() == 200 + + where: + modified | unmodified + null | null + oldDate | null + null | newDate + } + + @Unroll + def "Change lease AC fail"() { + setup: + String leaseID = setupContainerLeaseCondition(cu, receivedLeaseID) + def mac = new ModifiedAccessConditions().ifModifiedSince(modified).ifUnmodifiedSince(unmodified) + + when: + cu.changeLease(leaseID, UUID.randomUUID().toString(), mac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified + newDate | null + null | oldDate + } + + @Unroll + def "Change lease AC illegal"() { + setup: + ModifiedAccessConditions mac = new ModifiedAccessConditions().ifMatch(match).ifNoneMatch(noneMatch) + + when: + cu.changeLease(receivedLeaseID, garbageLeaseID, mac, null) + + then: + thrown(UnsupportedOperationException) + + where: + match | noneMatch + receivedEtag | null + null | garbageEtag + } + + def "Change lease error"() { + setup: + cu = primaryServiceURL.getContainerClient(generateContainerName()) + + when: + cu.changeLease("id", "id") + + then: + thrown(StorageException) + } + + @Unroll + def "Create URL special chars"() { + // This test checks that we encode special characters in blob names correctly. + setup: + AppendBlobClient bu2 = cu.getAppendBlobClient(name) + PageBlobClient bu3 = cu.getPageBlobClient(name + "2") + BlockBlobClient bu4 = cu.getBlockBlobClient(name + "3") + BlockBlobClient bu5 = cu.getBlockBlobClient(name) + + expect: + bu2.create().statusCode() == 201 + bu5.getProperties().statusCode() == 200 + bu3.create(512).statusCode() == 201 + bu4.upload(defaultInputStream.get(), defaultDataSize).statusCode() == 201 + + when: + Iterator blobs = cu.listBlobsFlat().iterator() + + then: + blobs.next().name() == name + blobs.next().name() == name + "2" + blobs.next().name() == name + "3" + + where: + name | _ + // "中文" | _ TODO: requires blob name to be url encoded, deferred for post preview-1, storage team to decide on encoding story across SDKS + "az[]" | _ + // "hello world" | _ TODO: see previous TODO + "hello/world" | _ + "hello&world" | _ + // "!*'();:@&=+\$,/?#[]" | _ TODO: see previous TODO + } + + def "Root explicit"() { + setup: + cu = primaryServiceURL.getContainerClient(ContainerClient.ROOT_CONTAINER_NAME) + // Create root container if not exist. + if (!cu.exists().value()) { + cu.create() + } + + AppendBlobClient bu = cu.getAppendBlobClient("rootblob") + + expect: + bu.create().statusCode() == 201 + } + + def "Root explicit in endpoint"() { + setup: + cu = primaryServiceURL.getContainerClient(ContainerClient.ROOT_CONTAINER_NAME) + // Create root container if not exist. + if (!cu.exists().value()) { + cu.create() + } + + AppendBlobClient bu = new AppendBlobClientBuilder() + .credential(primaryCreds) + .endpoint("http://" + primaryCreds.accountName() + ".blob.core.windows.net/\$root/rootblob") + .httpClient(getHttpClient()) + .buildClient() + + when: + Response createResponse = bu.create() + + Response propsResponse = bu.getProperties() + + then: + createResponse.statusCode() == 201 + propsResponse.statusCode() == 200 + propsResponse.value().blobType() == BlobType.APPEND_BLOB + } + + /* + def "Root implicit"() { + setup: + cu = primaryServiceURL.getContainerClient(ContainerClient.ROOT_CONTAINER_NAME) + // Create root container if not exist. + if (!cu.exists().value()) { + cu.create() + } + + AppendBlobClient bu = new AppendBlobClientBuilder() + .credential(primaryCreds) + .endpoint("http://" + primaryCreds.accountName() + ".blob.core.windows.net/rootblob") + .httpClient(getHttpClient()) + .buildClient() + + when: + Response createResponse = bu.create() + + Response propsResponse = bu.getProperties() + + then: + createResponse.statusCode() == 201 + propsResponse.statusCode() == 200 + propsResponse.value().blobType() == BlobType.APPEND_BLOB + } + */ + + def "Web container"() { + setup: + cu = primaryServiceURL.getContainerClient(ContainerClient.STATIC_WEBSITE_CONTAINER_NAME) + // Create root container if not exist. + try { + cu.create(null, null, null) + } + catch (StorageException se) { + if (se.errorCode() != StorageErrorCode.CONTAINER_ALREADY_EXISTS) { + throw se + } + } + def webContainer = primaryServiceURL.getContainerClient(ContainerClient.STATIC_WEBSITE_CONTAINER_NAME) + + when: + // Validate some basic operation. + webContainer.setAccessPolicy(null, null) + + then: + notThrown(StorageException) + } + + def "Get account info"() { + when: + Response response = primaryServiceURL.getAccountInfo() + + then: + response.headers().value("Date") != null + response.headers().value("x-ms-version") != null + response.headers().value("x-ms-request-id") != null + response.value().accountKind() != null + response.value().skuName() != null + } + + def "Get account info min"() { + expect: + primaryServiceURL.getAccountInfo().statusCode() == 200 + } + + def "Get account info error"() { + when: + StorageClient serviceURL = new StorageClientBuilder() + .endpoint(primaryServiceURL.getAccountUrl().toString()) + .buildClient() + + serviceURL.getContainerClient(generateContainerName()).getAccountInfo() + + then: + thrown(StorageException) + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/LargeFileTest.java b/storage/client/blob/src/test/java/com/azure/storage/blob/LargeFileTest.java new file mode 100644 index 0000000000000..a692d6d4c3c34 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/LargeFileTest.java @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.storage.common.credentials.SharedKeyCredential; + +import java.io.File; +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.Random; + +public class LargeFileTest { + private static final Random RANDOM = new Random(); + private static final String FILE_PATH = "C:\\Users\\jianghlu\\10g.dat"; + private static StorageClient storageClient; + private static ContainerClient containerClient; + + //@BeforeClass + public static void setup() { + storageClient = new StorageClientBuilder() + .credential(new SharedKeyCredential(System.getenv("ACCOUNT_NAME"), System.getenv("ACCOUNT_KEY"))) + .endpoint("https://" + System.getenv("ACCOUNT_NAME") + ".blob.core.windows.net") +// .httpClient(HttpClient.createDefault().proxy(() -> new ProxyOptions(Type.HTTP, new InetSocketAddress("localhost", 8888)))) + .buildClient(); + + containerClient = storageClient.getContainerClient("testcontainer-10g"); + if (!containerClient.exists().value()) { + containerClient.create(); + } + } + + //@Test + public void uploadLargeBlockBlob() throws Exception { + BlockBlobClient blockBlobClient = containerClient.getBlockBlobClient("testblob" + RANDOM.nextInt(1000)); + blockBlobClient.uploadFromFile(FILE_PATH); + } + + //@Test + public void downloadLargeBlockBlob() throws Exception { + OffsetDateTime start = OffsetDateTime.now(); + BlockBlobClient blockBlobClient = containerClient.getBlockBlobClient("testblob-10g"); +// blockBlobClient.uploadFromFile(filePath); +// File uploadedFile = new File(filePath); +// System.out.println("Upload " + uploadedFile.length() + " bytes took " + Duration.between(start, OffsetDateTime.now()).getSeconds() + " seconds"); +// start = OffsetDateTime.now(); + String downloadName = "D:\\10g-downloaded.dat"; + File downloaded = new File(downloadName); + downloaded.createNewFile(); + blockBlobClient.downloadToFile(downloadName); + System.out.println("Download " + downloaded.length() + " bytes took " + Duration.between(start, OffsetDateTime.now()).getSeconds() + " seconds"); + downloaded.delete(); + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy new file mode 100644 index 0000000000000..eee346b007288 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/PageBlobAPITest.groovy @@ -0,0 +1,1100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + +import com.azure.core.http.rest.Response +import com.azure.storage.blob.models.* +import spock.lang.Unroll + +import java.security.MessageDigest +import java.time.OffsetDateTime + +class PageBlobAPITest extends APISpec { + PageBlobClient bu + + def setup() { + bu = cu.getPageBlobClient(generateBlobName()) + bu.create(PageBlobClient.PAGE_BYTES) + } + + def "Create all null"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + Response response = bu.create(PageBlobClient.PAGE_BYTES) + + then: + response.statusCode() == 201 + validateBasicHeaders(response.headers()) + response.value().contentMD5() == null + response.value().isServerEncrypted() + } + + def "Create min"() { + expect: + bu.create(PageBlobClient.PAGE_BYTES).statusCode() == 201 + } + + def "Create sequence number"() { + when: + bu.create(PageBlobClient.PAGE_BYTES, 2, null, null, + null, null) + + then: + Integer.parseInt(bu.getProperties().headers().value("x-ms-blob-sequence-number")) == 2 + } + + @Unroll + def "Create headers"() { + setup: + BlobHTTPHeaders headers = new BlobHTTPHeaders().blobCacheControl(cacheControl) + .blobContentDisposition(contentDisposition) + .blobContentEncoding(contentEncoding) + .blobContentLanguage(contentLanguage) + .blobContentMD5(contentMD5) + .blobContentType(contentType) + + when: + bu.create(PageBlobClient.PAGE_BYTES, null, headers, null, null, null) + + Response response = bu.getProperties(null, null) + + then: + validateBlobProperties(response, cacheControl, contentDisposition, contentEncoding, contentLanguage, contentMD5, contentType) + + where: + cacheControl | contentDisposition | contentEncoding | contentLanguage | contentMD5 | contentType + null | null | null | null | null | null + // "control" | "disposition" | "encoding" | "language" | Base64.getEncoder().encode(MessageDigest.getInstance("MD5").digest(defaultData.array())) | "type" TODO (alzimmer): Determine why getProperties returns null + } + + @Unroll + def "Create metadata"() { + setup: + Metadata metadata = new Metadata() + if (key1 != null) { + metadata.put(key1, value1) + } + if (key2 != null) { + metadata.put(key2, value2) + } + + when: + bu.create(PageBlobClient.PAGE_BYTES, null, null, metadata, null, null) + + Response response = bu.getProperties(null, null) + + then: + response.statusCode() == 200 + response.value().metadata() == metadata + + where: + key1 | value1 | key2 | value2 + null | null | null | null + "foo" | "bar" | "fizz" | "buzz" + } + + @Unroll + def "Create AC"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + + expect: + bu.create(PageBlobClient.PAGE_BYTES, null, null, null, bac, null) + .statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Create AC fail"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.create(PageBlobClient.PAGE_BYTES, null, null, null, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Create error"() { + when: + bu.create(PageBlobClient.PAGE_BYTES, null, null, null, + new BlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId("id")), null) + + then: + thrown(StorageException) + } + + def "Upload page"() { + when: + Response response = bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + then: + response.statusCode() == 201 + validateBasicHeaders(response.headers()) + response.value().contentMD5() != null + response.value().blobSequenceNumber() == 0 + response.value().isServerEncrypted() + } + + def "Upload page min"() { + expect: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))).statusCode() == 201 + } + + @Unroll + def "Upload page IA"() { + when: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES * 2 - 1), data) + + then: + def e = thrown(Exception) + exceptionType.isInstance(e) + + where: + data | exceptionType + null | NullPointerException + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)) | IndexOutOfBoundsException + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES * 3)) | StorageException + } + + @Unroll + def "Upload page AC"() { + setup: + PageBlobAccessConditions pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + expect: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), pac, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + null | null | null | null | null | null | null | null + oldDate | null | null | null | null | null | null | null + null | newDate | null | null | null | null | null | null + null | null | receivedEtag | null | null | null | null | null + null | null | null | garbageEtag | null | null | null | null + null | null | null | null | receivedLeaseID | null | null | null + null | null | null | null | null | 5 | null | null + null | null | null | null | null | null | 3 | null + null | null | null | null | null | null | null | 0 + } + + @Unroll + def "Upload page AC fail"() { + setup: + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + PageBlobAccessConditions pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + when: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), pac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + newDate | null | null | null | null | null | null | null + null | oldDate | null | null | null | null | null | null + null | null | garbageEtag | null | null | null | null | null + null | null | null | receivedEtag | null | null | null | null + null | null | null | null | garbageLeaseID | null | null | null + null | null | null | null | null | -1 | null | null + null | null | null | null | null | null | -1 | null + null | null | null | null | null | null | null | 100 + } + + def "Upload page error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), + new PageBlobAccessConditions().leaseAccessConditions(new LeaseAccessConditions().leaseId("id")), + null) + + then: + thrown(StorageException) + } + + def "Upload page from URL min"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null) + def destURL = cu.getPageBlobClient(generateBlobName()) + destURL.create(PageBlobClient.PAGE_BYTES) + destURL.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + + when: + Response response = bu.uploadPagesFromURL(pageRange, destURL.getBlobUrl(), null) + + then: + response.statusCode() == 201 + validateBasicHeaders(response.headers()) + } + + def "Upload page from URL range"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + + byte[] data = getRandomByteArray(PageBlobClient.PAGE_BYTES * 4) + + def sourceURL = cu.getPageBlobClient(generateBlobName()) + sourceURL.create(PageBlobClient.PAGE_BYTES * 4) + sourceURL.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES * 4 - 1), + new ByteArrayInputStream(data)) + + def destURL = cu.getPageBlobClient(generateBlobName()) + destURL.create(PageBlobClient.PAGE_BYTES * 2) + + when: + destURL.uploadPagesFromURL(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES * 2 - 1), + sourceURL.getBlobUrl(), PageBlobClient.PAGE_BYTES * 2) + + then: + ByteArrayOutputStream outputStream = new ByteArrayOutputStream() + destURL.download(outputStream) + outputStream.toByteArray() == Arrays.copyOfRange(data, PageBlobClient.PAGE_BYTES * 2, PageBlobClient.PAGE_BYTES * 4) + } + + @Unroll + def "Upload page from URL IA"() { + when: + bu.uploadPagesFromURL(range, bu.getBlobUrl(), sourceOffset) + + then: + thrown(IllegalArgumentException) + + where: + sourceOffset | range + (Long)PageBlobClient.PAGE_BYTES | null + } + + def "Upload page from URL MD5"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + def destURL = cu.getPageBlobClient(generateBlobName()) + destURL.create(PageBlobClient.PAGE_BYTES) + def data = getRandomByteArray(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + bu.uploadPages(pageRange, new ByteArrayInputStream(data)) + + when: + destURL.uploadPagesFromURL(pageRange, bu.getBlobUrl(), null, MessageDigest.getInstance("MD5").digest(data), + null, null, null) + + then: + notThrown(StorageException) + } + + def "Upload page from URL MD5 fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + def destURL = cu.getPageBlobClient(generateBlobName()) + destURL.create(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + bu.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + when: + destURL.uploadPagesFromURL(pageRange, bu.getBlobUrl(), null, + MessageDigest.getInstance("MD5").digest("garbage".getBytes()), null, null, null) + + then: + thrown(StorageException) + } + + @Unroll + def "Upload page from URL destination AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + def sourceURL = cu.getPageBlobClient(generateBlobName()) + sourceURL.create(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + def pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + expect: + bu.uploadPagesFromURL(pageRange, sourceURL.getBlobUrl(), null, null, pac, null, null).statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + null | null | null | null | null | null | null | null + oldDate | null | null | null | null | null | null | null + null | newDate | null | null | null | null | null | null + null | null | receivedEtag | null | null | null | null | null + null | null | null | garbageEtag | null | null | null | null + null | null | null | null | receivedLeaseID | null | null | null + null | null | null | null | null | 5 | null | null + null | null | null | null | null | null | 3 | null + null | null | null | null | null | null | null | 0 + } + + @Unroll + def "Upload page from URL destination AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + + def sourceURL = cu.getPageBlobClient(generateBlobName()) + sourceURL.create(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + noneMatch = setupBlobMatchCondition(bu, noneMatch) + def pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + when: + bu.uploadPagesFromURL(pageRange, sourceURL.getBlobUrl(), null, null, pac, null, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + newDate | null | null | null | null | null | null | null + null | oldDate | null | null | null | null | null | null + null | null | garbageEtag | null | null | null | null | null + null | null | null | receivedEtag | null | null | null | null + null | null | null | null | garbageLeaseID | null | null | null + null | null | null | null | null | -1 | null | null + null | null | null | null | null | null | -1 | null + null | null | null | null | null | null | null | 100 + } + + @Unroll + def "Upload page from URL source AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + def sourceURL = cu.getPageBlobClient(generateBlobName()) + sourceURL.create(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + sourceIfMatch = setupBlobMatchCondition(sourceURL, sourceIfMatch) + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(sourceIfMatch) + .sourceIfNoneMatch(sourceIfNoneMatch) + + expect: + bu.uploadPagesFromURL(pageRange, sourceURL.getBlobUrl(), null, null, null, smac, null).statusCode() == 201 + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Upload page from URL source AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.CONTAINER, null, null, null) + def sourceURL = cu.getPageBlobClient(generateBlobName()) + sourceURL.create(PageBlobClient.PAGE_BYTES) + def pageRange = new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1) + sourceURL.uploadPages(pageRange, new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + def smac = new SourceModifiedAccessConditions() + .sourceIfModifiedSince(sourceIfModifiedSince) + .sourceIfUnmodifiedSince(sourceIfUnmodifiedSince) + .sourceIfMatch(sourceIfMatch) + .sourceIfNoneMatch(setupBlobMatchCondition(sourceURL, sourceIfNoneMatch)) + + when: + bu.uploadPagesFromURL(pageRange, sourceURL.getBlobUrl(), null, null, null, smac, null) + + then: + thrown(StorageException) + + where: + sourceIfModifiedSince | sourceIfUnmodifiedSince | sourceIfMatch | sourceIfNoneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Clear page"() { + setup: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES)), null, null) + + when: + Response response = bu.clearPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1)) + + then: + !bu.getPageRanges(new BlobRange(0)).iterator().hasNext() + validateBasicHeaders(response.headers()) + response.value().contentMD5() == null + response.value().blobSequenceNumber() == 0 + } + + def "Clear page min"() { + expect: + bu.clearPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1)) + } + + @Unroll + def "Clear pages AC"() { + setup: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + def pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + expect: + bu.clearPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), pac, null) + .statusCode() == 201 + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + null | null | null | null | null | null | null | null + oldDate | null | null | null | null | null | null | null + null | newDate | null | null | null | null | null | null + null | null | receivedEtag | null | null | null | null | null + null | null | null | garbageEtag | null | null | null | null + null | null | null | null | receivedLeaseID | null | null | null + null | null | null | null | null | 5 | null | null + null | null | null | null | null | null | 3 | null + null | null | null | null | null | null | null | 0 + } + + @Unroll + def "Clear pages AC fail"() { + setup: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + noneMatch = setupBlobMatchCondition(bu, noneMatch) + setupBlobLeaseCondition(bu, leaseID) + def pac = new PageBlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + .sequenceNumberAccessConditions(new SequenceNumberAccessConditions() + .ifSequenceNumberLessThan(sequenceNumberLT) + .ifSequenceNumberLessThanOrEqualTo(sequenceNumberLTE) + .ifSequenceNumberEqualTo(sequenceNumberEqual)) + + + when: + bu.clearPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), pac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID | sequenceNumberLT | sequenceNumberLTE | sequenceNumberEqual + newDate | null | null | null | null | null | null | null + null | oldDate | null | null | null | null | null | null + null | null | garbageEtag | null | null | null | null | null + null | null | null | receivedEtag | null | null | null | null + null | null | null | null | garbageLeaseID | null | null | null + null | null | null | null | null | -1 | null | null + null | null | null | null | null | null | -1 | null + null | null | null | null | null | null | null | 100 + } + + def "Clear page error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.clearPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1)) + + then: + thrown(StorageException) + } + + // TODO (alzimmer): Turn this on once paged responses become available + /*def "Get page ranges"() { + setup: + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + when: + Iterable response = bu.getPageRanges(new BlobRange(0, PageBlobClient.PAGE_BYTES)) + + then: + response.statusCode() == 200 + response.body().pageRange().size() == 1 + validateBasicHeaders(headers) + headers.blobContentLength() == (long) PageBlobClient.PAGE_BYTES + }*/ + + def "Get page ranges min"() { + when: + bu.getPageRanges(null) + + then: + notThrown(StorageException) + } + + @Unroll + def "Get page ranges AC"() { + setup: + match = setupBlobMatchCondition(bu, match) + leaseID = setupBlobLeaseCondition(bu, leaseID) + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(leaseID)) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch)) + + + when: + bu.getPageRanges(new BlobRange(0, PageBlobClient.PAGE_BYTES), bac, null).iterator().hasNext() + + then: + notThrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Get page ranges AC fail"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.getPageRanges(new BlobRange(0, PageBlobClient.PAGE_BYTES), bac, null).iterator().hasNext() + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Get page ranges error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.getPageRanges(null).iterator().hasNext() + + then: + thrown(StorageException) + } + + // TODO (alzimmer): This test needs to be restructured to support the Iterable T return + /*def "Get page ranges diff"() { + setup: + bu.create(PageBlobClient.PAGE_BYTES * 2) + + bu.uploadPages(new PageRange().start(PageBlobClient.PAGE_BYTES).end(PageBlobClient.PAGE_BYTES * 2 - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + String snapshot = bu.createSnapshot(null, null, null).value() + + bu.uploadPages(new PageRange().start(0).end(PageBlobClient.PAGE_BYTES - 1), + new ByteArrayInputStream(getRandomByteArray(PageBlobClient.PAGE_BYTES))) + + bu.clearPages(new PageRange().start(PageBlobClient.PAGE_BYTES).end(PageBlobClient.PAGE_BYTES * 2 - 1)) + + when: + Iterable response = bu.getPageRangesDiff(new BlobRange(0, PageBlobClient.PAGE_BYTES * 2), snapshot) + PageBlobGetPageRangesDiffHeaders headers = response.headers() + + then: + response.body().pageRange().size() == 1 + response.body().pageRange().get(0).start() == 0 + response.body().pageRange().get(0).end() == PageBlobClient.PAGE_BYTES - 1 + response.body().clearRange().size() == 1 + response.body().clearRange().get(0).start() == PageBlobClient.PAGE_BYTES + response.body().clearRange().get(0).end() == PageBlobClient.PAGE_BYTES * 2 - 1 + validateBasicHeaders(headers) + headers.blobContentLength() == PageBlobClient.PAGE_BYTES * 2 + }*/ + + def "Get page ranges diff min"() { + setup: + String snapshot = bu.createSnapshot().value() + + when: + bu.getPageRangesDiff(null, snapshot).iterator().hasNext() + + then: + notThrown(StorageException) + } + + @Unroll + def "Get page ranges diff AC"() { + setup: + String snapshot = bu.createSnapshot(null, null, null).value() + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + + when: + bu.getPageRangesDiff(new BlobRange(0, PageBlobClient.PAGE_BYTES), snapshot, bac, null).iterator().hasNext() + + then: + notThrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Get page ranges diff AC fail"() { + setup: + String snapshot = bu.createSnapshot().value() + + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.getPageRangesDiff(new BlobRange(0, PageBlobClient.PAGE_BYTES), snapshot, bac, null).iterator().hasNext() + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Get page ranges diff error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.getPageRangesDiff(null, "snapshot").iterator().hasNext() + + then: + thrown(StorageException) + } + + @Unroll + def "PageRange IA"() { + setup: + def range = new PageRange().start(start).end(end) + + when: + bu.clearPages(range) + + then: + thrown(IllegalArgumentException) + + where: + start | end + 1 | 1 + -PageBlobClient.PAGE_BYTES | PageBlobClient.PAGE_BYTES - 1 + 0 | 0 + 1 | PageBlobClient.PAGE_BYTES - 1 + 0 | PageBlobClient.PAGE_BYTES + PageBlobClient.PAGE_BYTES * 2 | PageBlobClient.PAGE_BYTES - 1 + } + + def "Resize"() { + setup: + Response response = bu.resize(PageBlobClient.PAGE_BYTES * 2) + + expect: + Integer.parseInt(bu.getProperties().headers().value("Content-Length")) == PageBlobClient.PAGE_BYTES * 2 + validateBasicHeaders(response.headers()) + response.value().blobSequenceNumber() != null + } + + def "Resize min"() { + expect: + bu.resize(PageBlobClient.PAGE_BYTES).statusCode() == 200 + } + + @Unroll + def "Resize AC"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + + expect: + bu.resize(PageBlobClient.PAGE_BYTES * 2, bac, null).statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Resize AC fail"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.resize(PageBlobClient.PAGE_BYTES * 2, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Resize error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.resize(0) + + then: + thrown(StorageException) + } + + @Unroll + def "Sequence number"() { + setup: + Response response = bu.updateSequenceNumber(action, number) + + expect: + Integer.parseInt(bu.getProperties().headers().value("x-ms-blob-sequence-number")) == result + validateBasicHeaders(response.headers()) + response.value().blobSequenceNumber() == result + + where: + action | number || result + SequenceNumberActionType.UPDATE | 5 || 5 + SequenceNumberActionType.INCREMENT | null || 1 + SequenceNumberActionType.MAX | 2 || 2 + } + + def "Sequence number min"() { + expect: + bu.updateSequenceNumber(SequenceNumberActionType.INCREMENT, null).statusCode() == 200 + } + + @Unroll + def "Sequence number AC"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(setupBlobMatchCondition(bu, match)) + .ifNoneMatch(noneMatch)) + + expect: + bu.updateSequenceNumber(SequenceNumberActionType.UPDATE, 1, bac, null) + .statusCode() == 200 + + where: + modified | unmodified | match | noneMatch | leaseID + null | null | null | null | null + oldDate | null | null | null | null + null | newDate | null | null | null + null | null | receivedEtag | null | null + null | null | null | garbageEtag | null + null | null | null | null | receivedLeaseID + } + + @Unroll + def "Sequence number AC fail"() { + setup: + BlobAccessConditions bac = new BlobAccessConditions() + .leaseAccessConditions(new LeaseAccessConditions().leaseId(setupBlobLeaseCondition(bu, leaseID))) + .modifiedAccessConditions(new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(setupBlobMatchCondition(bu, noneMatch))) + + when: + bu.updateSequenceNumber(SequenceNumberActionType.UPDATE, 1, bac, null) + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch | leaseID + newDate | null | null | null | null + null | oldDate | null | null | null + null | null | garbageEtag | null | null + null | null | null | receivedEtag | null + null | null | null | null | garbageLeaseID + } + + def "Sequence number error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.updateSequenceNumber(SequenceNumberActionType.UPDATE, 0) + + then: + thrown(StorageException) + } + + def "Start incremental copy"() { + setup: + cu.setAccessPolicy(PublicAccessType.BLOB, null) + PageBlobClient bu2 = cu.getPageBlobClient(generateBlobName()) + String snapshot = bu.createSnapshot().value() + + Response copyResponse = bu2.copyIncremental(bu.getBlobUrl(), snapshot) + String status = copyResponse.value().toString() + + OffsetDateTime start = OffsetDateTime.now() + while (status != CopyStatusType.SUCCESS.toString()) { + status = bu2.getProperties().headers().value("x-ms-copy-status") + OffsetDateTime currentTime = OffsetDateTime.now() + if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { + throw new Exception("Copy failed or took too long") + } + sleep(1000) + } + + expect: + Response propertiesResponse = bu2.getProperties() + Boolean.parseBoolean(propertiesResponse.headers().value("x-ms-incremental-copy")) + propertiesResponse.headers().value("x-ms-copy-destination-snapshot") != null + validateBasicHeaders(copyResponse.headers()) + copyResponse.headers().value("x-ms-copy-id") != null + copyResponse.value() != null + } + + def "Start incremental copy min"() { + setup: + cu.setAccessPolicy(PublicAccessType.BLOB, null) + PageBlobClient bu2 = cu.getPageBlobClient(generateBlobName()) + String snapshot = bu.createSnapshot().value() + + expect: + bu2.copyIncremental(bu.getBlobUrl(), snapshot).statusCode() == 202 + } + + @Unroll + def "Start incremental copy AC"() { + setup: + cu.setAccessPolicy(PublicAccessType.BLOB, null) + PageBlobClient bu2 = cu.getPageBlobClient(generateBlobName()) + String snapshot = bu.createSnapshot().value() + + Response copyResponse = bu2.copyIncremental(bu.getBlobUrl(), snapshot) + String status = copyResponse.value().toString() + + OffsetDateTime start = OffsetDateTime.now() + while (status != CopyStatusType.SUCCESS.toString()) { + status = bu2.getProperties().headers().value("x-ms-copy-status") + OffsetDateTime currentTime = OffsetDateTime.now() + if (status == CopyStatusType.FAILED.toString() || currentTime.minusMinutes(1) == start) { + throw new Exception("Copy failed or took too long") + } + sleep(1000) + } + + snapshot = bu.createSnapshot().value() + match = setupBlobMatchCondition(bu2, match) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + expect: + bu2.copyIncremental(bu.getBlobUrl(), snapshot, mac, null).statusCode() == 202 + + where: + modified | unmodified | match | noneMatch + null | null | null | null + oldDate | null | null | null + null | newDate | null | null + null | null | receivedEtag | null + null | null | null | garbageEtag + } + + @Unroll + def "Start incremental copy AC fail"() { + setup: + cu.setAccessPolicy(PublicAccessType.BLOB, null) + PageBlobClient bu2 = cu.getPageBlobClient(generateBlobName()) + String snapshot = bu.createSnapshot().value() + bu2.copyIncremental(bu.getBlobUrl(), snapshot) + snapshot = bu.createSnapshot().value() + noneMatch = setupBlobMatchCondition(bu2, noneMatch) + def mac = new ModifiedAccessConditions() + .ifModifiedSince(modified) + .ifUnmodifiedSince(unmodified) + .ifMatch(match) + .ifNoneMatch(noneMatch) + + when: + bu2.copyIncremental(bu.getBlobUrl(), snapshot, mac, null).statusCode() + + then: + thrown(StorageException) + + where: + modified | unmodified | match | noneMatch + newDate | null | null | null + null | oldDate | null | null + null | null | garbageEtag | null + null | null | null | receivedEtag + } + + def "Start incremental copy error"() { + setup: + bu = cu.getPageBlobClient(generateBlobName()) + + when: + bu.copyIncremental(new URL("https://www.error.com"), "snapshot") + + then: + thrown(StorageException) + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java b/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java new file mode 100644 index 0000000000000..1ac12cbe978da --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/Sample.java @@ -0,0 +1,217 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.rest.Response; +import com.azure.storage.blob.models.BlobItem; +import com.azure.storage.blob.models.ContainerItem; +import com.azure.storage.common.credentials.SharedKeyCredential; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +public class Sample { + + private static final String ACCOUNT_ENDPOINT = ""; + private static final String ACCOUNT_NAME = ""; + private static final String ACCOUNT_KEY = ""; + + //@Test + public void sample() throws IOException { + // get service client + StorageClient serviceClient = new StorageClientBuilder().endpoint(ACCOUNT_ENDPOINT) + .credential(new SharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)) + .httpClient(HttpClient.createDefault()/*.proxy(() -> new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8888)))*/) + .buildClient(); + + // create 5 containers + ContainerClient containerClient = null; + for (int i = 0; i < 5; i++) { + String name = "uxtesting" + UUID.randomUUID(); + containerClient = serviceClient.getContainerClient(name); + containerClient.create(); + System.out.println("Created container: " + name); + } + System.out.println(); + + // list containers in account + System.out.println("Listing containers in account:"); + for (ContainerItem item : serviceClient.listContainers()) { + System.out.println(item.name()); + } + System.out.println(); + + // in the last container, create 5 blobs + for (int i = 0; i < 5; i++) { + BlockBlobClient blobClient = containerClient.getBlockBlobClient("testblob-" + i); + ByteArrayInputStream testdata = new ByteArrayInputStream(("test data" + i).getBytes(StandardCharsets.UTF_8)); + + blobClient.upload(testdata, testdata.available()); + System.out.println("Uploaded blob."); + } + System.out.println(); + + // list blobs and download results + System.out.println("Listing/downloading blobs:"); + for (BlobItem item : containerClient.listBlobsFlat()) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + containerClient.getBlobClient(item.name()).download(stream); + System.out.println(item.name() + ": " + new String(stream.toByteArray())); + } + System.out.println(); + + // cleanup + for (ContainerItem item : serviceClient.listContainers()) { + containerClient = serviceClient.getContainerClient(item.name()); + containerClient.delete(); + System.out.println("Deleted container: " + item.name()); + } + } + + //@Test + public void asyncSample() throws IOException { + // get service client + StorageAsyncClient serviceClient = new StorageClientBuilder().endpoint(ACCOUNT_ENDPOINT) + .credential(new SharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)) + .httpClient(HttpClient.createDefault()/*.proxy(() -> new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8888)))*/) + .buildAsyncClient(); + + // create 5 containers + ContainerAsyncClient containerClient = null; + Mono createContainerTask = Mono.empty(); + for (int i = 0; i < 5; i++) { + String name = "uxtesting" + UUID.randomUUID(); + containerClient = serviceClient.getContainerAsyncClient(name); + + createContainerTask = createContainerTask.and(containerClient.create().then(Mono.defer(() -> { + System.out.println("Created container: " + name); + return Mono.empty(); + }))); + } + ContainerAsyncClient finalContainerClient = containerClient; // final variable for lambda usage + + createContainerTask + // list containers + .thenMany(Flux.defer(() -> { + System.out.println("Listing containers in account:"); + return serviceClient.listContainers() + .flatMap(containerItem -> { + System.out.println(containerItem.name()); + return Mono.empty(); + }); + })) + // in the last container, create 5 blobs + .then(Mono.defer(() -> { + Mono finished = Mono.empty(); + for (int i = 0; i < 5; i++) { + BlockBlobAsyncClient blobClient = finalContainerClient.getBlockBlobAsyncClient("testblob-" + i); + byte[] message = ("test data" + i).getBytes(StandardCharsets.UTF_8); + Flux testdata = Flux.just(ByteBuffer.wrap(message)); + + + finished = finished.and(blobClient.upload(testdata, message.length) + .then(Mono.defer(() -> { + System.out.println("Uploaded blob."); + return Mono.empty(); + }))); + } + + return finished; + })) + // list blobs + .thenMany(Flux.defer(() -> { + System.out.println(); + System.out.println("Listing/downloading blobs:"); + return finalContainerClient.listBlobsFlat(); + })) + // download results + .flatMap(listItem -> + finalContainerClient.getBlobAsyncClient(listItem.name()) + .download() + .flatMapMany(Response::value) + .map(buffer -> new String(buffer.array())) + .doOnNext(string -> System.out.println(listItem.name() + ": " + string))) + // cleanup + .thenMany(serviceClient.listContainers()) + .flatMap(containerItem -> serviceClient + .getContainerAsyncClient(containerItem.name()) + .delete()) + .blockLast(); + } + + //@Test + public void uploadDownloadFromFile() throws IOException { + final String data = "TEST DATA" + UUID.randomUUID(); + final String folderPath = "C:/Users/jaschrep/Desktop/temp"; + + // make start file + File startFile = new File(folderPath, "startFile" + UUID.randomUUID()); + FileOutputStream fstream = new FileOutputStream(startFile); + fstream.write(data.getBytes()); + fstream.close(); + + // get service client + StorageClient serviceClient = new StorageClientBuilder().endpoint(ACCOUNT_ENDPOINT) + .credential(new SharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)) + .httpClient(HttpClient.createDefault()/*.proxy(() -> new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8888)))*/) + .buildClient(); + + // make container + ContainerClient containerClient = serviceClient.getContainerClient("uxstudy" + UUID.randomUUID()); + containerClient.create(); + + // upload data + BlockBlobClient blobClient = containerClient.getBlockBlobClient("testblob_" + UUID.randomUUID()); + blobClient.uploadFromFile(startFile.getAbsolutePath()); + + // download data + File endFile = new File(folderPath, "endFile" + UUID.randomUUID()); + blobClient.downloadToFile(endFile.getAbsolutePath()); + } + + //@Test + public void uploadDownloadFromFileAsync() throws IOException { + final String data = "TEST DATA" + UUID.randomUUID(); + final String folderPath = "C:/Users/jaschrep/Desktop/temp"; + + // make start file + File startFile = new File(folderPath, "startFile" + UUID.randomUUID()); + FileOutputStream fstream = new FileOutputStream(startFile); + fstream.write(data.getBytes()); + fstream.close(); + + // get service client + StorageAsyncClient serviceClient = new StorageClientBuilder().endpoint(ACCOUNT_ENDPOINT) + .credential(new SharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY)) + .httpClient(HttpClient.createDefault()/*.proxy(() -> new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress("localhost", 8888)))*/) + .buildAsyncClient(); + + // make container + ContainerAsyncClient containerClient = serviceClient.getContainerAsyncClient("uxstudy" + UUID.randomUUID()); + containerClient.create() + + // upload data + .then(Mono.defer(() -> { + BlockBlobAsyncClient blobClient = containerClient.getBlockBlobAsyncClient("testblob_" + UUID.randomUUID()); + return blobClient.uploadFromFile(startFile.getAbsolutePath()) + .then(Mono.just(blobClient)); + })) + + // download data + .flatMap(blobClient -> + blobClient.downloadToFile(new File(folderPath, "endFile" + UUID.randomUUID()).getAbsolutePath())) + + .block(); + + } +} diff --git a/storage/client/blob/src/test/java/com/azure/storage/blob/ServiceAPITest.groovy b/storage/client/blob/src/test/java/com/azure/storage/blob/ServiceAPITest.groovy new file mode 100644 index 0000000000000..d6e8861b47398 --- /dev/null +++ b/storage/client/blob/src/test/java/com/azure/storage/blob/ServiceAPITest.groovy @@ -0,0 +1,384 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.blob + + +import com.azure.core.http.HttpHeaders +import com.azure.core.http.rest.Response +import com.azure.storage.blob.models.* +import com.azure.storage.common.policy.RequestRetryOptions +import org.junit.Assume + +import java.time.OffsetDateTime + +class ServiceAPITest extends APISpec { + def setup() { + RetentionPolicy disabled = new RetentionPolicy().enabled(false) + primaryServiceURL.setProperties(new StorageServiceProperties() + .staticWebsite(new StaticWebsite().enabled(false)) + .deleteRetentionPolicy(disabled) + .cors(null) + .hourMetrics(new Metrics().version("1.0").enabled(false) + .retentionPolicy(disabled)) + .minuteMetrics(new Metrics().version("1.0").enabled(false) + .retentionPolicy(disabled)) + .logging(new Logging().version("1.0") + .retentionPolicy(disabled)) + .defaultServiceVersion("2018-03-28"), null) + } + + def cleanup() { + Assume.assumeTrue("The test only runs in Live mode.", testMode.equalsIgnoreCase("RECORD")) + RetentionPolicy disabled = new RetentionPolicy().enabled(false) + primaryServiceURL.setProperties(new StorageServiceProperties() + .staticWebsite(new StaticWebsite().enabled(false)) + .deleteRetentionPolicy(disabled) + .cors(null) + .hourMetrics(new Metrics().version("1.0").enabled(false) + .retentionPolicy(disabled)) + .minuteMetrics(new Metrics().version("1.0").enabled(false) + .retentionPolicy(disabled)) + .logging(new Logging().version("1.0") + .retentionPolicy(disabled)) + .defaultServiceVersion("2018-03-28"), null) + } + + def "List containers"() { + when: + Iterable response = + primaryServiceURL.listContainers(new ListContainersOptions().prefix(containerPrefix), null) + + then: + for (ContainerItem c : response) { + assert c.name().startsWith(containerPrefix) + assert c.properties().lastModified() != null + assert c.properties().etag() != null + assert c.properties().leaseStatus() != null + assert c.properties().leaseState() != null + assert c.properties().leaseDuration() == null + assert c.properties().publicAccess() == null + assert !c.properties().hasLegalHold() + assert !c.properties().hasImmutabilityPolicy() + } + } + + def "List containers min"() { + when: + primaryServiceURL.listContainers().iterator().hasNext() + + then: + notThrown(StorageException) + } + + def "List containers marker"() { + setup: + for (int i = 0; i < 10; i++) { + primaryServiceURL.createContainer(generateContainerName()) + } + + Iterator listResponse = primaryServiceURL.listContainers().iterator() + String firstContainerName = listResponse.next().name() + + expect: + // Assert that the second segment is indeed after the first alphabetically + firstContainerName < listResponse.next().name() + } + + def "List containers details"() { + setup: + Metadata metadata = new Metadata() + metadata.put("foo", "bar") + cu = primaryServiceURL.createContainer("aaa" + generateContainerName(), metadata, null).value() + + expect: + primaryServiceURL.listContainers(new ListContainersOptions() + .details(new ContainerListDetails().metadata(true)) + .prefix("aaa" + containerPrefix), null) + .iterator().next().metadata() == metadata + + // Container with prefix "aaa" will not be cleaned up by normal test cleanup. + cu.delete().statusCode() == 202 + } + + // TODO (alzimmer): Turn this test back on when listing by page is implemented + /*def "List containers maxResults"() { + setup: + for (int i = 0; i < 11; i++) { + primaryServiceURL.createContainer(generateContainerName()) + } + + expect: + + primaryServiceURL.listContainersSegment(null, + new ListContainersOptions().maxResults(10), null) + .blockingGet().body().containerItems().size() == 10 + }*/ + + // TODO (alzimmer): Turn this test back on when listing by page is implemented as this requires being able to set a marker + /*def "List containers error"() { + when: + primaryServiceURL.listContainers("garbage", null, null).blockingGet() + + then: + thrown(StorageException) + }*/ + + def validatePropsSet(StorageServiceProperties sent, StorageServiceProperties received) { + return received.logging().read() == sent.logging().read() && + received.logging().delete() == sent.logging().delete() && + received.logging().write() == sent.logging().write() && + received.logging().version() == sent.logging().version() && + received.logging().retentionPolicy().days() == sent.logging().retentionPolicy().days() && + received.logging().retentionPolicy().enabled() == sent.logging().retentionPolicy().enabled() && + + received.cors().size() == sent.cors().size() && + received.cors().get(0).allowedMethods() == sent.cors().get(0).allowedMethods() && + received.cors().get(0).allowedHeaders() == sent.cors().get(0).allowedHeaders() && + received.cors().get(0).allowedOrigins() == sent.cors().get(0).allowedOrigins() && + received.cors().get(0).exposedHeaders() == sent.cors().get(0).exposedHeaders() && + received.cors().get(0).maxAgeInSeconds() == sent.cors().get(0).maxAgeInSeconds() && + + received.defaultServiceVersion() == sent.defaultServiceVersion() && + + received.hourMetrics().enabled() == sent.hourMetrics().enabled() && + received.hourMetrics().includeAPIs() == sent.hourMetrics().includeAPIs() && + received.hourMetrics().retentionPolicy().enabled() == sent.hourMetrics().retentionPolicy().enabled() && + received.hourMetrics().retentionPolicy().days() == sent.hourMetrics().retentionPolicy().days() && + received.hourMetrics().version() == sent.hourMetrics().version() && + + received.minuteMetrics().enabled() == sent.minuteMetrics().enabled() && + received.minuteMetrics().includeAPIs() == sent.minuteMetrics().includeAPIs() && + received.minuteMetrics().retentionPolicy().enabled() == sent.minuteMetrics().retentionPolicy().enabled() && + received.minuteMetrics().retentionPolicy().days() == sent.minuteMetrics().retentionPolicy().days() && + received.minuteMetrics().version() == sent.minuteMetrics().version() && + + received.deleteRetentionPolicy().enabled() == sent.deleteRetentionPolicy().enabled() && + received.deleteRetentionPolicy().days() == sent.deleteRetentionPolicy().days() && + + received.staticWebsite().enabled() == sent.staticWebsite().enabled() && + received.staticWebsite().indexDocument() == sent.staticWebsite().indexDocument() && + received.staticWebsite().errorDocument404Path() == sent.staticWebsite().errorDocument404Path() + } + + def "Set get properties"() { + when: + RetentionPolicy retentionPolicy = new RetentionPolicy().days(5).enabled(true) + Logging logging = new Logging().read(true).version("1.0") + .retentionPolicy(retentionPolicy) + ArrayList corsRules = new ArrayList<>() + corsRules.add(new CorsRule().allowedMethods("GET,PUT,HEAD") + .allowedOrigins("*") + .allowedHeaders("x-ms-version") + .exposedHeaders("x-ms-client-request-id") + .maxAgeInSeconds(10)) + String defaultServiceVersion = "2016-05-31" + Metrics hourMetrics = new Metrics().enabled(true).version("1.0") + .retentionPolicy(retentionPolicy).includeAPIs(true) + Metrics minuteMetrics = new Metrics().enabled(true).version("1.0") + .retentionPolicy(retentionPolicy).includeAPIs(true) + StaticWebsite website = new StaticWebsite().enabled(true) + .indexDocument("myIndex.html") + .errorDocument404Path("custom/error/path.html") + + StorageServiceProperties sentProperties = new StorageServiceProperties() + .logging(logging).cors(corsRules).defaultServiceVersion(defaultServiceVersion) + .minuteMetrics(minuteMetrics).hourMetrics(hourMetrics) + .deleteRetentionPolicy(retentionPolicy) + .staticWebsite(website) + + HttpHeaders headers = primaryServiceURL.setProperties(sentProperties).headers() + + // Service properties may take up to 30s to take effect. If they weren't already in place, wait. + sleep(30 * 1000) + + StorageServiceProperties receivedProperties = primaryServiceURL.getProperties().value() + + then: + headers.value("x-ms-request-id") != null + headers.value("x-ms-version") != null + validatePropsSet(sentProperties, receivedProperties) + } + + // In java, we don't have support from the validator for checking the bounds on days. The service will catch these. + + def "Set props min"() { + setup: + RetentionPolicy retentionPolicy = new RetentionPolicy().days(5).enabled(true) + Logging logging = new Logging().read(true).version("1.0") + .retentionPolicy(retentionPolicy) + ArrayList corsRules = new ArrayList<>() + corsRules.add(new CorsRule().allowedMethods("GET,PUT,HEAD") + .allowedOrigins("*") + .allowedHeaders("x-ms-version") + .exposedHeaders("x-ms-client-request-id") + .maxAgeInSeconds(10)) + String defaultServiceVersion = "2016-05-31" + Metrics hourMetrics = new Metrics().enabled(true).version("1.0") + .retentionPolicy(retentionPolicy).includeAPIs(true) + Metrics minuteMetrics = new Metrics().enabled(true).version("1.0") + .retentionPolicy(retentionPolicy).includeAPIs(true) + StaticWebsite website = new StaticWebsite().enabled(true) + .indexDocument("myIndex.html") + .errorDocument404Path("custom/error/path.html") + + StorageServiceProperties sentProperties = new StorageServiceProperties() + .logging(logging).cors(corsRules).defaultServiceVersion(defaultServiceVersion) + .minuteMetrics(minuteMetrics).hourMetrics(hourMetrics) + .deleteRetentionPolicy(retentionPolicy) + .staticWebsite(website) + + expect: + primaryServiceURL.setProperties(sentProperties).statusCode() == 202 + } + + def "Set props error"() { + when: + new StorageClientBuilder() + .endpoint("https://error.blob.core.windows.net") + .credential(primaryCreds) + .buildClient() + .setProperties(new StorageServiceProperties()) + + then: + thrown(StorageException) + } + + def "Get props min"() { + expect: + primaryServiceURL.getProperties().statusCode() == 200 + } + + def "Get props error"() { + when: + new StorageClientBuilder() + .endpoint("https://error.blob.core.windows.net") + .credential(primaryCreds) + .buildClient() + .getProperties() + + then: + thrown(StorageException) + } + + def "Get UserDelegationKey"() { + setup: + def start = OffsetDateTime.now() + def expiry = start.plusDays(1) + + Response response = getOAuthServiceURL().getUserDelegationKey(start, expiry, null) + + expect: + response.statusCode() == 200 + response.value() != null + response.value().signedOid() != null + response.value().signedTid() != null + response.value().signedStart() != null + response.value().signedExpiry() != null + response.value().signedService() != null + response.value().signedVersion() != null + response.value().value() != null + } + + def "Get UserDelegationKey min"() { + setup: + def expiry = OffsetDateTime.now().plusDays(1) + + def response = getOAuthServiceURL().getUserDelegationKey(null, expiry) + + expect: + response.statusCode() == 200 + } + + def "Get UserDelegationKey error"() { + when: + getOAuthServiceURL().getUserDelegationKey(start, expiry) + + then: + thrown(exception) + + where: + start | expiry || exception + null | null || IllegalArgumentException + OffsetDateTime.now() | OffsetDateTime.now().minusDays(1) || IllegalArgumentException + } + + def "Get stats"() { + setup: + String secondaryEndpoint = String.format("https://%s-secondary.blob.core.windows.net", primaryCreds.accountName()) + StorageClient serviceClient = new StorageClientBuilder().endpoint(secondaryEndpoint) + .credential(primaryCreds).buildClient() + Response response = serviceClient.getStatistics() + + expect: + response.headers().value("x-ms-version") != null + response.headers().value("x-ms-request-id") != null + response.headers().value("Date") != null + response.value().geoReplication().status() != null + response.value().geoReplication().lastSyncTime() != null + } + + def "Get stats min"() { + setup: + String secondaryEndpoint = String.format("https://%s-secondary.blob.core.windows.net", primaryCreds.accountName()) + StorageClient serviceClient = new StorageClientBuilder().endpoint(secondaryEndpoint) + .credential(primaryCreds).buildClient() + expect: + serviceClient.getStatistics().statusCode() == 200 + } + + def "Get stats error"() { + when: + primaryServiceURL.getStatistics() + + then: + thrown(StorageException) + } + + def "Get account info"() { + when: + Response response = primaryServiceURL.getAccountInfo() + + then: + response.headers().value("Date") != null + response.headers().value("x-ms-version") != null + response.headers().value("x-ms-request-id") != null + response.value().accountKind() != null + response.value().skuName() != null + } + + def "Get account info min"() { + expect: + primaryServiceURL.getAccountInfo().statusCode() == 200 + } + + def "Get account info error"() { + when: + StorageClient serviceURL = new StorageClientBuilder() + .endpoint(primaryServiceURL.getAccountUrl().toString()) + .buildClient() + serviceURL.getAccountInfo() + + then: + thrown(StorageException) + } + + + // This test validates a fix for a bug that caused NPE to be thrown when the account did not exist. + def "Invalid account name"() { + setup: + URL badURL = new URL("http://fake.blobfake.core.windows.net") + StorageClient client = new StorageClientBuilder() + .endpoint(badURL.toString()) + .credential(primaryCreds) + .retryOptions(new RequestRetryOptions(null, 2, null, null, null, null)) + .buildClient() + + when: + client.getProperties() + + then: + def e = thrown(RuntimeException) + e.getCause() instanceof UnknownHostException + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java b/storage/client/file/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java new file mode 100644 index 0000000000000..fe93273e3f64e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; + +import java.util.HashMap; + +/** + * Holds a SAS token used for authenticating requests. + */ +public final class SASTokenCredential { + // Required SAS token pieces + private static final String SIGNED_VERSION = "sv"; + private static final String SIGNED_SERVICES = "ss"; + private static final String SIGNED_RESOURCE_TYPES = "srt"; + private static final String SIGNED_PERMISSIONS = "sp"; + private static final String SIGNED_EXPIRY = "se"; + private static final String SIGNATURE = "sig"; + + // Optional SAS token pieces + private static final String SIGNED_START = "st"; + private static final String SIGNED_PROTOCOL = "spr"; + private static final String SIGNED_IP = "sip"; + + private final String sasToken; + + /** + * Creates a SAS token credential from the passed SAS token. + * @param sasToken SAS token used to authenticate requests with the service. + */ + public SASTokenCredential(String sasToken) { + this.sasToken = sasToken; + } + + /** + * @return the SAS token + */ + public String sasToken() { + return sasToken; + } + + /** + * Creates a SAS token credential from the passed URL query string + * @param query URL query used to build the SAS token + * @return a SAS token credential if the query param contains all the necessary pieces + */ + public static SASTokenCredential fromQuery(String query) { + if (ImplUtils.isNullOrEmpty(query)) { + return null; + } + + HashMap queryParams = new HashMap<>(); + for (String queryParam : query.split("&")) { + String key = queryParam.split("=", 2)[0]; + queryParams.put(key, queryParam); + } + + if (queryParams.size() < 6 + || !queryParams.containsKey(SIGNED_VERSION) + || !queryParams.containsKey(SIGNED_SERVICES) + || !queryParams.containsKey(SIGNED_RESOURCE_TYPES) + || !queryParams.containsKey(SIGNED_PERMISSIONS) + || !queryParams.containsKey(SIGNED_EXPIRY) + || !queryParams.containsKey(SIGNATURE)) { + return null; + } + + StringBuilder sasTokenBuilder = new StringBuilder(queryParams.get(SIGNED_VERSION)) + .append("&").append(queryParams.get(SIGNED_SERVICES)) + .append("&").append(queryParams.get(SIGNED_RESOURCE_TYPES)) + .append("&").append(queryParams.get(SIGNED_PERMISSIONS)); + + // SIGNED_START is optional + if (queryParams.containsKey(SIGNED_START)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_START)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_EXPIRY)); + + // SIGNED_IP is optional + if (queryParams.containsKey(SIGNED_IP)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_IP)); + } + + // SIGNED_PROTOCOL is optional + if (queryParams.containsKey(SIGNED_PROTOCOL)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_PROTOCOL)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNATURE)); + + return new SASTokenCredential(sasTokenBuilder.toString()); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java b/storage/client/file/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java new file mode 100644 index 0000000000000..19b2b4c307221 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java @@ -0,0 +1,230 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; +import io.netty.handler.codec.http.QueryStringDecoder; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * SharedKey credential policy that is put into a header to authorize requests. + */ +public final class SharedKeyCredential { + private static final String AUTHORIZATION_HEADER_FORMAT = "SharedKey %s:%s"; + + // Pieces of the connection string that are needed. + private static final String ACCOUNT_NAME = "AccountName".toLowerCase(); + private static final String ACCOUNT_KEY = "AccountKey".toLowerCase(); + + private final String accountName; + private final byte[] accountKey; + + /** + * Initializes a new instance of SharedKeyCredential contains an account's name and its primary or secondary + * accountKey. + * + * @param accountName The account name associated with the request. + * @param accountKey The account access key used to authenticate the request. + */ + public SharedKeyCredential(String accountName, String accountKey) { + Objects.requireNonNull(accountName); + Objects.requireNonNull(accountKey); + this.accountName = accountName; + this.accountKey = Base64.getDecoder().decode(accountKey); + } + + /** + * Creates a SharedKey credential from the passed connection string. + * @param connectionString Connection string used to build the SharedKey credential. + * @return a SharedKey credential if the connection string contains AccountName and AccountKey + * @throws IllegalArgumentException If {@code connectionString} doesn't have AccountName or AccountKey. + */ + public static SharedKeyCredential fromConnectionString(String connectionString) { + HashMap connectionStringPieces = new HashMap<>(); + for (String connectionStringPiece : connectionString.split(";")) { + String[] kvp = connectionStringPiece.split("=", 2); + connectionStringPieces.put(kvp[0].toLowerCase(), kvp[1]); + } + + String accountName = connectionStringPieces.get(ACCOUNT_NAME); + String accountKey = connectionStringPieces.get(ACCOUNT_KEY); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + return new SharedKeyCredential(accountName, accountKey); + } + + /** + * Gets the account name associated with the request. + * + * @return The account name. + */ + public String accountName() { + return accountName; + } + + /** + * Generates the SharedKey Authorization value from information in the request. + * @param requestURL URL of the request + * @param httpMethod HTTP method being used + * @param headers Headers on the request + * @return the SharedKey authorization value + */ + public String generateAuthorizationHeader(URL requestURL, String httpMethod, Map headers) { + return computeHMACSHA256(buildStringToSign(requestURL, httpMethod, headers)); + } + + /** + * Computes a signature for the specified string using the HMAC-SHA256 algorithm. + * Package-private because it is used to generate SAS signatures. + * + * @param stringToSign The UTF-8-encoded string to sign. + * @return A {@code String} that contains the HMAC-SHA256-encoded signature. + * @throws InvalidKeyException If the accountKey is not a valid Base64-encoded string. + */ + public String computeHmac256(final String stringToSign) throws InvalidKeyException { + try { + /* + We must get a new instance of the Mac calculator for each signature calculated because the instances are + not threadsafe and there is some suggestion online that they may not even be safe for reuse, so we use a + new one each time to be sure. + */ + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(this.accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + return Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + } catch (final NoSuchAlgorithmException e) { + throw new Error(e); + } + } + + private String buildStringToSign(URL requestURL, String httpMethod, Map headers) { + String contentLength = headers.get("Content-Length"); + contentLength = contentLength.equals("0") ? "" : contentLength; + + // If the x-ms-header exists ignore the Date header + String dateHeader = (headers.containsKey("x-ms-date")) ? "" : getStandardHeaderValue(headers,"Date"); + + return String.join("\n", + httpMethod, + getStandardHeaderValue(headers,"Content-Encoding"), + getStandardHeaderValue(headers,"Content-Language"), + contentLength, + getStandardHeaderValue(headers,"Content-MD5"), + getStandardHeaderValue(headers,"Content-Type"), + dateHeader, + getStandardHeaderValue(headers,"If-Modified-Since"), + getStandardHeaderValue(headers,"If-Match"), + getStandardHeaderValue(headers, "If-None-Match"), + getStandardHeaderValue(headers,"If-Unmodified-Since"), + getStandardHeaderValue(headers, "Range"), + getAdditionalXmsHeaders(headers), + getCanonicalizedResource(requestURL)); + } + + /* + * Returns an empty string if the header value is null or empty. + */ + private String getStandardHeaderValue(Map headers, String headerName) { + final String headerValue = headers.get(headerName); + + return headerValue == null ? "" : headerValue; + } + + private String getAdditionalXmsHeaders(Map headers) { + // Add only headers that begin with 'x-ms-' + final List xmsHeaderNameArray = headers.entrySet().stream() + .filter(entry -> entry.getKey().toLowerCase(Locale.ROOT).startsWith("x-ms-")) + .filter(entry -> entry.getValue() != null) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + if (xmsHeaderNameArray.isEmpty()) { + return ""; + } + + Collections.sort(xmsHeaderNameArray); + + final StringBuilder canonicalizedHeaders = new StringBuilder(); + for (final String key : xmsHeaderNameArray) { + if (canonicalizedHeaders.length() > 0) { + canonicalizedHeaders.append('\n'); + } + + canonicalizedHeaders.append(key) + .append(':') + .append(headers.get(key)); + } + + return canonicalizedHeaders.toString(); + } + + private String getCanonicalizedResource(URL requestURL) { + + // Resource path + final StringBuilder canonicalizedResource = new StringBuilder("/"); + canonicalizedResource.append(accountName); + + // Note that AbsolutePath starts with a '/'. + if (requestURL.getPath().length() > 0) { + canonicalizedResource.append(requestURL.getPath()); + } else { + canonicalizedResource.append('/'); + } + + // check for no query params and return + if (requestURL.getQuery() == null) { + return canonicalizedResource.toString(); + } + + // The URL object's query field doesn't include the '?'. The QueryStringDecoder expects it. + QueryStringDecoder queryDecoder = new QueryStringDecoder("?" + requestURL.getQuery()); + Map> queryParams = queryDecoder.parameters(); + + ArrayList queryParamNames = new ArrayList<>(queryParams.keySet()); + Collections.sort(queryParamNames); + + for (String queryParamName : queryParamNames) { + final List queryParamValues = queryParams.get(queryParamName); + Collections.sort(queryParamValues); + String queryParamValuesStr = String.join(",", queryParamValues); + canonicalizedResource.append("\n") + .append(queryParamName.toLowerCase(Locale.ROOT)) + .append(":") + .append(queryParamValuesStr); + } + + // append to main string builder the join of completed params with new line + return canonicalizedResource.toString(); + } + + private String computeHMACSHA256(String stringToSign) { + try { + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + String signature = Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + return String.format(AUTHORIZATION_HEADER_FORMAT, accountName, signature); + } catch (NoSuchAlgorithmException | InvalidKeyException ex) { + throw new Error(ex); + } + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/credentials/package-info.java b/storage/client/file/src/main/java/com/azure/storage/common/credentials/package-info.java new file mode 100644 index 0000000000000..b03314b4cc0b0 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/credentials/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains credentials used by Azure Storage services. + */ +package com.azure.storage.common.credentials; diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java new file mode 100644 index 0000000000000..edeaf6484ea6a --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import java.util.concurrent.TimeUnit; + +/** + * Options for configuring the {@link RequestRetryPolicy}. Please refer to the Factory for more information. Note + * that there is no option for overall operation timeout. This is because Rx object have a timeout field which provides + * this functionality. + */ +public final class RequestRetryOptions { + + private final int maxTries; + private final int tryTimeout; + private final long retryDelayInMs; + private final long maxRetryDelayInMs; + /** + * A {@link RetryPolicyType} telling the pipeline what kind of retry policy to use. + */ + private RetryPolicyType retryPolicyType; + private String secondaryHost; + + /** + * Constructor with default retry values: Exponential backoff, maxTries=4, tryTimeout=30, retryDelayInMs=4000, + * maxRetryDelayInMs=120000, secondaryHost=null. + */ + public RequestRetryOptions() { + this(RetryPolicyType.EXPONENTIAL, null, + null, null, null, null); + } + + /** + * Configures how the {@link com.azure.core.http.HttpPipeline} should retry requests. + * + * @param retryPolicyType + * A {@link RetryPolicyType} specifying the type of retry pattern to use. A value of {@code null} accepts + * the default. + * @param maxTries + * Specifies the maximum number of attempts an operation will be tried before producing an error. A value of + * {@code null} means that you accept our default policy. A value of 1 means 1 try and no retries. + * @param tryTimeout + * Indicates the maximum time allowed for any single try of an HTTP request. A value of {@code null} means + * that you accept our default. NOTE: When transferring large amounts of data, the default TryTimeout will + * probably not be sufficient. You should override this value based on the bandwidth available to the host + * machine and proximity to the Storage service. A good starting point may be something like (60 seconds per + * MB of anticipated-payload-size). + * @param retryDelayInMs + * Specifies the amount of delay to use before retrying an operation. A value of {@code null} means you + * accept the default value. The delay increases (exponentially or linearly) with each retry up to a maximum + * specified by MaxRetryDelay. If you specify {@code null}, then you must also specify {@code null} for + * MaxRetryDelay. + * @param maxRetryDelayInMs + * Specifies the maximum delay allowed before retrying an operation. A value of {@code null} means you + * accept the default value. If you specify {@code null}, then you must also specify {@code null} for + * RetryDelay. + * @param secondaryHost + * If a secondaryHost is specified, retries will be tried against this host. If secondaryHost is + * {@code null} (the default) then operations are not retried against another host. NOTE: Before setting + * this field, make sure you understand the issues around reading stale and potentially-inconsistent data at + * this webpage + * + *

    Sample Code

    + * + *

    For more samples, please see the samples file

    + */ + public RequestRetryOptions(RetryPolicyType retryPolicyType, Integer maxTries, Integer tryTimeout, + Long retryDelayInMs, Long maxRetryDelayInMs, String secondaryHost) { + this.retryPolicyType = retryPolicyType == null ? RetryPolicyType.EXPONENTIAL : retryPolicyType; + if (maxTries != null) { + assertInBounds("maxRetries", maxTries, 1, Integer.MAX_VALUE); + this.maxTries = maxTries; + } else { + this.maxTries = 4; + } + + if (tryTimeout != null) { + assertInBounds("tryTimeout", tryTimeout, 1, Integer.MAX_VALUE); + this.tryTimeout = tryTimeout; + } else { + this.tryTimeout = 60; + } + + if ((retryDelayInMs == null && maxRetryDelayInMs != null) + || (retryDelayInMs != null && maxRetryDelayInMs == null)) { + throw new IllegalArgumentException("Both retryDelay and maxRetryDelay must be null or neither can be null"); + } + + if (retryDelayInMs != null && maxRetryDelayInMs != null) { + assertInBounds("maxRetryDelayInMs", maxRetryDelayInMs, 1, Long.MAX_VALUE); + assertInBounds("retryDelayInMs", retryDelayInMs, 1, maxRetryDelayInMs); + this.maxRetryDelayInMs = maxRetryDelayInMs; + this.retryDelayInMs = retryDelayInMs; + } else { + switch (this.retryPolicyType) { + case EXPONENTIAL: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(4); + break; + case FIXED: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(30); + break; + default: + throw new IllegalArgumentException("Unrecognize retry policy type."); + } + this.maxRetryDelayInMs = TimeUnit.SECONDS.toMillis(120); + } + + this.secondaryHost = secondaryHost; + } + + int maxTries() { + return this.maxTries; + } + + int tryTimeout() { + return this.tryTimeout; + } + + String secondaryHost() { + return this.secondaryHost; + } + + long retryDelayInMs() { + return retryDelayInMs; + } + + long maxRetryDelayInMs() { + return maxRetryDelayInMs; + } + + /** + * Calculates how long to delay before sending the next request. + * + * @param tryCount + * An {@code int} indicating which try we are on. + * + * @return A {@code long} value of how many milliseconds to delay. + */ + long calculateDelayInMs(int tryCount) { + long delay = 0; + switch (this.retryPolicyType) { + case EXPONENTIAL: + delay = (pow(2L, tryCount - 1) - 1L) * this.retryDelayInMs; + break; + + case FIXED: + delay = this.retryDelayInMs; + break; + default: + throw new IllegalArgumentException("Invalid retry policy type."); + } + + return Math.min(delay, this.maxRetryDelayInMs); + } + + private long pow(long number, int exponent) { + long result = 1; + for (int i = 0; i < exponent; i++) { + result *= number; + } + + return result; + } + + private static void assertInBounds(final String param, final long value, final long min, final long max) { + if (value < min || value > max) { + throw new IllegalArgumentException(String.format("The value of the parameter '%s' should be between %s and %s.", param, min, max)); + } + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java new file mode 100644 index 0000000000000..b862b76928af0 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + + +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.http.UrlBuilder; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.time.Duration; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeoutException; + +/** + * This is a request policy in an {@link com.azure.core.http.HttpPipeline} for retrying a given HTTP request. The request + * that is retried will be identical each time it is reissued. Retries will try against a secondary if one is specified + * and the type of operation/error indicates that the secondary can handle the request. Exponential and fixed backoff are + * supported. The policy must only be used directly when creating a custom pipeline. + */ +public final class RequestRetryPolicy implements HttpPipelinePolicy { + private final RequestRetryOptions requestRetryOptions; + + public RequestRetryPolicy(RequestRetryOptions requestRetryOptions) { + this.requestRetryOptions = requestRetryOptions; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + HttpRequest httpRequest = context.httpRequest(); + boolean considerSecondary = (httpRequest.httpMethod().equals(HttpMethod.GET) + || httpRequest.httpMethod().equals(HttpMethod.HEAD)) + && (this.requestRetryOptions.secondaryHost() != null); + + return this.attemptAsync(httpRequest, next, 1, considerSecondary, 1); + } + + /** + * This method actually attempts to send the request and determines if we should attempt again and, if so, how + * long to wait before sending out the next request. + *

    + * Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) When to retry: connection failure + * or an HTTP status code of 500 or greater, except 501 and 505 If using a secondary: Odd tries go against + * primary; even tries go against the secondary For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, + * 1.2) If secondary gets a 404, don't fail, retry but future retries are only against the primary When retrying + * against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2)) + * + * @param httpRequest + * The request to try. + * @param primaryTry + * This indicates how man tries we've attempted against the primary DC. + * @param considerSecondary + * Before each try, we'll select either the primary or secondary URL if appropriate. + * @param attempt + * This indicates the total number of attempts to send the request. + * + * @return A single containing either the successful response or an error that was not retryable because either + * the maxTries was exceeded or retries will not mitigate the issue. + */ + private Mono attemptAsync(final HttpRequest httpRequest, HttpPipelineNextPolicy next, final int primaryTry, + final boolean considerSecondary, + final int attempt) { + + // Determine which endpoint to try. It's primary if there is no secondary or if it is an odd number attempt. + final boolean tryingPrimary = !considerSecondary || (attempt % 2 != 0); + + // Select the correct host and delay. + long delayMs; + if (tryingPrimary) { + // The first attempt returns 0 delay. + delayMs = this.requestRetryOptions.calculateDelayInMs(primaryTry); + } else { + // Delay with some jitter before trying the secondary. + delayMs = (long) ((ThreadLocalRandom.current().nextFloat() / 2 + 0.8) * 1000); // Add jitter + } + + /* + Clone the original request to ensure that each try starts with the original (unmutated) request. We cannot + simply call httpRequest.buffer() because although the body will start emitting from the beginning of the + stream, the buffers that were emitted will have already been consumed (their position set to their limit), + so it is not a true reset. By adding the map function, we ensure that anything which consumes the + ByteBuffers downstream will only actually consume a duplicate so the original is preserved. This only + duplicates the ByteBuffer object, not the underlying data. + */ + Flux bufferedBody = httpRequest.body() == null + ? null : httpRequest.body().map(ByteBuf::duplicate); + httpRequest.body(bufferedBody); + if (!tryingPrimary) { + UrlBuilder builder = UrlBuilder.parse(httpRequest.url()); + builder.host(this.requestRetryOptions.secondaryHost()); + try { + httpRequest.url(builder.toURL()); + } catch (MalformedURLException e) { + return Mono.error(e); + } + } + + /* + We want to send the request with a given timeout, but we don't want to kickoff that timeout-bound operation + until after the retry backoff delay, so we call delaySubscription. + */ + return next.clone().process() + .timeout(Duration.ofSeconds(this.requestRetryOptions.tryTimeout())) + .delaySubscription(Duration.ofMillis(delayMs)) + .flatMap(response -> { + boolean newConsiderSecondary = considerSecondary; + String action; + int statusCode = response.statusCode(); + + /* + If attempt was against the secondary & it returned a StatusNotFound (404), then the + resource was not found. This may be due to replication delay. So, in this case, + we'll never try the secondary again for this operation. + */ + if (!tryingPrimary && statusCode == 404) { + newConsiderSecondary = false; + action = "Retry: Secondary URL returned 404"; + } else if (statusCode == 503 || statusCode == 500) { + action = "Retry: Temporary error or server timeout"; + } else { + action = "NoRetry: Successful HTTP request"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, newConsiderSecondary, + attempt + 1); + } + return Mono.just(response); + }) + .onErrorResume(throwable -> { + /* + It is likely that many users will not realize that their Flux must be replayable and + get an error upon retries when the provided data length does not match the length of the exact + data. We cannot enforce the desired Flux behavior, so we provide a hint when this is likely + the root cause. + */ + if (throwable instanceof IllegalStateException && attempt > 1) { + return Mono.error(new IllegalStateException("The request failed because the " + + "size of the contents of the provided Flux did not match the provided " + + "data size upon attempting to retry. This is likely caused by the Flux " + + "not being replayable. To support retries, all Fluxes must produce the " + + "same data for each subscriber. Please ensure this behavior.", throwable)); + } + + /* + IOException is a catch-all for IO related errors. Technically it includes many types which may + not be network exceptions, but we should not hit those unless there is a bug in our logic. In + either case, it is better to optimistically retry instead of failing too soon. + A Timeout Exception is a client-side timeout coming from Rx. + */ + String action; + if (throwable instanceof IOException) { + action = "Retry: Network error"; + } else if (throwable instanceof TimeoutException) { + action = "Retry: Client timeout"; + } else { + action = "NoRetry: Unknown error"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, considerSecondary, + attempt + 1); + } + return Mono.error(throwable); + }); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java new file mode 100644 index 0000000000000..bee125775e55d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +/** + * This type holds possible options for retry backoff algorithms. They may be used with {@link RequestRetryOptions}. + */ +public enum RetryPolicyType { + /** + * Tells the pipeline to use an exponential back-off retry policy. + */ + EXPONENTIAL, + + /** + * Tells the pipeline to use a fixed back-off retry policy. + */ + FIXED +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java new file mode 100644 index 0000000000000..ba2debfcd3620 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.storage.common.credentials.SASTokenCredential; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Policy that adds the SAS token to the request URL's query. + */ +public final class SASTokenCredentialPolicy implements HttpPipelinePolicy { + private final SASTokenCredential credential; + + /** + * Creates a SAS token credential policy that appends the SAS token to the request URL's query. + * @param credential SAS token credential + */ + public SASTokenCredentialPolicy(SASTokenCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + try { + URL requestURL = context.httpRequest().url(); + String delimiter = !ImplUtils.isNullOrEmpty(requestURL.getQuery()) ? "&" : "?"; + + String newURL = requestURL.toString() + delimiter + credential.sasToken(); + context.httpRequest().url(new URL(newURL)); + } catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + + return next.process(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java new file mode 100644 index 0000000000000..8ee1284591dd2 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.storage.common.credentials.SharedKeyCredential; +import reactor.core.publisher.Mono; + +/** + * Policy that adds the SharedKey into the request's Authorization header. + */ +public final class SharedKeyCredentialPolicy implements HttpPipelinePolicy { + private final SharedKeyCredential credential; + + /** + * Creates a SharedKey pipeline policy that adds the SharedKey into the request's authorization header. + * @param credential the SharedKey credential used to create the policy. + */ + public SharedKeyCredentialPolicy(SharedKeyCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + String authorizationValue = credential.generateAuthorizationHeader(context.httpRequest().url(), + context.httpRequest().httpMethod().toString(), + context.httpRequest().headers().toMap()); + context.httpRequest().header("Authorization", authorizationValue); + return next.process(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/common/policy/package-info.java b/storage/client/file/src/main/java/com/azure/storage/common/policy/package-info.java new file mode 100644 index 0000000000000..6f36065ea580b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/common/policy/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains policies used by Azure Storage services. + */ +package com.azure.storage.common.policy; diff --git a/storage/client/file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java new file mode 100644 index 0000000000000..0669d18eb92f9 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryAsyncClient.java @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.DirectoryInfo; +import com.azure.storage.file.models.DirectoryProperties; +import com.azure.storage.file.models.FileHTTPHeaders; +import com.azure.storage.file.models.FileRef; +import com.azure.storage.file.models.HandleItem; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class DirectoryAsyncClient { + + DirectoryAsyncClient() { + throw new UnsupportedOperationException(); + } + + public static DirectoryClientBuilder asyncBuilder() { + throw new UnsupportedOperationException(); + } + + public FileAsyncClient getFileClient(String name) { + throw new UnsupportedOperationException(); + } + + public DirectoryAsyncClient getDirectoryClient(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> create(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono delete() { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setMetadata(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Flux listFilesAndDirectories(String prefix, int maxResults, String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Flux getHandles(int maxResult, boolean recursive) { + throw new UnsupportedOperationException(); + } + + public Flux forceCloseHandles(String handleId, boolean recursive) { + throw new UnsupportedOperationException(); + } + + public Mono> createSubDirectory(String directoryName, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteSubDirectory(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> createFile(String fileName, long maxSize, FileHTTPHeaders httpHeaders, Map meatadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteFile(String fileName) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClient.java b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClient.java new file mode 100644 index 0000000000000..22d4063b0f410 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClient.java @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.DirectoryInfo; +import com.azure.storage.file.models.DirectoryProperties; +import com.azure.storage.file.models.FileHTTPHeaders; +import com.azure.storage.file.models.FileRef; +import com.azure.storage.file.models.HandleItem; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class DirectoryClient { + + private final DirectoryAsyncClient client; + + DirectoryClient() { + throw new UnsupportedOperationException(); + } + + public static DirectoryClientBuilder syncBuilder() { + throw new UnsupportedOperationException(); + } + + public FileClient getFileClient(String name) { + throw new UnsupportedOperationException(); + } + + public DirectoryClient getDirectoryClient(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> create(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono delete() { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setMetadata(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Flux listFilesAndDirectories(String prefix, int maxResults, String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Flux getHandles(int maxResult, boolean recursive) { + throw new UnsupportedOperationException(); + } + + public Flux forceCloseHandles(String handleId, boolean recursive) { + throw new UnsupportedOperationException(); + } + + public Mono> createSubDirectory(String directoryName, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteSubDirectory(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> createFile(String fileName, long maxSize, FileHTTPHeaders httpHeaders, Map meatadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteFile(String fileName) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClientBuilder.java b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClientBuilder.java new file mode 100644 index 0000000000000..7bbd3cb138d2e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/DirectoryClientBuilder.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +public class DirectoryClientBuilder { + +// connectionString, shareName, directoryName, FileClientOptions, SharedKeyCredential, +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileAsyncClient.java b/storage/client/file/src/main/java/com/azure/storage/file/FileAsyncClient.java new file mode 100644 index 0000000000000..0297818f4650b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileAsyncClient.java @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.FileCopyInfo; +import com.azure.storage.file.models.FileDownloadInfo; +import com.azure.storage.file.models.FileHTTPHeaders; +import com.azure.storage.file.models.FileInfo; +import com.azure.storage.file.models.FileProperties; +import com.azure.storage.file.models.FileRangeInfo; +import com.azure.storage.file.models.FileRangeWriteType; +import com.azure.storage.file.models.FileUploadInfo; +import com.azure.storage.file.models.HandleItem; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class FileAsyncClient { + FileAsyncClient() { + throw new UnsupportedOperationException(); + } + + public static FileClientBuilder asyncBuilder() { + throw new UnsupportedOperationException(); + } + + public Mono> create(long maxSize, FileHTTPHeaders httpHeaders, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono> startCopy(String sourceUrl, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono abortCopy(String copyId) { + throw new UnsupportedOperationException(); + } + + public Mono> downloadWithProperties(long offset, long length, boolean rangeGetContentMD5) { + throw new UnsupportedOperationException(); + } + + public Mono delete() { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setHttpHeaders(long newFileSize, FileHTTPHeaders httpHeaders) { + throw new UnsupportedOperationException(); + } + + public Mono> setMeatadata(Map meatadata) { + throw new UnsupportedOperationException(); + } + + public Mono> upload(FileRangeWriteType type, long offset, long length, Flux data) { + throw new UnsupportedOperationException(); + } + + public Flux listRanges(long offset, long length, String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Flux listHandles(int maxResults) { + throw new UnsupportedOperationException(); + } + + public Flux forceCloseHandles(String handleId) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileClient.java b/storage/client/file/src/main/java/com/azure/storage/file/FileClient.java new file mode 100644 index 0000000000000..3d6bacb4ff3ea --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileClient.java @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.FileCopyInfo; +import com.azure.storage.file.models.FileDownloadInfo; +import com.azure.storage.file.models.FileHTTPHeaders; +import com.azure.storage.file.models.FileInfo; +import com.azure.storage.file.models.FileProperties; +import com.azure.storage.file.models.FileRangeInfo; +import com.azure.storage.file.models.FileRangeWriteType; +import com.azure.storage.file.models.FileUploadInfo; +import com.azure.storage.file.models.HandleItem; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class FileClient { + private final FileAsyncClient client; + + FileClient() { + throw new UnsupportedOperationException(); + } + + public static FileClientBuilder syncBuilder() { + throw new UnsupportedOperationException(); + } + + public Mono> create(long maxSize, FileHTTPHeaders httpHeaders, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono> startCopy(String sourceUrl, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono abortCopy(String copyId) { + throw new UnsupportedOperationException(); + } + + public Mono> downloadWithProperties(long offset, long length, boolean rangeGetContentMD5) { + throw new UnsupportedOperationException(); + } + + public Mono delete() { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setHttpHeaders(long newFileSize, FileHTTPHeaders httpHeaders) { + throw new UnsupportedOperationException(); + } + + public Mono> setMeatadata(Map meatadata) { + throw new UnsupportedOperationException(); + } + + public Mono> upload(FileRangeWriteType type, long offset, long length, Flux data) { + throw new UnsupportedOperationException(); + } + + public Flux listRanges(long offset, long length, String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Flux listHandles(int maxResults) { + throw new UnsupportedOperationException(); + } + + public Flux forceCloseHandles(String handleId) { + throw new UnsupportedOperationException(); + } +} + diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileClientBuilder.java b/storage/client/file/src/main/java/com/azure/storage/file/FileClientBuilder.java new file mode 100644 index 0000000000000..610466b2aed52 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileClientBuilder.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +public class FileClientBuilder { + + // fileUri, SharedKeyCredential, FileClientOptions ,withSnapshot +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java new file mode 100644 index 0000000000000..9c66716ca61c0 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceAsyncClient.java @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.FileServiceProperties; +import com.azure.storage.file.models.ListSharesOptions; +import com.azure.storage.file.models.ShareItem; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class FileServiceAsyncClient { + + FileServiceAsyncClient() { + throw new UnsupportedOperationException(); + } + + public static FileServiceClientBuilder asyncBuilder() { + throw new UnsupportedOperationException(); + } + + public String url() { + throw new UnsupportedOperationException(); + } + + public ShareAsyncClient getShareClient(String shareName) { + throw new UnsupportedOperationException(); + } + + public Flux listShares(ListSharesOptions options) { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties() { + throw new UnsupportedOperationException(); + } + + public Mono setProperties() { + throw new UnsupportedOperationException(); + } + + public Mono> createShare(String shareName, Map metadata, int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono deleteShare(String shareName, String shareSnapshot) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClient.java b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClient.java new file mode 100644 index 0000000000000..fd808bf1d6fde --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClient.java @@ -0,0 +1,52 @@ +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.FileServiceProperties; +import com.azure.storage.file.models.ListSharesOptions; +import com.azure.storage.file.models.ShareItem; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +public class FileServiceClient { + + private final FileServiceAsyncClient client; + + FileServiceClient() { + throw new UnsupportedOperationException(); + } + + public static FileServiceClientBuilder syncBuilder() { + throw new UnsupportedOperationException(); + } + + public String url() { + throw new UnsupportedOperationException(); + } + + public ShareClient getShareClient(String shareName) { + throw new UnsupportedOperationException(); + } + + public Flux listShares(ListSharesOptions options) { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties() { + throw new UnsupportedOperationException(); + } + + public Mono setProperties() { + throw new UnsupportedOperationException(); + } + + public Mono> createShare(String shareName, Map metadata, int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono deleteShare(String shareName, String shareSnapshot) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java new file mode 100644 index 0000000000000..01148e8af57f5 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/FileServiceClientBuilder.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +public class FileServiceClientBuilder { + + // connection string, FileClientOptions, Uri, SharedKeyCredential +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/ShareAsyncClient.java b/storage/client/file/src/main/java/com/azure/storage/file/ShareAsyncClient.java new file mode 100644 index 0000000000000..d6d1326ba9545 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/ShareAsyncClient.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.ShareInfo; +import com.azure.storage.file.models.ShareProperties; +import com.azure.storage.file.models.ShareSnapshotInfo; +import com.azure.storage.file.models.ShareStatistics; +import com.azure.storage.file.models.SignedIdentifier; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +public class ShareAsyncClient { + + ShareAsyncClient() { + throw new UnsupportedOperationException(); + } + + public static ShareClientBuilder asyncBuilder() { + throw new UnsupportedOperationException(); + } + + public String url() { + throw new UnsupportedOperationException(); + } + + public DirectoryAsyncClient getRootDirectoryClient() { + throw new UnsupportedOperationException(); + } + + public DirectoryAsyncClient getDirectoryClient(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> create(Map metadata, int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono> createSnapshot(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono delete(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setQuota(int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono> setMetadata(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Flux listAccessPolicy() { + throw new UnsupportedOperationException(); + } + public Mono> setAccessPolicy(List permissions) { + throw new UnsupportedOperationException(); + } + + public Mono> getStatistics() { + throw new UnsupportedOperationException(); + } + + public Mono> createDirectory(String directoryName, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteDirectory(String directoryName) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/ShareClient.java b/storage/client/file/src/main/java/com/azure/storage/file/ShareClient.java new file mode 100644 index 0000000000000..17ad31b4aa504 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/ShareClient.java @@ -0,0 +1,82 @@ +package com.azure.storage.file; + +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.VoidResponse; +import com.azure.storage.file.models.ShareInfo; +import com.azure.storage.file.models.ShareProperties; +import com.azure.storage.file.models.ShareSnapshotInfo; +import com.azure.storage.file.models.ShareStatistics; +import com.azure.storage.file.models.SignedIdentifier; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +public class ShareClient { + + private final ShareAsyncClient client; + + ShareClient() { + throw new UnsupportedOperationException(); + } + + public static ShareClientBuilder syncBuilder() { + throw new UnsupportedOperationException(); + } + + public String url() { + throw new UnsupportedOperationException(); + } + + public DirectoryClient getRootDirectoryClient() { + throw new UnsupportedOperationException(); + } + + public DirectoryClient getDirectoryClient(String directoryName) { + throw new UnsupportedOperationException(); + } + + public Mono> create(Map metadata, int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono> createSnapshot(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono delete(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> getProperties(String shareSnapshot) { + throw new UnsupportedOperationException(); + } + + public Mono> setQuota(int quotaInGB) { + throw new UnsupportedOperationException(); + } + + public Mono> setMetadata(Map metadata) { + throw new UnsupportedOperationException(); + } + + public Flux listAccessPolicy() { + throw new UnsupportedOperationException(); + } + public Mono> setAccessPolicy(List permissions) { + throw new UnsupportedOperationException(); + } + + public Mono> getStatistics() { + throw new UnsupportedOperationException(); + } + + public Mono> createDirectory(String directoryName, Map metadata) { + throw new UnsupportedOperationException(); + } + + public Mono deleteDirectory(String directoryName) { + throw new UnsupportedOperationException(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/ShareClientBuilder.java b/storage/client/file/src/main/java/com/azure/storage/file/ShareClientBuilder.java new file mode 100644 index 0000000000000..5ab4e37ddcd3e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/ShareClientBuilder.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file; + +public class ShareClientBuilder { + + // connectionString, shareName, FileClientOptions, withSnapshot, SharedKeyCredential, +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageBuilder.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageBuilder.java new file mode 100644 index 0000000000000..6dced97e93c08 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageBuilder.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * A appendBlobClientBuilder for creating a new instance of the AzureFileStorage type. + */ +public final class AzureFileStorageBuilder { + /* + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the AzureFileStorageBuilder. + */ + public AzureFileStorageBuilder version(String version) { + this.version = version; + return this; + } + + /* + * The URL of the service account, share, directory or file that is the target of the desired operation. + */ + private String url; + + /** + * Sets The URL of the service account, share, directory or file that is the target of the desired operation. + * + * @param url the url value. + * @return the AzureFileStorageBuilder. + */ + public AzureFileStorageBuilder url(String url) { + this.url = url; + return this; + } + + /* + * The HTTP pipeline to send requests through + */ + private HttpPipeline pipeline; + + /** + * Sets The HTTP pipeline to send requests through. + * + * @param pipeline the pipeline value. + * @return the AzureFileStorageBuilder. + */ + public AzureFileStorageBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + /** + * Builds an instance of AzureFileStorageImpl with the provided parameters. + * + * @return an instance of AzureFileStorageImpl. + */ + public AzureFileStorageImpl build() { + if (version == null) { + this.version = "2018-11-09"; + } + if (pipeline == null) { + this.pipeline = RestProxy.createDefaultPipeline(); + } + AzureFileStorageImpl client = new AzureFileStorageImpl(pipeline); + if (this.version != null) { + client.version(this.version); + } + if (this.url != null) { + client.url(this.url); + } + return client; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageImpl.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageImpl.java new file mode 100644 index 0000000000000..ec39450873537 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/AzureFileStorageImpl.java @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.ServiceClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * Initializes a new instance of the AzureFileStorage type. + */ +public final class AzureFileStorageImpl extends ServiceClient { + /** + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Gets Specifies the version of the operation to use for this request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the service client itself. + */ + AzureFileStorageImpl version(String version) { + this.version = version; + return this; + } + + /** + * The URL of the service account, share, directory or file that is the target of the desired operation. + */ + private String url; + + /** + * Gets The URL of the service account, share, directory or file that is the target of the desired operation. + * + * @return the url value. + */ + public String url() { + return this.url; + } + + /** + * Sets The URL of the service account, share, directory or file that is the target of the desired operation. + * + * @param url the url value. + * @return the service client itself. + */ + AzureFileStorageImpl url(String url) { + this.url = url; + return this; + } + + /** + * The ServicesImpl object to access its operations. + */ + private ServicesImpl services; + + /** + * Gets the ServicesImpl object to access its operations. + * + * @return the ServicesImpl object. + */ + public ServicesImpl services() { + return this.services; + } + + /** + * The SharesImpl object to access its operations. + */ + private SharesImpl shares; + + /** + * Gets the SharesImpl object to access its operations. + * + * @return the SharesImpl object. + */ + public SharesImpl shares() { + return this.shares; + } + + /** + * The DirectorysImpl object to access its operations. + */ + private DirectorysImpl directorys; + + /** + * Gets the DirectorysImpl object to access its operations. + * + * @return the DirectorysImpl object. + */ + public DirectorysImpl directorys() { + return this.directorys; + } + + /** + * The FilesImpl object to access its operations. + */ + private FilesImpl files; + + /** + * Gets the FilesImpl object to access its operations. + * + * @return the FilesImpl object. + */ + public FilesImpl files() { + return this.files; + } + + /** + * Initializes an instance of AzureFileStorage client. + */ + public AzureFileStorageImpl() { + this(RestProxy.createDefaultPipeline()); + } + + /** + * Initializes an instance of AzureFileStorage client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + */ + public AzureFileStorageImpl(HttpPipeline httpPipeline) { + super(httpPipeline); + this.services = new ServicesImpl(this); + this.shares = new SharesImpl(this); + this.directorys = new DirectorysImpl(this); + this.files = new FilesImpl(this); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/DirectorysImpl.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/DirectorysImpl.java new file mode 100644 index 0000000000000..4e3f44c781ef9 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/DirectorysImpl.java @@ -0,0 +1,314 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.file.models.DirectorysCreateResponse; +import com.azure.storage.file.models.DirectorysDeleteResponse; +import com.azure.storage.file.models.DirectorysForceCloseHandlesResponse; +import com.azure.storage.file.models.DirectorysGetPropertiesResponse; +import com.azure.storage.file.models.DirectorysListFilesAndDirectoriesSegmentResponse; +import com.azure.storage.file.models.DirectorysListHandlesResponse; +import com.azure.storage.file.models.DirectorysSetMetadataResponse; +import com.azure.storage.file.models.StorageErrorException; +import reactor.core.publisher.Mono; + +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Directorys. + */ +public final class DirectorysImpl { + /** + * The proxy service used to perform REST calls. + */ + private DirectorysService service; + + /** + * The service client containing this operation class. + */ + private AzureFileStorageImpl client; + + /** + * Initializes an instance of DirectorysImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public DirectorysImpl(AzureFileStorageImpl client) { + this.service = RestProxy.create(DirectorysService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Directorys to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Files Directory") + private interface DirectorysService { + @PUT("{shareName}/{directory}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, Context context); + + @GET("{shareName}/{directory}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, Context context); + + @DELETE("{shareName}/{directory}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, Context context); + + @PUT("{shareName}/{directory}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}/{directory}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listFilesAndDirectoriesSegment(@HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}/{directory}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listHandles(@HostParam("url") String url, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("timeout") Integer timeout, @QueryParam("sharesnapshot") String sharesnapshot, @HeaderParam("x-ms-recursive") Boolean recursive, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}/{directory}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono forceCloseHandles(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @QueryParam("marker") String marker, @QueryParam("sharesnapshot") String sharesnapshot, @HeaderParam("x-ms-handle-id") String handleId, @HeaderParam("x-ms-recursive") Boolean recursive, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + } + + /** + * Creates a new directory under the specified share or parent directory. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String restype = "directory"; + return service.create(this.client.url(), timeout, metadata, this.client.version(), restype, context); + } + + /** + * Creates a new directory under the specified share or parent directory. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Integer timeout, Map metadata, Context context) { + final String restype = "directory"; + return service.create(this.client.url(), timeout, metadata, this.client.version(), restype, context); + } + + /** + * Returns all system properties for the specified directory, and can also be used to check the existence of a directory. The data returned does not include the files in the directory or any subdirectories. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final String sharesnapshot = null; + final Integer timeout = null; + final String restype = "directory"; + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), restype, context); + } + + /** + * Returns all system properties for the specified directory, and can also be used to check the existence of a directory. The data returned does not include the files in the directory or any subdirectories. + * + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String sharesnapshot, Integer timeout, Context context) { + final String restype = "directory"; + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), restype, context); + } + + /** + * Removes the specified empty directory. Note that the directory must be empty before it can be deleted. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String restype = "directory"; + return service.delete(this.client.url(), timeout, this.client.version(), restype, context); + } + + /** + * Removes the specified empty directory. Note that the directory must be empty before it can be deleted. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Integer timeout, Context context) { + final String restype = "directory"; + return service.delete(this.client.url(), timeout, this.client.version(), restype, context); + } + + /** + * Updates user defined metadata for the specified directory. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String restype = "directory"; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Updates user defined metadata for the specified directory. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Integer timeout, Map metadata, Context context) { + final String restype = "directory"; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Returns a list of files or directories under the specified share or directory. It lists the contents only for a single level of the directory hierarchy. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listFilesAndDirectoriesSegmentWithRestResponseAsync(Context context) { + final String prefix = null; + final String sharesnapshot = null; + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String restype = "directory"; + final String comp = "list"; + return service.listFilesAndDirectoriesSegment(this.client.url(), prefix, sharesnapshot, marker, maxresults, timeout, this.client.version(), restype, comp, context); + } + + /** + * Returns a list of files or directories under the specified share or directory. It lists the contents only for a single level of the directory hierarchy. + * + * @param prefix Filters the results to return only entries whose name begins with the specified prefix. + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of entries to return. If the request does not specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 items. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listFilesAndDirectoriesSegmentWithRestResponseAsync(String prefix, String sharesnapshot, String marker, Integer maxresults, Integer timeout, Context context) { + final String restype = "directory"; + final String comp = "list"; + return service.listFilesAndDirectoriesSegment(this.client.url(), prefix, sharesnapshot, marker, maxresults, timeout, this.client.version(), restype, comp, context); + } + + /** + * Lists handles for directory. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listHandlesWithRestResponseAsync(Context context) { + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String sharesnapshot = null; + final Boolean recursive = null; + final String comp = "listhandles"; + return service.listHandles(this.client.url(), marker, maxresults, timeout, sharesnapshot, recursive, this.client.version(), comp, context); + } + + /** + * Lists handles for directory. + * + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of entries to return. If the request does not specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 items. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param recursive Specifies operation should apply to the directory specified in the URI, its files, its subdirectories and their files. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listHandlesWithRestResponseAsync(String marker, Integer maxresults, Integer timeout, String sharesnapshot, Boolean recursive, Context context) { + final String comp = "listhandles"; + return service.listHandles(this.client.url(), marker, maxresults, timeout, sharesnapshot, recursive, this.client.version(), comp, context); + } + + /** + * Closes all handles open for given directory. + * + * @param handleId Specifies handle ID opened on the file or directory to be closed. Asterix (‘*’) is a wildcard that specifies all handles. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono forceCloseHandlesWithRestResponseAsync(String handleId, Context context) { + final Integer timeout = null; + final String marker = null; + final String sharesnapshot = null; + final Boolean recursive = null; + final String comp = "forceclosehandles"; + return service.forceCloseHandles(this.client.url(), timeout, marker, sharesnapshot, handleId, recursive, this.client.version(), comp, context); + } + + /** + * Closes all handles open for given directory. + * + * @param handleId Specifies handle ID opened on the file or directory to be closed. Asterix (‘*’) is a wildcard that specifies all handles. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param recursive Specifies operation should apply to the directory specified in the URI, its files, its subdirectories and their files. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono forceCloseHandlesWithRestResponseAsync(String handleId, Integer timeout, String marker, String sharesnapshot, Boolean recursive, Context context) { + final String comp = "forceclosehandles"; + return service.forceCloseHandles(this.client.url(), timeout, marker, sharesnapshot, handleId, recursive, this.client.version(), comp, context); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/FilesImpl.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/FilesImpl.java new file mode 100644 index 0000000000000..ee44ffe4f9830 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/FilesImpl.java @@ -0,0 +1,551 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HEAD; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.util.Base64Util; +import com.azure.core.util.Context; +import com.azure.storage.file.models.FileHTTPHeaders; +import com.azure.storage.file.models.FileRangeWriteType; +import com.azure.storage.file.models.FilesAbortCopyResponse; +import com.azure.storage.file.models.FilesCreateResponse; +import com.azure.storage.file.models.FilesDeleteResponse; +import com.azure.storage.file.models.FilesDownloadResponse; +import com.azure.storage.file.models.FilesForceCloseHandlesResponse; +import com.azure.storage.file.models.FilesGetPropertiesResponse; +import com.azure.storage.file.models.FilesGetRangeListResponse; +import com.azure.storage.file.models.FilesListHandlesResponse; +import com.azure.storage.file.models.FilesSetHTTPHeadersResponse; +import com.azure.storage.file.models.FilesSetMetadataResponse; +import com.azure.storage.file.models.FilesStartCopyResponse; +import com.azure.storage.file.models.FilesUploadRangeResponse; +import com.azure.storage.file.models.StorageErrorException; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Files. + */ +public final class FilesImpl { + /** + * The proxy service used to perform REST calls. + */ + private FilesService service; + + /** + * The service client containing this operation class. + */ + private AzureFileStorageImpl client; + + /** + * Initializes an instance of FilesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public FilesImpl(AzureFileStorageImpl client) { + this.service = RestProxy.create(FilesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Files to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Files File") + private interface FilesService { + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-content-length") long fileContentLength, @HeaderParam("x-ms-type") String fileTypeConstant, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-content-type") String fileContentType, @HeaderParam("x-ms-content-encoding") String fileContentEncoding, @HeaderParam("x-ms-content-language") String fileContentLanguage, @HeaderParam("x-ms-cache-control") String fileCacheControl, @HeaderParam("x-ms-content-md5") String fileContentMD5, @HeaderParam("x-ms-content-disposition") String fileContentDisposition, Context context); + + @GET("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200, 206}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono download(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-range-get-content-md5") Boolean rangeGetContentMD5, Context context); + + @HEAD("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + Mono getProperties(@HostParam("url") String url, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, Context context); + + @DELETE("{shareName}/{directory}/{fileName}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setHTTPHeaders(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-content-length") Long fileContentLength, @QueryParam("comp") String comp, @HeaderParam("x-ms-content-type") String fileContentType, @HeaderParam("x-ms-content-encoding") String fileContentEncoding, @HeaderParam("x-ms-content-language") String fileContentLanguage, @HeaderParam("x-ms-cache-control") String fileCacheControl, @HeaderParam("x-ms-content-md5") String fileContentMD5, @HeaderParam("x-ms-content-disposition") String fileContentDisposition, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono uploadRange(@HostParam("url") String url, @BodyParam("application/octet-stream") Flux optionalbody, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-range") String range, @HeaderParam("x-ms-write") FileRangeWriteType fileRangeWrite, @HeaderParam("Content-Length") long contentLength, @HeaderParam("Content-MD5") String contentMD5, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getRangeList(@HostParam("url") String url, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-range") String range, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono startCopy(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-copy-source") String copySource, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono abortCopy(@HostParam("url") String url, @QueryParam("copyid") String copyId, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-copy-action") String copyActionAbortConstant, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listHandles(@HostParam("url") String url, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("timeout") Integer timeout, @QueryParam("sharesnapshot") String sharesnapshot, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}/{directory}/{fileName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono forceCloseHandles(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @QueryParam("marker") String marker, @QueryParam("sharesnapshot") String sharesnapshot, @HeaderParam("x-ms-handle-id") String handleId, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + } + + /** + * Creates a new file or replaces a file. Note it only initializes the file with no content. + * + * @param fileContentLength Specifies the maximum size for the file, up to 1 TB. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(long fileContentLength, Context context) { + final Integer timeout = null; + final String fileTypeConstant = "file"; + final Map metadata = null; + final String fileContentType = null; + final String fileContentEncoding = null; + final String fileContentLanguage = null; + final String fileCacheControl = null; + final String fileContentDisposition = null; + String fileContentMD5Converted = null; + return service.create(this.client.url(), timeout, this.client.version(), fileContentLength, fileTypeConstant, metadata, fileContentType, fileContentEncoding, fileContentLanguage, fileCacheControl, fileContentMD5Converted, fileContentDisposition, context); + } + + /** + * Creates a new file or replaces a file. Note it only initializes the file with no content. + * + * @param fileContentLength Specifies the maximum size for the file, up to 1 TB. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param fileHTTPHeaders Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(long fileContentLength, Integer timeout, Map metadata, FileHTTPHeaders fileHTTPHeaders, Context context) { + final String fileTypeConstant = "file"; + String fileContentType = null; + if (fileHTTPHeaders != null) { + fileContentType = fileHTTPHeaders.fileContentType(); + } + String fileContentEncoding = null; + if (fileHTTPHeaders != null) { + fileContentEncoding = fileHTTPHeaders.fileContentEncoding(); + } + String fileContentLanguage = null; + if (fileHTTPHeaders != null) { + fileContentLanguage = fileHTTPHeaders.fileContentLanguage(); + } + String fileCacheControl = null; + if (fileHTTPHeaders != null) { + fileCacheControl = fileHTTPHeaders.fileCacheControl(); + } + byte[] fileContentMD5 = null; + if (fileHTTPHeaders != null) { + fileContentMD5 = fileHTTPHeaders.fileContentMD5(); + } + String fileContentDisposition = null; + if (fileHTTPHeaders != null) { + fileContentDisposition = fileHTTPHeaders.fileContentDisposition(); + } + String fileContentMD5Converted = Base64Util.encodeToString(fileContentMD5); + return service.create(this.client.url(), timeout, this.client.version(), fileContentLength, fileTypeConstant, metadata, fileContentType, fileContentEncoding, fileContentLanguage, fileCacheControl, fileContentMD5Converted, fileContentDisposition, context); + } + + /** + * Reads or downloads a file from the system, including its metadata and properties. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono downloadWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String range = null; + final Boolean rangeGetContentMD5 = null; + return service.download(this.client.url(), timeout, this.client.version(), range, rangeGetContentMD5, context); + } + + /** + * Reads or downloads a file from the system, including its metadata and properties. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param range Return file data only from the specified byte range. + * @param rangeGetContentMD5 When this header is set to true and specified together with the Range header, the service returns the MD5 hash for the range, as long as the range is less than or equal to 4 MB in size. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono downloadWithRestResponseAsync(Integer timeout, String range, Boolean rangeGetContentMD5, Context context) { + return service.download(this.client.url(), timeout, this.client.version(), range, rangeGetContentMD5, context); + } + + /** + * Returns all user-defined metadata, standard HTTP properties, and system properties for the file. It does not return the content of the file. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final String sharesnapshot = null; + final Integer timeout = null; + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), context); + } + + /** + * Returns all user-defined metadata, standard HTTP properties, and system properties for the file. It does not return the content of the file. + * + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String sharesnapshot, Integer timeout, Context context) { + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), context); + } + + /** + * removes the file from the storage account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Context context) { + final Integer timeout = null; + return service.delete(this.client.url(), timeout, this.client.version(), context); + } + + /** + * removes the file from the storage account. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Integer timeout, Context context) { + return service.delete(this.client.url(), timeout, this.client.version(), context); + } + + /** + * Sets HTTP headers on the file. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setHTTPHeadersWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Long fileContentLength = null; + final String comp = "properties"; + final String fileContentType = null; + final String fileContentEncoding = null; + final String fileContentLanguage = null; + final String fileCacheControl = null; + final String fileContentDisposition = null; + String fileContentMD5Converted = null; + return service.setHTTPHeaders(this.client.url(), timeout, this.client.version(), fileContentLength, comp, fileContentType, fileContentEncoding, fileContentLanguage, fileCacheControl, fileContentMD5Converted, fileContentDisposition, context); + } + + /** + * Sets HTTP headers on the file. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param fileContentLength Resizes a file to the specified size. If the specified byte value is less than the current size of the file, then all ranges above the specified byte value are cleared. + * @param fileHTTPHeaders Additional parameters for the operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setHTTPHeadersWithRestResponseAsync(Integer timeout, Long fileContentLength, FileHTTPHeaders fileHTTPHeaders, Context context) { + final String comp = "properties"; + String fileContentType = null; + if (fileHTTPHeaders != null) { + fileContentType = fileHTTPHeaders.fileContentType(); + } + String fileContentEncoding = null; + if (fileHTTPHeaders != null) { + fileContentEncoding = fileHTTPHeaders.fileContentEncoding(); + } + String fileContentLanguage = null; + if (fileHTTPHeaders != null) { + fileContentLanguage = fileHTTPHeaders.fileContentLanguage(); + } + String fileCacheControl = null; + if (fileHTTPHeaders != null) { + fileCacheControl = fileHTTPHeaders.fileCacheControl(); + } + byte[] fileContentMD5 = null; + if (fileHTTPHeaders != null) { + fileContentMD5 = fileHTTPHeaders.fileContentMD5(); + } + String fileContentDisposition = null; + if (fileHTTPHeaders != null) { + fileContentDisposition = fileHTTPHeaders.fileContentDisposition(); + } + String fileContentMD5Converted = Base64Util.encodeToString(fileContentMD5); + return service.setHTTPHeaders(this.client.url(), timeout, this.client.version(), fileContentLength, comp, fileContentType, fileContentEncoding, fileContentLanguage, fileCacheControl, fileContentMD5Converted, fileContentDisposition, context); + } + + /** + * Updates user-defined metadata for the specified file. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), comp, context); + } + + /** + * Updates user-defined metadata for the specified file. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Integer timeout, Map metadata, Context context) { + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), comp, context); + } + + /** + * Upload a range of bytes to a file. + * + * @param range Specifies the range of bytes to be written. Both the start and end of the range must be specified. For an update operation, the range can be up to 4 MB in size. For a clear operation, the range can be up to the value of the file's full size. The File service accepts only a single byte range for the Range and 'x-ms-range' headers, and the byte range must be specified in the following format: bytes=startByte-endByte. + * @param fileRangeWrite Specify one of the following options: - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update. - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and set the Range header to a value that indicates the range to clear, up to maximum file size. Possible values include: 'update', 'clear'. + * @param contentLength Specifies the number of bytes being transmitted in the request body. When the x-ms-write header is set to clear, the value of this header must be set to zero. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadRangeWithRestResponseAsync(String range, FileRangeWriteType fileRangeWrite, long contentLength, Context context) { + final Flux optionalbody = null; + final Integer timeout = null; + final String comp = "range"; + String contentMD5Converted = null; + return service.uploadRange(this.client.url(), optionalbody, timeout, range, fileRangeWrite, contentLength, contentMD5Converted, this.client.version(), comp, context); + } + + /** + * Upload a range of bytes to a file. + * + * @param range Specifies the range of bytes to be written. Both the start and end of the range must be specified. For an update operation, the range can be up to 4 MB in size. For a clear operation, the range can be up to the value of the file's full size. The File service accepts only a single byte range for the Range and 'x-ms-range' headers, and the byte range must be specified in the following format: bytes=startByte-endByte. + * @param fileRangeWrite Specify one of the following options: - Update: Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update. - Clear: Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and set the Range header to a value that indicates the range to clear, up to maximum file size. Possible values include: 'update', 'clear'. + * @param contentLength Specifies the number of bytes being transmitted in the request body. When the x-ms-write header is set to clear, the value of this header must be set to zero. + * @param optionalbody Initial data. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param contentMD5 An MD5 hash of the content. This hash is used to verify the integrity of the data during transport. When the Content-MD5 header is specified, the File service compares the hash of the content that has arrived with the header value that was sent. If the two hashes do not match, the operation will fail with error code 400 (Bad Request). + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono uploadRangeWithRestResponseAsync(String range, FileRangeWriteType fileRangeWrite, long contentLength, Flux optionalbody, Integer timeout, byte[] contentMD5, Context context) { + final String comp = "range"; + String contentMD5Converted = Base64Util.encodeToString(contentMD5); + return service.uploadRange(this.client.url(), optionalbody, timeout, range, fileRangeWrite, contentLength, contentMD5Converted, this.client.version(), comp, context); + } + + /** + * Returns the list of valid ranges for a file. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getRangeListWithRestResponseAsync(Context context) { + final String sharesnapshot = null; + final Integer timeout = null; + final String range = null; + final String comp = "rangelist"; + return service.getRangeList(this.client.url(), sharesnapshot, timeout, this.client.version(), range, comp, context); + } + + /** + * Returns the list of valid ranges for a file. + * + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param range Specifies the range of bytes over which to list ranges, inclusively. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getRangeListWithRestResponseAsync(String sharesnapshot, Integer timeout, String range, Context context) { + final String comp = "rangelist"; + return service.getRangeList(this.client.url(), sharesnapshot, timeout, this.client.version(), range, comp, context); + } + + /** + * Copies a blob or file to a destination file within the storage account. + * + * @param copySource Specifies the URL of the source file or blob, up to 2 KB in length. To copy a file to another file within the same storage account, you may use Shared Key to authenticate the source file. If you are copying a file from another storage account, or if you are copying a blob from the same storage account or another storage account, then you must authenticate the source file or blob using a shared access signature. If the source is a public blob, no authentication is required to perform the copy operation. A file in a share snapshot can also be specified as a copy source. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono startCopyWithRestResponseAsync(String copySource, Context context) { + final Integer timeout = null; + final Map metadata = null; + return service.startCopy(this.client.url(), timeout, this.client.version(), metadata, copySource, context); + } + + /** + * Copies a blob or file to a destination file within the storage account. + * + * @param copySource Specifies the URL of the source file or blob, up to 2 KB in length. To copy a file to another file within the same storage account, you may use Shared Key to authenticate the source file. If you are copying a file from another storage account, or if you are copying a blob from the same storage account or another storage account, then you must authenticate the source file or blob using a shared access signature. If the source is a public blob, no authentication is required to perform the copy operation. A file in a share snapshot can also be specified as a copy source. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono startCopyWithRestResponseAsync(String copySource, Integer timeout, Map metadata, Context context) { + return service.startCopy(this.client.url(), timeout, this.client.version(), metadata, copySource, context); + } + + /** + * Aborts a pending Copy File operation, and leaves a destination file with zero length and full metadata. + * + * @param copyId The copy identifier provided in the x-ms-copy-id header of the original Copy File operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono abortCopyWithRestResponseAsync(String copyId, Context context) { + final Integer timeout = null; + final String copyActionAbortConstant = "abort"; + final String comp = "copy"; + return service.abortCopy(this.client.url(), copyId, timeout, copyActionAbortConstant, this.client.version(), comp, context); + } + + /** + * Aborts a pending Copy File operation, and leaves a destination file with zero length and full metadata. + * + * @param copyId The copy identifier provided in the x-ms-copy-id header of the original Copy File operation. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono abortCopyWithRestResponseAsync(String copyId, Integer timeout, Context context) { + final String copyActionAbortConstant = "abort"; + final String comp = "copy"; + return service.abortCopy(this.client.url(), copyId, timeout, copyActionAbortConstant, this.client.version(), comp, context); + } + + /** + * Lists handles for file. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listHandlesWithRestResponseAsync(Context context) { + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String sharesnapshot = null; + final String comp = "listhandles"; + return service.listHandles(this.client.url(), marker, maxresults, timeout, sharesnapshot, this.client.version(), comp, context); + } + + /** + * Lists handles for file. + * + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of entries to return. If the request does not specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 items. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listHandlesWithRestResponseAsync(String marker, Integer maxresults, Integer timeout, String sharesnapshot, Context context) { + final String comp = "listhandles"; + return service.listHandles(this.client.url(), marker, maxresults, timeout, sharesnapshot, this.client.version(), comp, context); + } + + /** + * Closes all handles open for given file. + * + * @param handleId Specifies handle ID opened on the file or directory to be closed. Asterix (‘*’) is a wildcard that specifies all handles. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono forceCloseHandlesWithRestResponseAsync(String handleId, Context context) { + final Integer timeout = null; + final String marker = null; + final String sharesnapshot = null; + final String comp = "forceclosehandles"; + return service.forceCloseHandles(this.client.url(), timeout, marker, sharesnapshot, handleId, this.client.version(), comp, context); + } + + /** + * Closes all handles open for given file. + * + * @param handleId Specifies handle ID opened on the file or directory to be closed. Asterix (‘*’) is a wildcard that specifies all handles. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono forceCloseHandlesWithRestResponseAsync(String handleId, Integer timeout, String marker, String sharesnapshot, Context context) { + final String comp = "forceclosehandles"; + return service.forceCloseHandles(this.client.url(), timeout, marker, sharesnapshot, handleId, this.client.version(), comp, context); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/ListSharesIncludeTypeWrapper.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/ListSharesIncludeTypeWrapper.java new file mode 100644 index 0000000000000..280a657b38196 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/ListSharesIncludeTypeWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.storage.file.models.ListSharesIncludeType; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<ListSharesIncludeType> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "ListSharesIncludeType") +public final class ListSharesIncludeTypeWrapper { + @JacksonXmlProperty(localName = "ListSharesIncludeType") + private final List listSharesIncludeType; + + /** + * Creates an instance of ListSharesIncludeTypeWrapper. + * + * @param listSharesIncludeType the list. + */ + @JsonCreator + public ListSharesIncludeTypeWrapper(@JsonProperty("ListSharesIncludeType") List listSharesIncludeType) { + this.listSharesIncludeType = listSharesIncludeType; + } + + /** + * Get the List<ListSharesIncludeType> contained in this wrapper. + * + * @return the List<ListSharesIncludeType>. + */ + public List items() { + return listSharesIncludeType; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/ServicesImpl.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/ServicesImpl.java new file mode 100644 index 0000000000000..5fcf68a794327 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/ServicesImpl.java @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.CollectionFormat; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.serializer.jackson.JacksonAdapter; +import com.azure.core.util.Context; +import com.azure.storage.file.models.ListSharesIncludeType; +import com.azure.storage.file.models.ServicesGetPropertiesResponse; +import com.azure.storage.file.models.ServicesListSharesSegmentResponse; +import com.azure.storage.file.models.ServicesSetPropertiesResponse; +import com.azure.storage.file.models.StorageErrorException; +import com.azure.storage.file.models.StorageServiceProperties; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * An instance of this class provides access to all the operations defined in + * Services. + */ +public final class ServicesImpl { + /** + * The proxy service used to perform REST calls. + */ + private ServicesService service; + + /** + * The service client containing this operation class. + */ + private AzureFileStorageImpl client; + + /** + * Initializes an instance of ServicesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public ServicesImpl(AzureFileStorageImpl client) { + this.service = RestProxy.create(ServicesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Services to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Files Service") + private interface ServicesService { + @PUT("") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setProperties(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") StorageServiceProperties storageServiceProperties, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listSharesSegment(@HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("include") String include, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("comp") String comp, Context context); + } + + /** + * Sets properties for a storage account's File service endpoint, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Context context) { + final Integer timeout = null; + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), restype, comp, context); + } + + /** + * Sets properties for a storage account's File service endpoint, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Integer timeout, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), restype, comp, context); + } + + /** + * Gets the properties of a storage account's File service, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), restype, comp, context); + } + + /** + * Gets the properties of a storage account's File service, including properties for Storage Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Integer timeout, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), restype, comp, context); + } + + /** + * The List Shares Segment operation returns a list of the shares and share snapshots under the specified account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listSharesSegmentWithRestResponseAsync(Context context) { + final String prefix = null; + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String comp = "list"; + String includeConverted = null; + return service.listSharesSegment(this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), comp, context); + } + + /** + * The List Shares Segment operation returns a list of the shares and share snapshots under the specified account. + * + * @param prefix Filters the results to return only entries whose name begins with the specified prefix. + * @param marker A string value that identifies the portion of the list to be returned with the next list operation. The operation returns a marker value within the response body if the list returned was not complete. The marker value may then be used in a subsequent call to request the next set of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of entries to return. If the request does not specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 items. + * @param include Include this parameter to specify one or more datasets to include in the response. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listSharesSegmentWithRestResponseAsync(String prefix, String marker, Integer maxresults, List include, Integer timeout, Context context) { + final String comp = "list"; + String includeConverted = JacksonAdapter.createDefaultSerializerAdapter().serializeList(include, CollectionFormat.CSV); + return service.listSharesSegment(this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), comp, context); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/SharesImpl.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/SharesImpl.java new file mode 100644 index 0000000000000..bdc5fbadff999 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/SharesImpl.java @@ -0,0 +1,379 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.file.models.DeleteSnapshotsOptionType; +import com.azure.storage.file.models.SharesCreateResponse; +import com.azure.storage.file.models.SharesCreateSnapshotResponse; +import com.azure.storage.file.models.SharesDeleteResponse; +import com.azure.storage.file.models.SharesGetAccessPolicyResponse; +import com.azure.storage.file.models.SharesGetPropertiesResponse; +import com.azure.storage.file.models.SharesGetStatisticsResponse; +import com.azure.storage.file.models.SharesSetAccessPolicyResponse; +import com.azure.storage.file.models.SharesSetMetadataResponse; +import com.azure.storage.file.models.SharesSetQuotaResponse; +import com.azure.storage.file.models.SignedIdentifier; +import com.azure.storage.file.models.StorageErrorException; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Shares. + */ +public final class SharesImpl { + /** + * The proxy service used to perform REST calls. + */ + private SharesService service; + + /** + * The service client containing this operation class. + */ + private AzureFileStorageImpl client; + + /** + * Initializes an instance of SharesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public SharesImpl(AzureFileStorageImpl client) { + this.service = RestProxy.create(SharesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Shares to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Files Shares") + private interface SharesService { + @PUT("{shareName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-share-quota") Integer quota, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, Context context); + + @GET("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, Context context); + + @DELETE("{shareName}") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@HostParam("url") String url, @QueryParam("sharesnapshot") String sharesnapshot, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-delete-snapshots") DeleteSnapshotsOptionType deleteSnapshots, @QueryParam("restype") String restype, Context context); + + @PUT("{shareName}") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono createSnapshot(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setQuota(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-share-quota") Integer quota, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccessPolicy(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @PUT("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setAccessPolicy(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") SignedIdentifiersWrapper shareAcl, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("{shareName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getStatistics(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + } + + /** + * Creates a new share under the specified account. If the share with the same name already exists, the operation fails. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final Integer quota = null; + final String restype = "share"; + return service.create(this.client.url(), timeout, metadata, quota, this.client.version(), restype, context); + } + + /** + * Creates a new share under the specified account. If the share with the same name already exists, the operation fails. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param quota Specifies the maximum size of the share, in gigabytes. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Integer timeout, Map metadata, Integer quota, Context context) { + final String restype = "share"; + return service.create(this.client.url(), timeout, metadata, quota, this.client.version(), restype, context); + } + + /** + * Returns all user-defined metadata and system properties for the specified share or share snapshot. The data returned does not include the share's list of files. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final String sharesnapshot = null; + final Integer timeout = null; + final String restype = "share"; + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), restype, context); + } + + /** + * Returns all user-defined metadata and system properties for the specified share or share snapshot. The data returned does not include the share's list of files. + * + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(String sharesnapshot, Integer timeout, Context context) { + final String restype = "share"; + return service.getProperties(this.client.url(), sharesnapshot, timeout, this.client.version(), restype, context); + } + + /** + * Operation marks the specified share or share snapshot for deletion. The share or share snapshot and any files contained within it are later deleted during garbage collection. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Context context) { + final String sharesnapshot = null; + final Integer timeout = null; + final DeleteSnapshotsOptionType deleteSnapshots = null; + final String restype = "share"; + return service.delete(this.client.url(), sharesnapshot, timeout, this.client.version(), deleteSnapshots, restype, context); + } + + /** + * Operation marks the specified share or share snapshot for deletion. The share or share snapshot and any files contained within it are later deleted during garbage collection. + * + * @param sharesnapshot The snapshot parameter is an opaque DateTime value that, when present, specifies the share snapshot to query. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param deleteSnapshots Specifies the option include to delete the base share and all of its snapshots. Possible values include: 'include'. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String sharesnapshot, Integer timeout, DeleteSnapshotsOptionType deleteSnapshots, Context context) { + final String restype = "share"; + return service.delete(this.client.url(), sharesnapshot, timeout, this.client.version(), deleteSnapshots, restype, context); + } + + /** + * Creates a read-only snapshot of a share. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createSnapshotWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String restype = "share"; + final String comp = "snapshot"; + return service.createSnapshot(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Creates a read-only snapshot of a share. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createSnapshotWithRestResponseAsync(Integer timeout, Map metadata, Context context) { + final String restype = "share"; + final String comp = "snapshot"; + return service.createSnapshot(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Sets quota for the specified share. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setQuotaWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Integer quota = null; + final String restype = "share"; + final String comp = "properties"; + return service.setQuota(this.client.url(), timeout, this.client.version(), quota, restype, comp, context); + } + + /** + * Sets quota for the specified share. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param quota Specifies the maximum size of the share, in gigabytes. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setQuotaWithRestResponseAsync(Integer timeout, Integer quota, Context context) { + final String restype = "share"; + final String comp = "properties"; + return service.setQuota(this.client.url(), timeout, this.client.version(), quota, restype, comp, context); + } + + /** + * Sets one or more user-defined name-value pairs for the specified share. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String restype = "share"; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Sets one or more user-defined name-value pairs for the specified share. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param metadata A name-value pair to associate with a file storage object. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Integer timeout, Map metadata, Context context) { + final String restype = "share"; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), restype, comp, context); + } + + /** + * Returns information about stored access policies specified on the share. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String restype = "share"; + final String comp = "acl"; + return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), restype, comp, context); + } + + /** + * Returns information about stored access policies specified on the share. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(Integer timeout, Context context) { + final String restype = "share"; + final String comp = "acl"; + return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), restype, comp, context); + } + + /** + * Sets a stored access policy for use with shared access signatures. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String restype = "share"; + final String comp = "acl"; + SignedIdentifiersWrapper shareAclConverted = new SignedIdentifiersWrapper(null); + return service.setAccessPolicy(this.client.url(), shareAclConverted, timeout, this.client.version(), restype, comp, context); + } + + /** + * Sets a stored access policy for use with shared access signatures. + * + * @param shareAcl The ACL for the share. + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(List shareAcl, Integer timeout, Context context) { + final String restype = "share"; + final String comp = "acl"; + SignedIdentifiersWrapper shareAclConverted = new SignedIdentifiersWrapper(shareAcl); + return service.setAccessPolicy(this.client.url(), shareAclConverted, timeout, this.client.version(), restype, comp, context); + } + + /** + * Retrieves statistics related to the share. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String restype = "share"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), restype, comp, context); + } + + /** + * Retrieves statistics related to the share. + * + * @param timeout The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting Timeouts for File Service Operations.</a>. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Integer timeout, Context context) { + final String restype = "share"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), restype, comp, context); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/SignedIdentifiersWrapper.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/SignedIdentifiersWrapper.java new file mode 100644 index 0000000000000..da1e30459bfcb --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/SignedIdentifiersWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.implementation; + +import com.azure.storage.file.models.SignedIdentifier; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<SignedIdentifier> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "SignedIdentifiers") +public final class SignedIdentifiersWrapper { + @JacksonXmlProperty(localName = "SignedIdentifier") + private final List signedIdentifiers; + + /** + * Creates an instance of SignedIdentifiersWrapper. + * + * @param signedIdentifiers the list. + */ + @JsonCreator + public SignedIdentifiersWrapper(@JsonProperty("SignedIdentifier") List signedIdentifiers) { + this.signedIdentifiers = signedIdentifiers; + } + + /** + * Get the List<SignedIdentifier> contained in this wrapper. + * + * @return the List<SignedIdentifier>. + */ + public List items() { + return signedIdentifiers; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/implementation/package-info.java b/storage/client/file/src/main/java/com/azure/storage/file/implementation/package-info.java new file mode 100644 index 0000000000000..c7e9e946b39e4 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/implementation/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementations and inner classes for + * AzureFileStorage. + */ +package com.azure.storage.file.implementation; diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/AccessPolicy.java b/storage/client/file/src/main/java/com/azure/storage/file/models/AccessPolicy.java new file mode 100644 index 0000000000000..94ccd39fbec5f --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/AccessPolicy.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * An Access policy. + */ +@JacksonXmlRootElement(localName = "AccessPolicy") +public final class AccessPolicy { + /* + * The date-time the policy is active. + */ + @JsonProperty(value = "Start") + private OffsetDateTime start; + + /* + * The date-time the policy expires. + */ + @JsonProperty(value = "Expiry") + private OffsetDateTime expiry; + + /* + * The permissions for the ACL policy. + */ + @JsonProperty(value = "Permission") + private String permission; + + /** + * Get the start property: The date-time the policy is active. + * + * @return the start value. + */ + public OffsetDateTime start() { + return this.start; + } + + /** + * Set the start property: The date-time the policy is active. + * + * @param start the start value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy start(OffsetDateTime start) { + this.start = start; + return this; + } + + /** + * Get the expiry property: The date-time the policy expires. + * + * @return the expiry value. + */ + public OffsetDateTime expiry() { + return this.expiry; + } + + /** + * Set the expiry property: The date-time the policy expires. + * + * @param expiry the expiry value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy expiry(OffsetDateTime expiry) { + this.expiry = expiry; + return this; + } + + /** + * Get the permission property: The permissions for the ACL policy. + * + * @return the permission value. + */ + public String permission() { + return this.permission; + } + + /** + * Set the permission property: The permissions for the ACL policy. + * + * @param permission the permission value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy permission(String permission) { + this.permission = permission; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/CopyStatusType.java b/storage/client/file/src/main/java/com/azure/storage/file/models/CopyStatusType.java new file mode 100644 index 0000000000000..1d14aa7b9a316 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/CopyStatusType.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for CopyStatusType. + */ +public enum CopyStatusType { + /** + * Enum value pending. + */ + PENDING("pending"), + + /** + * Enum value success. + */ + SUCCESS("success"), + + /** + * Enum value aborted. + */ + ABORTED("aborted"), + + /** + * Enum value failed. + */ + FAILED("failed"); + + /** + * The actual serialized value for a CopyStatusType instance. + */ + private final String value; + + CopyStatusType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a CopyStatusType instance. + * + * @param value the serialized value to parse. + * @return the parsed CopyStatusType object, or null if unable to parse. + */ + @JsonCreator + public static CopyStatusType fromString(String value) { + CopyStatusType[] items = CopyStatusType.values(); + for (CopyStatusType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/CorsRule.java b/storage/client/file/src/main/java/com/azure/storage/file/models/CorsRule.java new file mode 100644 index 0000000000000..998d7c00bbf93 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/CorsRule.java @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * CORS is an HTTP feature that enables a web application running under one + * domain to access resources in another domain. Web browsers implement a + * security restriction known as same-origin policy that prevents a web page + * from calling APIs in a different domain; CORS provides a secure way to allow + * one domain (the origin domain) to call APIs in another domain. + */ +@JacksonXmlRootElement(localName = "CorsRule") +public final class CorsRule { + /* + * The origin domains that are permitted to make a request against the + * storage service via CORS. The origin domain is the domain from which the + * request originates. Note that the origin must be an exact case-sensitive + * match with the origin that the user age sends to the service. You can + * also use the wildcard character '*' to allow all origin domains to make + * requests via CORS. + */ + @JsonProperty(value = "AllowedOrigins", required = true) + private String allowedOrigins; + + /* + * The methods (HTTP request verbs) that the origin domain may use for a + * CORS request. (comma separated) + */ + @JsonProperty(value = "AllowedMethods", required = true) + private String allowedMethods; + + /* + * The request headers that the origin domain may specify on the CORS + * request. + */ + @JsonProperty(value = "AllowedHeaders", required = true) + private String allowedHeaders; + + /* + * The response headers that may be sent in the response to the CORS + * request and exposed by the browser to the request issuer. + */ + @JsonProperty(value = "ExposedHeaders", required = true) + private String exposedHeaders; + + /* + * The maximum amount time that a browser should cache the preflight + * OPTIONS request. + */ + @JsonProperty(value = "MaxAgeInSeconds", required = true) + private int maxAgeInSeconds; + + /** + * Get the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @return the allowedOrigins value. + */ + public String allowedOrigins() { + return this.allowedOrigins; + } + + /** + * Set the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @param allowedOrigins the allowedOrigins value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedOrigins(String allowedOrigins) { + this.allowedOrigins = allowedOrigins; + return this; + } + + /** + * Get the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @return the allowedMethods value. + */ + public String allowedMethods() { + return this.allowedMethods; + } + + /** + * Set the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @param allowedMethods the allowedMethods value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedMethods(String allowedMethods) { + this.allowedMethods = allowedMethods; + return this; + } + + /** + * Get the allowedHeaders property: The request headers that the origin + * domain may specify on the CORS request. + * + * @return the allowedHeaders value. + */ + public String allowedHeaders() { + return this.allowedHeaders; + } + + /** + * Set the allowedHeaders property: The request headers that the origin + * domain may specify on the CORS request. + * + * @param allowedHeaders the allowedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedHeaders(String allowedHeaders) { + this.allowedHeaders = allowedHeaders; + return this; + } + + /** + * Get the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @return the exposedHeaders value. + */ + public String exposedHeaders() { + return this.exposedHeaders; + } + + /** + * Set the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @param exposedHeaders the exposedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule exposedHeaders(String exposedHeaders) { + this.exposedHeaders = exposedHeaders; + return this; + } + + /** + * Get the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @return the maxAgeInSeconds value. + */ + public int maxAgeInSeconds() { + return this.maxAgeInSeconds; + } + + /** + * Set the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @param maxAgeInSeconds the maxAgeInSeconds value to set. + * @return the CorsRule object itself. + */ + public CorsRule maxAgeInSeconds(int maxAgeInSeconds) { + this.maxAgeInSeconds = maxAgeInSeconds; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DeleteSnapshotsOptionType.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DeleteSnapshotsOptionType.java new file mode 100644 index 0000000000000..080e8961a2710 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DeleteSnapshotsOptionType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for DeleteSnapshotsOptionType. + */ +public enum DeleteSnapshotsOptionType { + /** + * Enum value include. + */ + INCLUDE("include"), + + /** + * Enum value only. + */ + ONLY("only"); + + /** + * The actual serialized value for a DeleteSnapshotsOptionType instance. + */ + private final String value; + + DeleteSnapshotsOptionType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a DeleteSnapshotsOptionType instance. + * + * @param value the serialized value to parse. + * @return the parsed DeleteSnapshotsOptionType object, or null if unable to parse. + */ + @JsonCreator + public static DeleteSnapshotsOptionType fromString(String value) { + DeleteSnapshotsOptionType[] items = DeleteSnapshotsOptionType.values(); + for (DeleteSnapshotsOptionType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryCreateHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryCreateHeaders.java new file mode 100644 index 0000000000000..f4f14ebd7c7b4 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryCreateHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "Directory-Create-Headers") +public final class DirectoryCreateHeaders { + /* + * The ETag contains a value which represents the version of the directory, + * in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the directory or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * directory. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the directory, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the directory, in quotes. + * + * @param eTag the eTag value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @param lastModified the lastModified value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryCreateHeaders object itself. + */ + public DirectoryCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryDeleteHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryDeleteHeaders.java new file mode 100644 index 0000000000000..7e98303ea6e71 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryDeleteHeaders.java @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "Directory-Delete-Headers") +public final class DirectoryDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryDeleteHeaders object itself. + */ + public DirectoryDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryDeleteHeaders object itself. + */ + public DirectoryDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryDeleteHeaders object itself. + */ + public DirectoryDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryDeleteHeaders object itself. + */ + public DirectoryDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryForceCloseHandlesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryForceCloseHandlesHeaders.java new file mode 100644 index 0000000000000..08722706147e4 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryForceCloseHandlesHeaders.java @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ForceCloseHandles operation. + */ +@JacksonXmlRootElement(localName = "Directory-ForceCloseHandles-Headers") +public final class DirectoryForceCloseHandlesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * A string describing next handle to be closed. It is returned when more + * handles need to be closed to complete the request. + */ + @JsonProperty(value = "x-ms-marker") + private String marker; + + /* + * Contains count of number of handles closed. + */ + @JsonProperty(value = "x-ms-number-of-handles-closed") + private Integer numberOfHandlesClosed; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the marker property: A string describing next handle to be closed. + * It is returned when more handles need to be closed to complete the + * request. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: A string describing next handle to be closed. + * It is returned when more handles need to be closed to complete the + * request. + * + * @param marker the marker value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the numberOfHandlesClosed property: Contains count of number of + * handles closed. + * + * @return the numberOfHandlesClosed value. + */ + public Integer numberOfHandlesClosed() { + return this.numberOfHandlesClosed; + } + + /** + * Set the numberOfHandlesClosed property: Contains count of number of + * handles closed. + * + * @param numberOfHandlesClosed the numberOfHandlesClosed value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders numberOfHandlesClosed(Integer numberOfHandlesClosed) { + this.numberOfHandlesClosed = numberOfHandlesClosed; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryForceCloseHandlesHeaders object itself. + */ + public DirectoryForceCloseHandlesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryGetPropertiesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryGetPropertiesHeaders.java new file mode 100644 index 0000000000000..5739160de25c7 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryGetPropertiesHeaders.java @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Directory-GetProperties-Headers") +public final class DirectoryGetPropertiesHeaders { + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the Directory was last modified. Operations on + * files within the directory do not affect the last modified time of the + * directory. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the directory metadata is + * completely encrypted using the specified algorithm. Otherwise, the value + * is set to false. + */ + @JsonProperty(value = "x-ms-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the Directory + * was last modified. Operations on files within the directory do not + * affect the last modified time of the directory. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the Directory + * was last modified. Operations on files within the directory do not + * affect the last modified time of the directory. + * + * @param lastModified the lastModified value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the directory metadata is completely encrypted using the + * specified algorithm. Otherwise, the value is set to false. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the directory metadata is completely encrypted using the + * specified algorithm. Otherwise, the value is set to false. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryGetPropertiesHeaders object itself. + */ + public DirectoryGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryInfo.java new file mode 100644 index 0000000000000..bd529f2538e2f --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class DirectoryInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryItem.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryItem.java new file mode 100644 index 0000000000000..4f385aee443ec --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryItem.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * A listed directory item. + */ +@JacksonXmlRootElement(localName = "Directory") +public final class DirectoryItem { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the DirectoryItem object itself. + */ + public DirectoryItem name(String name) { + this.name = name; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListFilesAndDirectoriesSegmentHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListFilesAndDirectoriesSegmentHeaders.java new file mode 100644 index 0000000000000..cbcd8b9d60100 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListFilesAndDirectoriesSegmentHeaders.java @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListFilesAndDirectoriesSegment operation. + */ +@JacksonXmlRootElement(localName = "Directory-ListFilesAndDirectoriesSegment-Headers") +public final class DirectoryListFilesAndDirectoriesSegmentHeaders { + /* + * Specifies the format in which the results are returned. Currently this + * value is 'application/xml'. + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the DirectoryListFilesAndDirectoriesSegmentHeaders object + * itself. + */ + public DirectoryListFilesAndDirectoriesSegmentHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryListFilesAndDirectoriesSegmentHeaders object + * itself. + */ + public DirectoryListFilesAndDirectoriesSegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryListFilesAndDirectoriesSegmentHeaders object + * itself. + */ + public DirectoryListFilesAndDirectoriesSegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryListFilesAndDirectoriesSegmentHeaders object + * itself. + */ + public DirectoryListFilesAndDirectoriesSegmentHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryListFilesAndDirectoriesSegmentHeaders object + * itself. + */ + public DirectoryListFilesAndDirectoriesSegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListHandlesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListHandlesHeaders.java new file mode 100644 index 0000000000000..c816949938439 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryListHandlesHeaders.java @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListHandles operation. + */ +@JacksonXmlRootElement(localName = "Directory-ListHandles-Headers") +public final class DirectoryListHandlesHeaders { + /* + * Specifies the format in which the results are returned. Currently this + * value is 'application/xml'. + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the DirectoryListHandlesHeaders object itself. + */ + public DirectoryListHandlesHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectoryListHandlesHeaders object itself. + */ + public DirectoryListHandlesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectoryListHandlesHeaders object itself. + */ + public DirectoryListHandlesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectoryListHandlesHeaders object itself. + */ + public DirectoryListHandlesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectoryListHandlesHeaders object itself. + */ + public DirectoryListHandlesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryProperties.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryProperties.java new file mode 100644 index 0000000000000..b140fd4a481eb --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectoryProperties.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class DirectoryProperties { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorySetMetadataHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorySetMetadataHeaders.java new file mode 100644 index 0000000000000..603bde2f285aa --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorySetMetadataHeaders.java @@ -0,0 +1,196 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "Directory-SetMetadata-Headers") +public final class DirectorySetMetadataHeaders { + /* + * The ETag contains a value which represents the version of the directory, + * in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the directory, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the directory, in quotes. + * + * @param eTag the eTag value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the DirectorySetMetadataHeaders object itself. + */ + public DirectorySetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysCreateResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysCreateResponse.java new file mode 100644 index 0000000000000..a65683e6cfc87 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class DirectorysCreateResponse extends ResponseBase { + /** + * Creates an instance of DirectorysCreateResponse. + * + * @param request the request which resulted in this DirectorysCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, DirectoryCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysDeleteResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysDeleteResponse.java new file mode 100644 index 0000000000000..239dcaba95e59 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class DirectorysDeleteResponse extends ResponseBase { + /** + * Creates an instance of DirectorysDeleteResponse. + * + * @param request the request which resulted in this DirectorysDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, DirectoryDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysForceCloseHandlesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysForceCloseHandlesResponse.java new file mode 100644 index 0000000000000..c3aaa1f5ce71c --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysForceCloseHandlesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the forceCloseHandles operation. + */ +public final class DirectorysForceCloseHandlesResponse extends ResponseBase { + /** + * Creates an instance of DirectorysForceCloseHandlesResponse. + * + * @param request the request which resulted in this DirectorysForceCloseHandlesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysForceCloseHandlesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, DirectoryForceCloseHandlesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysGetPropertiesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysGetPropertiesResponse.java new file mode 100644 index 0000000000000..1e2295bf6f6f0 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class DirectorysGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of DirectorysGetPropertiesResponse. + * + * @param request the request which resulted in this DirectorysGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, DirectoryGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListFilesAndDirectoriesSegmentResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListFilesAndDirectoriesSegmentResponse.java new file mode 100644 index 0000000000000..cd8966e8fbf46 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListFilesAndDirectoriesSegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listFilesAndDirectoriesSegment operation. + */ +public final class DirectorysListFilesAndDirectoriesSegmentResponse extends ResponseBase { + /** + * Creates an instance of DirectorysListFilesAndDirectoriesSegmentResponse. + * + * @param request the request which resulted in this DirectorysListFilesAndDirectoriesSegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysListFilesAndDirectoriesSegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListFilesAndDirectoriesSegmentResponse value, DirectoryListFilesAndDirectoriesSegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListFilesAndDirectoriesSegmentResponse value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListHandlesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListHandlesResponse.java new file mode 100644 index 0000000000000..267a2615ae5ef --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysListHandlesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listHandles operation. + */ +public final class DirectorysListHandlesResponse extends ResponseBase { + /** + * Creates an instance of DirectorysListHandlesResponse. + * + * @param request the request which resulted in this DirectorysListHandlesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysListHandlesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListHandlesResponse value, DirectoryListHandlesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListHandlesResponse value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysSetMetadataResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysSetMetadataResponse.java new file mode 100644 index 0000000000000..e3eee5271a136 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/DirectorysSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class DirectorysSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of DirectorysSetMetadataResponse. + * + * @param request the request which resulted in this DirectorysSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public DirectorysSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, DirectorySetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileAbortCopyHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileAbortCopyHeaders.java new file mode 100644 index 0000000000000..b5a7162058d7c --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileAbortCopyHeaders.java @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for AbortCopy operation. + */ +@JacksonXmlRootElement(localName = "File-AbortCopy-Headers") +public final class FileAbortCopyHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileAbortCopyHeaders object itself. + */ + public FileAbortCopyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileAbortCopyHeaders object itself. + */ + public FileAbortCopyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileAbortCopyHeaders object itself. + */ + public FileAbortCopyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileAbortCopyHeaders object itself. + */ + public FileAbortCopyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileCopyInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileCopyInfo.java new file mode 100644 index 0000000000000..fe4498b81c3da --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileCopyInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileCopyInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileCreateHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileCreateHeaders.java new file mode 100644 index 0000000000000..f294bbef75fdd --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileCreateHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "File-Create-Headers") +public final class FileCreateHeaders { + /* + * The ETag contains a value which represents the version of the file, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the directory or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * directory. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @param lastModified the lastModified value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileCreateHeaders object itself. + */ + public FileCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileDeleteHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDeleteHeaders.java new file mode 100644 index 0000000000000..daf2668bd0521 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDeleteHeaders.java @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "File-Delete-Headers") +public final class FileDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileDeleteHeaders object itself. + */ + public FileDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileDeleteHeaders object itself. + */ + public FileDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileDeleteHeaders object itself. + */ + public FileDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileDeleteHeaders object itself. + */ + public FileDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadHeaders.java new file mode 100644 index 0000000000000..df05458677164 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadHeaders.java @@ -0,0 +1,782 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.Map; + +/** + * Defines headers for Download operation. + */ +@JacksonXmlRootElement(localName = "File-Download-Headers") +public final class FileDownloadHeaders { + /* + * Returns the date and time the file was last modified. Any operation that + * modifies the file or its properties updates the last modified time. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The number of bytes present in the response body. + */ + @JsonProperty(value = "Content-Length") + private Long contentLength; + + /* + * The content type specified for the file. The default content type is + * 'application/octet-stream' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * Indicates the range of bytes returned if the client requested a subset + * of the file by setting the Range request header. + */ + @JsonProperty(value = "Content-Range") + private String contentRange; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * If the file has an MD5 hash and the request is to read the full file, + * this response header is returned so that the client can check for + * message content integrity. If the request is to read a specified range + * and the 'x-ms-range-get-content-md5' is set to true, then the request + * returns an MD5 hash for the range, as long as the range size is less + * than or equal to 4 MB. If neither of these sets of conditions is true, + * then no value is returned for the 'Content-MD5' header. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * Returns the value that was specified for the Content-Encoding request + * header. + */ + @JsonProperty(value = "Content-Encoding") + private String contentEncoding; + + /* + * Returned if it was previously specified for the file. + */ + @JsonProperty(value = "Cache-Control") + private String cacheControl; + + /* + * Returns the value that was specified for the 'x-ms-content-disposition' + * header and specifies how to process the response. + */ + @JsonProperty(value = "Content-Disposition") + private String contentDisposition; + + /* + * Returns the value that was specified for the Content-Language request + * header. + */ + @JsonProperty(value = "Content-Language") + private String contentLanguage; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * Indicates that the service supports requests for partial file content. + */ + @JsonProperty(value = "Accept-Ranges") + private String acceptRanges; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Conclusion time of the last attempted Copy File operation where this + * file was the destination file. This value can specify the time of a + * completed, aborted, or failed copy attempt. + */ + @JsonProperty(value = "x-ms-copy-completion-time") + private DateTimeRfc1123 copyCompletionTime; + + /* + * Only appears when x-ms-copy-status is failed or pending. Describes cause + * of fatal or non-fatal copy operation failure. + */ + @JsonProperty(value = "x-ms-copy-status-description") + private String copyStatusDescription; + + /* + * String identifier for the last attempted Copy File operation where this + * file was the destination file. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * Contains the number of bytes copied and the total bytes in the source in + * the last attempted Copy File operation where this file was the + * destination file. Can show between 0 and Content-Length bytes copied. + */ + @JsonProperty(value = "x-ms-copy-progress") + private String copyProgress; + + /* + * URL up to 2KB in length that specifies the source file used in the last + * attempted Copy File operation where this file was the destination file. + */ + @JsonProperty(value = "x-ms-copy-source") + private String copySource; + + /* + * State of the copy operation identified by 'x-ms-copy-id'. Possible + * values include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * If the file has a MD5 hash, and if request contains range header (Range + * or x-ms-range), this response header is returned with the value of the + * whole file's MD5 value. This value may or may not be equal to the value + * returned in Content-MD5 header, with the latter calculated from the + * requested range. + */ + @JsonProperty(value = "x-ms-content-md5") + private byte[] fileContentMD5; + + /* + * The value of this header is set to true if the file data and application + * metadata are completely encrypted using the specified algorithm. + * Otherwise, the value is set to false (when the file is unencrypted, or + * if only parts of the file/application metadata are encrypted). + */ + @JsonProperty(value = "x-ms-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the file was + * last modified. Any operation that modifies the file or its properties + * updates the last modified time. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the file was + * last modified. Any operation that modifies the file or its properties + * updates the last modified time. + * + * @param lastModified the lastModified value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the contentLength property: The number of bytes present in the + * response body. + * + * @return the contentLength value. + */ + public Long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: The number of bytes present in the + * response body. + * + * @param contentLength the contentLength value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentLength(Long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * Get the contentType property: The content type specified for the file. + * The default content type is 'application/octet-stream'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The content type specified for the file. + * The default content type is 'application/octet-stream'. + * + * @param contentType the contentType value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the contentRange property: Indicates the range of bytes returned if + * the client requested a subset of the file by setting the Range request + * header. + * + * @return the contentRange value. + */ + public String contentRange() { + return this.contentRange; + } + + /** + * Set the contentRange property: Indicates the range of bytes returned if + * the client requested a subset of the file by setting the Range request + * header. + * + * @param contentRange the contentRange value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentRange(String contentRange) { + this.contentRange = contentRange; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the contentMD5 property: If the file has an MD5 hash and the request + * is to read the full file, this response header is returned so that the + * client can check for message content integrity. If the request is to + * read a specified range and the 'x-ms-range-get-content-md5' is set to + * true, then the request returns an MD5 hash for the range, as long as the + * range size is less than or equal to 4 MB. If neither of these sets of + * conditions is true, then no value is returned for the 'Content-MD5' + * header. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return Arrays.copyOf(this.contentMD5, this.contentMD5.length); + } + + /** + * Set the contentMD5 property: If the file has an MD5 hash and the request + * is to read the full file, this response header is returned so that the + * client can check for message content integrity. If the request is to + * read a specified range and the 'x-ms-range-get-content-md5' is set to + * true, then the request returns an MD5 hash for the range, as long as the + * range size is less than or equal to 4 MB. If neither of these sets of + * conditions is true, then no value is returned for the 'Content-MD5' + * header. + * + * @param contentMD5 the contentMD5 value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = Arrays.copyOf(contentMD5, contentMD5.length); + return this; + } + + /** + * Get the contentEncoding property: Returns the value that was specified + * for the Content-Encoding request header. + * + * @return the contentEncoding value. + */ + public String contentEncoding() { + return this.contentEncoding; + } + + /** + * Set the contentEncoding property: Returns the value that was specified + * for the Content-Encoding request header. + * + * @param contentEncoding the contentEncoding value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * Get the cacheControl property: Returned if it was previously specified + * for the file. + * + * @return the cacheControl value. + */ + public String cacheControl() { + return this.cacheControl; + } + + /** + * Set the cacheControl property: Returned if it was previously specified + * for the file. + * + * @param cacheControl the cacheControl value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * Get the contentDisposition property: Returns the value that was + * specified for the 'x-ms-content-disposition' header and specifies how to + * process the response. + * + * @return the contentDisposition value. + */ + public String contentDisposition() { + return this.contentDisposition; + } + + /** + * Set the contentDisposition property: Returns the value that was + * specified for the 'x-ms-content-disposition' header and specifies how to + * process the response. + * + * @param contentDisposition the contentDisposition value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * Get the contentLanguage property: Returns the value that was specified + * for the Content-Language request header. + * + * @return the contentLanguage value. + */ + public String contentLanguage() { + return this.contentLanguage; + } + + /** + * Set the contentLanguage property: Returns the value that was specified + * for the Content-Language request header. + * + * @param contentLanguage the contentLanguage value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the acceptRanges property: Indicates that the service supports + * requests for partial file content. + * + * @return the acceptRanges value. + */ + public String acceptRanges() { + return this.acceptRanges; + } + + /** + * Set the acceptRanges property: Indicates that the service supports + * requests for partial file content. + * + * @param acceptRanges the acceptRanges value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders acceptRanges(String acceptRanges) { + this.acceptRanges = acceptRanges; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyCompletionTime property: Conclusion time of the last + * attempted Copy File operation where this file was the destination file. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. + * + * @return the copyCompletionTime value. + */ + public OffsetDateTime copyCompletionTime() { + if (this.copyCompletionTime == null) { + return null; + } + return this.copyCompletionTime.dateTime(); + } + + /** + * Set the copyCompletionTime property: Conclusion time of the last + * attempted Copy File operation where this file was the destination file. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. + * + * @param copyCompletionTime the copyCompletionTime value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copyCompletionTime(OffsetDateTime copyCompletionTime) { + if (copyCompletionTime == null) { + this.copyCompletionTime = null; + } else { + this.copyCompletionTime = new DateTimeRfc1123(copyCompletionTime); + } + return this; + } + + /** + * Get the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + * + * @return the copyStatusDescription value. + */ + public String copyStatusDescription() { + return this.copyStatusDescription; + } + + /** + * Set the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + * + * @param copyStatusDescription the copyStatusDescription value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copyStatusDescription(String copyStatusDescription) { + this.copyStatusDescription = copyStatusDescription; + return this; + } + + /** + * Get the copyId property: String identifier for the last attempted Copy + * File operation where this file was the destination file. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for the last attempted Copy + * File operation where this file was the destination file. + * + * @param copyId the copyId value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy File operation + * where this file was the destination file. Can show between 0 and + * Content-Length bytes copied. + * + * @return the copyProgress value. + */ + public String copyProgress() { + return this.copyProgress; + } + + /** + * Set the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy File operation + * where this file was the destination file. Can show between 0 and + * Content-Length bytes copied. + * + * @param copyProgress the copyProgress value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copyProgress(String copyProgress) { + this.copyProgress = copyProgress; + return this; + } + + /** + * Get the copySource property: URL up to 2KB in length that specifies the + * source file used in the last attempted Copy File operation where this + * file was the destination file. + * + * @return the copySource value. + */ + public String copySource() { + return this.copySource; + } + + /** + * Set the copySource property: URL up to 2KB in length that specifies the + * source file used in the last attempted Copy File operation where this + * file was the destination file. + * + * @param copySource the copySource value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copySource(String copySource) { + this.copySource = copySource; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * 'x-ms-copy-id'. Possible values include: 'pending', 'success', + * 'aborted', 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * 'x-ms-copy-id'. Possible values include: 'pending', 'success', + * 'aborted', 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the fileContentMD5 property: If the file has a MD5 hash, and if + * request contains range header (Range or x-ms-range), this response + * header is returned with the value of the whole file's MD5 value. This + * value may or may not be equal to the value returned in Content-MD5 + * header, with the latter calculated from the requested range. + * + * @return the fileContentMD5 value. + */ + public byte[] fileContentMD5() { + return Arrays.copyOf(this.fileContentMD5, this.fileContentMD5.length); + } + + /** + * Set the fileContentMD5 property: If the file has a MD5 hash, and if + * request contains range header (Range or x-ms-range), this response + * header is returned with the value of the whole file's MD5 value. This + * value may or may not be equal to the value returned in Content-MD5 + * header, with the latter calculated from the requested range. + * + * @param fileContentMD5 the fileContentMD5 value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders fileContentMD5(byte[] fileContentMD5) { + this.fileContentMD5 = Arrays.copyOf(fileContentMD5, fileContentMD5.length); + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the file data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application + * metadata are encrypted). + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the file data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application + * metadata are encrypted). + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileDownloadHeaders object itself. + */ + public FileDownloadHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadInfo.java new file mode 100644 index 0000000000000..694fe762c8131 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileDownloadInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileDownloadInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileForceCloseHandlesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileForceCloseHandlesHeaders.java new file mode 100644 index 0000000000000..39f245c7d1116 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileForceCloseHandlesHeaders.java @@ -0,0 +1,194 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ForceCloseHandles operation. + */ +@JacksonXmlRootElement(localName = "File-ForceCloseHandles-Headers") +public final class FileForceCloseHandlesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * A string describing next handle to be closed. It is returned when more + * handles need to be closed to complete the request. + */ + @JsonProperty(value = "x-ms-marker") + private String marker; + + /* + * Contains count of number of handles closed. + */ + @JsonProperty(value = "x-ms-number-of-handles-closed") + private Integer numberOfHandlesClosed; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the marker property: A string describing next handle to be closed. + * It is returned when more handles need to be closed to complete the + * request. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: A string describing next handle to be closed. + * It is returned when more handles need to be closed to complete the + * request. + * + * @param marker the marker value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the numberOfHandlesClosed property: Contains count of number of + * handles closed. + * + * @return the numberOfHandlesClosed value. + */ + public Integer numberOfHandlesClosed() { + return this.numberOfHandlesClosed; + } + + /** + * Set the numberOfHandlesClosed property: Contains count of number of + * handles closed. + * + * @param numberOfHandlesClosed the numberOfHandlesClosed value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders numberOfHandlesClosed(Integer numberOfHandlesClosed) { + this.numberOfHandlesClosed = numberOfHandlesClosed; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileForceCloseHandlesHeaders object itself. + */ + public FileForceCloseHandlesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetPropertiesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetPropertiesHeaders.java new file mode 100644 index 0000000000000..ff397f6cd7ce1 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetPropertiesHeaders.java @@ -0,0 +1,709 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "File-GetProperties-Headers") +public final class FileGetPropertiesHeaders { + /* + * Returns the date and time the file was last modified. The date format + * follows RFC 1123. Any operation that modifies the file or its properties + * updates the last modified time. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * Returns the type File. Reserved for future use. Possible values include: + * 'File' + */ + @JsonProperty(value = "x-ms-type") + private String fileType; + + /* + * The size of the file in bytes. This header returns the value of the + * 'x-ms-content-length' header that is stored with the file. + */ + @JsonProperty(value = "Content-Length") + private Long contentLength; + + /* + * The content type specified for the file. The default content type is + * 'application/octet-stream' + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * If the Content-MD5 header has been set for the file, the Content-MD5 + * response header is returned so that the client can check for message + * content integrity. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * If the Content-Encoding request header has previously been set for the + * file, the Content-Encoding value is returned in this header. + */ + @JsonProperty(value = "Content-Encoding") + private String contentEncoding; + + /* + * If the Cache-Control request header has previously been set for the + * file, the Cache-Control value is returned in this header. + */ + @JsonProperty(value = "Cache-Control") + private String cacheControl; + + /* + * Returns the value that was specified for the 'x-ms-content-disposition' + * header and specifies how to process the response. + */ + @JsonProperty(value = "Content-Disposition") + private String contentDisposition; + + /* + * Returns the value that was specified for the Content-Language request + * header. + */ + @JsonProperty(value = "Content-Language") + private String contentLanguage; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Conclusion time of the last attempted Copy File operation where this + * file was the destination file. This value can specify the time of a + * completed, aborted, or failed copy attempt. + */ + @JsonProperty(value = "x-ms-copy-completion-time") + private DateTimeRfc1123 copyCompletionTime; + + /* + * Only appears when x-ms-copy-status is failed or pending. Describes cause + * of fatal or non-fatal copy operation failure. + */ + @JsonProperty(value = "x-ms-copy-status-description") + private String copyStatusDescription; + + /* + * String identifier for the last attempted Copy File operation where this + * file was the destination file. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * Contains the number of bytes copied and the total bytes in the source in + * the last attempted Copy File operation where this file was the + * destination file. Can show between 0 and Content-Length bytes copied. + */ + @JsonProperty(value = "x-ms-copy-progress") + private String copyProgress; + + /* + * URL up to 2KB in length that specifies the source file used in the last + * attempted Copy File operation where this file was the destination file. + */ + @JsonProperty(value = "x-ms-copy-source") + private String copySource; + + /* + * State of the copy operation identified by 'x-ms-copy-id'. Possible + * values include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * The value of this header is set to true if the file data and application + * metadata are completely encrypted using the specified algorithm. + * Otherwise, the value is set to false (when the file is unencrypted, or + * if only parts of the file/application metadata are encrypted). + */ + @JsonProperty(value = "x-ms-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: Returns the date and time the file was + * last modified. The date format follows RFC 1123. Any operation that + * modifies the file or its properties updates the last modified time. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the file was + * last modified. The date format follows RFC 1123. Any operation that + * modifies the file or its properties updates the last modified time. + * + * @param lastModified the lastModified value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the fileType property: Returns the type File. Reserved for future + * use. Possible values include: 'File'. + * + * @return the fileType value. + */ + public String fileType() { + return this.fileType; + } + + /** + * Set the fileType property: Returns the type File. Reserved for future + * use. Possible values include: 'File'. + * + * @param fileType the fileType value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders fileType(String fileType) { + this.fileType = fileType; + return this; + } + + /** + * Get the contentLength property: The size of the file in bytes. This + * header returns the value of the 'x-ms-content-length' header that is + * stored with the file. + * + * @return the contentLength value. + */ + public Long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: The size of the file in bytes. This + * header returns the value of the 'x-ms-content-length' header that is + * stored with the file. + * + * @param contentLength the contentLength value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentLength(Long contentLength) { + this.contentLength = contentLength; + return this; + } + + /** + * Get the contentType property: The content type specified for the file. + * The default content type is 'application/octet-stream'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: The content type specified for the file. + * The default content type is 'application/octet-stream'. + * + * @param contentType the contentType value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the contentMD5 property: If the Content-MD5 header has been set for + * the file, the Content-MD5 response header is returned so that the client + * can check for message content integrity. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return Arrays.copyOf(this.contentMD5, this.contentMD5.length); + } + + /** + * Set the contentMD5 property: If the Content-MD5 header has been set for + * the file, the Content-MD5 response header is returned so that the client + * can check for message content integrity. + * + * @param contentMD5 the contentMD5 value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = Arrays.copyOf(contentMD5, contentMD5.length); + return this; + } + + /** + * Get the contentEncoding property: If the Content-Encoding request header + * has previously been set for the file, the Content-Encoding value is + * returned in this header. + * + * @return the contentEncoding value. + */ + public String contentEncoding() { + return this.contentEncoding; + } + + /** + * Set the contentEncoding property: If the Content-Encoding request header + * has previously been set for the file, the Content-Encoding value is + * returned in this header. + * + * @param contentEncoding the contentEncoding value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentEncoding(String contentEncoding) { + this.contentEncoding = contentEncoding; + return this; + } + + /** + * Get the cacheControl property: If the Cache-Control request header has + * previously been set for the file, the Cache-Control value is returned in + * this header. + * + * @return the cacheControl value. + */ + public String cacheControl() { + return this.cacheControl; + } + + /** + * Set the cacheControl property: If the Cache-Control request header has + * previously been set for the file, the Cache-Control value is returned in + * this header. + * + * @param cacheControl the cacheControl value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders cacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + + /** + * Get the contentDisposition property: Returns the value that was + * specified for the 'x-ms-content-disposition' header and specifies how to + * process the response. + * + * @return the contentDisposition value. + */ + public String contentDisposition() { + return this.contentDisposition; + } + + /** + * Set the contentDisposition property: Returns the value that was + * specified for the 'x-ms-content-disposition' header and specifies how to + * process the response. + * + * @param contentDisposition the contentDisposition value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentDisposition(String contentDisposition) { + this.contentDisposition = contentDisposition; + return this; + } + + /** + * Get the contentLanguage property: Returns the value that was specified + * for the Content-Language request header. + * + * @return the contentLanguage value. + */ + public String contentLanguage() { + return this.contentLanguage; + } + + /** + * Set the contentLanguage property: Returns the value that was specified + * for the Content-Language request header. + * + * @param contentLanguage the contentLanguage value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders contentLanguage(String contentLanguage) { + this.contentLanguage = contentLanguage; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyCompletionTime property: Conclusion time of the last + * attempted Copy File operation where this file was the destination file. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. + * + * @return the copyCompletionTime value. + */ + public OffsetDateTime copyCompletionTime() { + if (this.copyCompletionTime == null) { + return null; + } + return this.copyCompletionTime.dateTime(); + } + + /** + * Set the copyCompletionTime property: Conclusion time of the last + * attempted Copy File operation where this file was the destination file. + * This value can specify the time of a completed, aborted, or failed copy + * attempt. + * + * @param copyCompletionTime the copyCompletionTime value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copyCompletionTime(OffsetDateTime copyCompletionTime) { + if (copyCompletionTime == null) { + this.copyCompletionTime = null; + } else { + this.copyCompletionTime = new DateTimeRfc1123(copyCompletionTime); + } + return this; + } + + /** + * Get the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + * + * @return the copyStatusDescription value. + */ + public String copyStatusDescription() { + return this.copyStatusDescription; + } + + /** + * Set the copyStatusDescription property: Only appears when + * x-ms-copy-status is failed or pending. Describes cause of fatal or + * non-fatal copy operation failure. + * + * @param copyStatusDescription the copyStatusDescription value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copyStatusDescription(String copyStatusDescription) { + this.copyStatusDescription = copyStatusDescription; + return this; + } + + /** + * Get the copyId property: String identifier for the last attempted Copy + * File operation where this file was the destination file. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for the last attempted Copy + * File operation where this file was the destination file. + * + * @param copyId the copyId value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy File operation + * where this file was the destination file. Can show between 0 and + * Content-Length bytes copied. + * + * @return the copyProgress value. + */ + public String copyProgress() { + return this.copyProgress; + } + + /** + * Set the copyProgress property: Contains the number of bytes copied and + * the total bytes in the source in the last attempted Copy File operation + * where this file was the destination file. Can show between 0 and + * Content-Length bytes copied. + * + * @param copyProgress the copyProgress value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copyProgress(String copyProgress) { + this.copyProgress = copyProgress; + return this; + } + + /** + * Get the copySource property: URL up to 2KB in length that specifies the + * source file used in the last attempted Copy File operation where this + * file was the destination file. + * + * @return the copySource value. + */ + public String copySource() { + return this.copySource; + } + + /** + * Set the copySource property: URL up to 2KB in length that specifies the + * source file used in the last attempted Copy File operation where this + * file was the destination file. + * + * @param copySource the copySource value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copySource(String copySource) { + this.copySource = copySource; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * 'x-ms-copy-id'. Possible values include: 'pending', 'success', + * 'aborted', 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * 'x-ms-copy-id'. Possible values include: 'pending', 'success', + * 'aborted', 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the file data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application + * metadata are encrypted). + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the file data and application metadata are completely encrypted + * using the specified algorithm. Otherwise, the value is set to false + * (when the file is unencrypted, or if only parts of the file/application + * metadata are encrypted). + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileGetPropertiesHeaders object itself. + */ + public FileGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetRangeListHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetRangeListHeaders.java new file mode 100644 index 0000000000000..61f16897c4fc4 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileGetRangeListHeaders.java @@ -0,0 +1,231 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetRangeList operation. + */ +@JacksonXmlRootElement(localName = "File-GetRangeList-Headers") +public final class FileGetRangeListHeaders { + /* + * The date/time that the file was last modified. Any operation that + * modifies the file, including an update of the file's metadata or + * properties, changes the file's last modified time. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * The ETag contains a value which represents the version of the file, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * The size of the file in bytes. + */ + @JsonProperty(value = "x-ms-content-length") + private Long fileContentLength; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the lastModified property: The date/time that the file was last + * modified. Any operation that modifies the file, including an update of + * the file's metadata or properties, changes the file's last modified + * time. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: The date/time that the file was last + * modified. Any operation that modifies the file, including an update of + * the file's metadata or properties, changes the file's last modified + * time. + * + * @param lastModified the lastModified value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the fileContentLength property: The size of the file in bytes. + * + * @return the fileContentLength value. + */ + public Long fileContentLength() { + return this.fileContentLength; + } + + /** + * Set the fileContentLength property: The size of the file in bytes. + * + * @param fileContentLength the fileContentLength value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders fileContentLength(Long fileContentLength) { + this.fileContentLength = fileContentLength; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileGetRangeListHeaders object itself. + */ + public FileGetRangeListHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileHTTPHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileHTTPHeaders.java new file mode 100644 index 0000000000000..01c69b3a9f299 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileHTTPHeaders.java @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.Arrays; + +/** + * Additional parameters for a set of operations, such as: Files_create, + * Files_setHTTPHeaders. + */ +@JacksonXmlRootElement(localName = "file-HTTP-headers") +public final class FileHTTPHeaders { + /* + * Sets the MIME content type of the file. The default type is + * 'application/octet-stream'. + */ + @JsonProperty(value = "fileContentType") + private String fileContentType; + + /* + * Specifies which content encodings have been applied to the file. + */ + @JsonProperty(value = "fileContentEncoding") + private String fileContentEncoding; + + /* + * Specifies the natural languages used by this resource. + */ + @JsonProperty(value = "fileContentLanguage") + private String fileContentLanguage; + + /* + * Sets the file's cache control. The File service stores this value but + * does not use or modify it. + */ + @JsonProperty(value = "fileCacheControl") + private String fileCacheControl; + + /* + * Sets the file's MD5 hash. + */ + @JsonProperty(value = "fileContentMD5") + private byte[] fileContentMD5; + + /* + * Sets the file's Content-Disposition header. + */ + @JsonProperty(value = "fileContentDisposition") + private String fileContentDisposition; + + /** + * Get the fileContentType property: Sets the MIME content type of the + * file. The default type is 'application/octet-stream'. + * + * @return the fileContentType value. + */ + public String fileContentType() { + return this.fileContentType; + } + + /** + * Set the fileContentType property: Sets the MIME content type of the + * file. The default type is 'application/octet-stream'. + * + * @param fileContentType the fileContentType value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileContentType(String fileContentType) { + this.fileContentType = fileContentType; + return this; + } + + /** + * Get the fileContentEncoding property: Specifies which content encodings + * have been applied to the file. + * + * @return the fileContentEncoding value. + */ + public String fileContentEncoding() { + return this.fileContentEncoding; + } + + /** + * Set the fileContentEncoding property: Specifies which content encodings + * have been applied to the file. + * + * @param fileContentEncoding the fileContentEncoding value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileContentEncoding(String fileContentEncoding) { + this.fileContentEncoding = fileContentEncoding; + return this; + } + + /** + * Get the fileContentLanguage property: Specifies the natural languages + * used by this resource. + * + * @return the fileContentLanguage value. + */ + public String fileContentLanguage() { + return this.fileContentLanguage; + } + + /** + * Set the fileContentLanguage property: Specifies the natural languages + * used by this resource. + * + * @param fileContentLanguage the fileContentLanguage value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileContentLanguage(String fileContentLanguage) { + this.fileContentLanguage = fileContentLanguage; + return this; + } + + /** + * Get the fileCacheControl property: Sets the file's cache control. The + * File service stores this value but does not use or modify it. + * + * @return the fileCacheControl value. + */ + public String fileCacheControl() { + return this.fileCacheControl; + } + + /** + * Set the fileCacheControl property: Sets the file's cache control. The + * File service stores this value but does not use or modify it. + * + * @param fileCacheControl the fileCacheControl value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileCacheControl(String fileCacheControl) { + this.fileCacheControl = fileCacheControl; + return this; + } + + /** + * Get the fileContentMD5 property: Sets the file's MD5 hash. + * + * @return the fileContentMD5 value. + */ + public byte[] fileContentMD5() { + return Arrays.copyOf(this.fileContentMD5, this.fileContentMD5.length); + } + + /** + * Set the fileContentMD5 property: Sets the file's MD5 hash. + * + * @param fileContentMD5 the fileContentMD5 value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileContentMD5(byte[] fileContentMD5) { + this.fileContentMD5 = Arrays.copyOf(fileContentMD5, fileContentMD5.length); + return this; + } + + /** + * Get the fileContentDisposition property: Sets the file's + * Content-Disposition header. + * + * @return the fileContentDisposition value. + */ + public String fileContentDisposition() { + return this.fileContentDisposition; + } + + /** + * Set the fileContentDisposition property: Sets the file's + * Content-Disposition header. + * + * @param fileContentDisposition the fileContentDisposition value to set. + * @return the FileHTTPHeaders object itself. + */ + public FileHTTPHeaders fileContentDisposition(String fileContentDisposition) { + this.fileContentDisposition = fileContentDisposition; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileInfo.java new file mode 100644 index 0000000000000..47a634785e190 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileItem.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileItem.java new file mode 100644 index 0000000000000..267445aaf42d2 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileItem.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * A listed file item. + */ +@JacksonXmlRootElement(localName = "File") +public final class FileItem { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The properties property. + */ + @JsonProperty(value = "Properties", required = true) + private FileProperty properties; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the FileItem object itself. + */ + public FileItem name(String name) { + this.name = name; + return this; + } + + /** + * Get the properties property: The properties property. + * + * @return the properties value. + */ + public FileProperty properties() { + return this.properties; + } + + /** + * Set the properties property: The properties property. + * + * @param properties the properties value to set. + * @return the FileItem object itself. + */ + public FileItem properties(FileProperty properties) { + this.properties = properties; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileListHandlesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileListHandlesHeaders.java new file mode 100644 index 0000000000000..c972e5cc9db44 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileListHandlesHeaders.java @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListHandles operation. + */ +@JacksonXmlRootElement(localName = "File-ListHandles-Headers") +public final class FileListHandlesHeaders { + /* + * Specifies the format in which the results are returned. Currently this + * value is 'application/xml'. + */ + @JsonProperty(value = "Content-Type") + private String contentType; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @return the contentType value. + */ + public String contentType() { + return this.contentType; + } + + /** + * Set the contentType property: Specifies the format in which the results + * are returned. Currently this value is 'application/xml'. + * + * @param contentType the contentType value to set. + * @return the FileListHandlesHeaders object itself. + */ + public FileListHandlesHeaders contentType(String contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileListHandlesHeaders object itself. + */ + public FileListHandlesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileListHandlesHeaders object itself. + */ + public FileListHandlesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileListHandlesHeaders object itself. + */ + public FileListHandlesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileListHandlesHeaders object itself. + */ + public FileListHandlesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperties.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperties.java new file mode 100644 index 0000000000000..dd691c0b06871 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperties.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileProperties { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperty.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperty.java new file mode 100644 index 0000000000000..f045b9e209d79 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileProperty.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * File properties. + */ +@JacksonXmlRootElement(localName = "FileProperty") +public final class FileProperty { + /* + * Content length of the file. This value may not be up-to-date since an + * SMB client may have modified the file locally. The value of + * Content-Length may not reflect that fact until the handle is closed or + * the op-lock is broken. To retrieve current property values, call Get + * File Properties. + */ + @JsonProperty(value = "Content-Length", required = true) + private long contentLength; + + /** + * Get the contentLength property: Content length of the file. This value + * may not be up-to-date since an SMB client may have modified the file + * locally. The value of Content-Length may not reflect that fact until the + * handle is closed or the op-lock is broken. To retrieve current property + * values, call Get File Properties. + * + * @return the contentLength value. + */ + public long contentLength() { + return this.contentLength; + } + + /** + * Set the contentLength property: Content length of the file. This value + * may not be up-to-date since an SMB client may have modified the file + * locally. The value of Content-Length may not reflect that fact until the + * handle is closed or the op-lock is broken. To retrieve current property + * values, call Get File Properties. + * + * @param contentLength the contentLength value to set. + * @return the FileProperty object itself. + */ + public FileProperty contentLength(long contentLength) { + this.contentLength = contentLength; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeInfo.java new file mode 100644 index 0000000000000..aac3c8ed7541b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileRangeInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeWriteType.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeWriteType.java new file mode 100644 index 0000000000000..6bce222b4eeae --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRangeWriteType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for FileRangeWriteType. + */ +public enum FileRangeWriteType { + /** + * Enum value update. + */ + UPDATE("update"), + + /** + * Enum value clear. + */ + CLEAR("clear"); + + /** + * The actual serialized value for a FileRangeWriteType instance. + */ + private final String value; + + FileRangeWriteType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a FileRangeWriteType instance. + * + * @param value the serialized value to parse. + * @return the parsed FileRangeWriteType object, or null if unable to parse. + */ + @JsonCreator + public static FileRangeWriteType fromString(String value) { + FileRangeWriteType[] items = FileRangeWriteType.values(); + for (FileRangeWriteType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileRef.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRef.java new file mode 100644 index 0000000000000..0cd1261d2af97 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileRef.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileRef { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileServiceProperties.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileServiceProperties.java new file mode 100644 index 0000000000000..8ad66286adba1 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileServiceProperties.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileServiceProperties { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetHTTPHeadersHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetHTTPHeadersHeaders.java new file mode 100644 index 0000000000000..178e2f0cd66ba --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetHTTPHeadersHeaders.java @@ -0,0 +1,238 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetHTTPHeaders operation. + */ +@JacksonXmlRootElement(localName = "File-SetHTTPHeaders-Headers") +public final class FileSetHTTPHeadersHeaders { + /* + * The ETag contains a value which represents the version of the file, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the directory was last modified. Any operation + * that modifies the directory or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * directory. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the directory + * was last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the directory + * was last modified. Any operation that modifies the directory or its + * properties updates the last modified time. Operations on files do not + * affect the last modified time of the directory. + * + * @param lastModified the lastModified value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileSetHTTPHeadersHeaders object itself. + */ + public FileSetHTTPHeadersHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetMetadataHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetMetadataHeaders.java new file mode 100644 index 0000000000000..98fa0ac8d2dc7 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileSetMetadataHeaders.java @@ -0,0 +1,196 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "File-SetMetadata-Headers") +public final class FileSetMetadataHeaders { + /* + * The ETag contains a value which represents the version of the file, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileSetMetadataHeaders object itself. + */ + public FileSetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileStartCopyHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileStartCopyHeaders.java new file mode 100644 index 0000000000000..939ed8e062949 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileStartCopyHeaders.java @@ -0,0 +1,266 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for StartCopy operation. + */ +@JacksonXmlRootElement(localName = "File-StartCopy-Headers") +public final class FileStartCopyHeaders { + /* + * If the copy is completed, contains the ETag of the destination file. If + * the copy is not complete, contains the ETag of the empty file created at + * the start of the copy. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date/time that the copy operation to the destination file + * completed. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * String identifier for this copy operation. Use with Get File or Get File + * Properties to check the status of this copy operation, or pass to Abort + * Copy File to abort a pending copy. + */ + @JsonProperty(value = "x-ms-copy-id") + private String copyId; + + /* + * State of the copy operation identified by x-ms-copy-id. Possible values + * include: 'pending', 'success', 'aborted', 'failed' + */ + @JsonProperty(value = "x-ms-copy-status") + private CopyStatusType copyStatus; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: If the copy is completed, contains the ETag of + * the destination file. If the copy is not complete, contains the ETag of + * the empty file created at the start of the copy. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: If the copy is completed, contains the ETag of + * the destination file. If the copy is not complete, contains the ETag of + * the empty file created at the start of the copy. + * + * @param eTag the eTag value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date/time that the copy + * operation to the destination file completed. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date/time that the copy + * operation to the destination file completed. + * + * @param lastModified the lastModified value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the copyId property: String identifier for this copy operation. Use + * with Get File or Get File Properties to check the status of this copy + * operation, or pass to Abort Copy File to abort a pending copy. + * + * @return the copyId value. + */ + public String copyId() { + return this.copyId; + } + + /** + * Set the copyId property: String identifier for this copy operation. Use + * with Get File or Get File Properties to check the status of this copy + * operation, or pass to Abort Copy File to abort a pending copy. + * + * @param copyId the copyId value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders copyId(String copyId) { + this.copyId = copyId; + return this; + } + + /** + * Get the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @return the copyStatus value. + */ + public CopyStatusType copyStatus() { + return this.copyStatus; + } + + /** + * Set the copyStatus property: State of the copy operation identified by + * x-ms-copy-id. Possible values include: 'pending', 'success', 'aborted', + * 'failed'. + * + * @param copyStatus the copyStatus value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders copyStatus(CopyStatusType copyStatus) { + this.copyStatus = copyStatus; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileStartCopyHeaders object itself. + */ + public FileStartCopyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadInfo.java new file mode 100644 index 0000000000000..644075f434f74 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class FileUploadInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadRangeHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadRangeHeaders.java new file mode 100644 index 0000000000000..686014ab74e59 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FileUploadRangeHeaders.java @@ -0,0 +1,274 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Arrays; + +/** + * Defines headers for UploadRange operation. + */ +@JacksonXmlRootElement(localName = "File-UploadRange-Headers") +public final class FileUploadRangeHeaders { + /* + * The ETag contains a value which represents the version of the file, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the directory was last modified. Any operation + * that modifies the share or its properties or metadata updates the last + * modified time. Operations on files do not affect the last modified time + * of the share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header is returned so that the client can check for message content + * integrity. The value of this header is computed by the File service; it + * is not necessarily the same value as may have been specified in the + * request headers. + */ + @JsonProperty(value = "Content-MD5") + private byte[] contentMD5; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The value of this header is set to true if the contents of the request + * are successfully encrypted using the specified algorithm, and false + * otherwise. + */ + @JsonProperty(value = "x-ms-request-server-encrypted") + private Boolean isServerEncrypted; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the file, in quotes. + * + * @param eTag the eTag value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the directory + * was last modified. Any operation that modifies the share or its + * properties or metadata updates the last modified time. Operations on + * files do not affect the last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the directory + * was last modified. Any operation that modifies the share or its + * properties or metadata updates the last modified time. Operations on + * files do not affect the last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the contentMD5 property: This header is returned so that the client + * can check for message content integrity. The value of this header is + * computed by the File service; it is not necessarily the same value as + * may have been specified in the request headers. + * + * @return the contentMD5 value. + */ + public byte[] contentMD5() { + return Arrays.copyOf(this.contentMD5, this.contentMD5.length); + } + + /** + * Set the contentMD5 property: This header is returned so that the client + * can check for message content integrity. The value of this header is + * computed by the File service; it is not necessarily the same value as + * may have been specified in the request headers. + * + * @param contentMD5 the contentMD5 value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders contentMD5(byte[] contentMD5) { + this.contentMD5 = Arrays.copyOf(contentMD5, contentMD5.length); + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @return the isServerEncrypted value. + */ + public Boolean isServerEncrypted() { + return this.isServerEncrypted; + } + + /** + * Set the isServerEncrypted property: The value of this header is set to + * true if the contents of the request are successfully encrypted using the + * specified algorithm, and false otherwise. + * + * @param isServerEncrypted the isServerEncrypted value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders isServerEncrypted(Boolean isServerEncrypted) { + this.isServerEncrypted = isServerEncrypted; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the FileUploadRangeHeaders object itself. + */ + public FileUploadRangeHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAbortCopyResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAbortCopyResponse.java new file mode 100644 index 0000000000000..c34ccb2996d08 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAbortCopyResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the abortCopy operation. + */ +public final class FilesAbortCopyResponse extends ResponseBase { + /** + * Creates an instance of FilesAbortCopyResponse. + * + * @param request the request which resulted in this FilesAbortCopyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesAbortCopyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileAbortCopyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAndDirectoriesListSegment.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAndDirectoriesListSegment.java new file mode 100644 index 0000000000000..b5b88d30e4b70 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesAndDirectoriesListSegment.java @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Abstract for entries that can be listed from Directory. + */ +@JacksonXmlRootElement(localName = "Entries") +public final class FilesAndDirectoriesListSegment { + /* + * The directoryItems property. + */ + @JsonProperty("Directory") + private List directoryItems = new ArrayList<>(); + + /* + * The fileItems property. + */ + @JsonProperty("File") + private List fileItems = new ArrayList<>(); + + /** + * Get the directoryItems property: The directoryItems property. + * + * @return the directoryItems value. + */ + public List directoryItems() { + return this.directoryItems; + } + + /** + * Set the directoryItems property: The directoryItems property. + * + * @param directoryItems the directoryItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + public FilesAndDirectoriesListSegment directoryItems(List directoryItems) { + this.directoryItems = directoryItems; + return this; + } + + /** + * Get the fileItems property: The fileItems property. + * + * @return the fileItems value. + */ + public List fileItems() { + return this.fileItems; + } + + /** + * Set the fileItems property: The fileItems property. + * + * @param fileItems the fileItems value to set. + * @return the FilesAndDirectoriesListSegment object itself. + */ + public FilesAndDirectoriesListSegment fileItems(List fileItems) { + this.fileItems = fileItems; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesCreateResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesCreateResponse.java new file mode 100644 index 0000000000000..01e483722bd16 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class FilesCreateResponse extends ResponseBase { + /** + * Creates an instance of FilesCreateResponse. + * + * @param request the request which resulted in this FilesCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDeleteResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDeleteResponse.java new file mode 100644 index 0000000000000..cfeb40f49cac9 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class FilesDeleteResponse extends ResponseBase { + /** + * Creates an instance of FilesDeleteResponse. + * + * @param request the request which resulted in this FilesDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDownloadResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDownloadResponse.java new file mode 100644 index 0000000000000..b9a1d0270c152 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesDownloadResponse.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import io.netty.buffer.ByteBuf; +import java.io.Closeable; +import reactor.core.publisher.Flux; + +/** + * Contains all response data for the download operation. + */ +public final class FilesDownloadResponse extends ResponseBase> implements Closeable { + /** + * Creates an instance of FilesDownloadResponse. + * + * @param request the request which resulted in this FilesDownloadResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the content stream. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesDownloadResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Flux value, FileDownloadHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the response content stream. + */ + @Override + public Flux value() { + return super.value(); + } + + /** + * Disposes of the connection associated with this stream response. + */ + @Override + public void close() { + value().subscribe(bb -> { }, t -> { }).dispose(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesForceCloseHandlesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesForceCloseHandlesResponse.java new file mode 100644 index 0000000000000..2d4b04103b298 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesForceCloseHandlesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the forceCloseHandles operation. + */ +public final class FilesForceCloseHandlesResponse extends ResponseBase { + /** + * Creates an instance of FilesForceCloseHandlesResponse. + * + * @param request the request which resulted in this FilesForceCloseHandlesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesForceCloseHandlesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileForceCloseHandlesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetPropertiesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetPropertiesResponse.java new file mode 100644 index 0000000000000..82f13783a1111 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class FilesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of FilesGetPropertiesResponse. + * + * @param request the request which resulted in this FilesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetRangeListResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetRangeListResponse.java new file mode 100644 index 0000000000000..ed71044cd06b1 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesGetRangeListResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the getRangeList operation. + */ +public final class FilesGetRangeListResponse extends ResponseBase> { + /** + * Creates an instance of FilesGetRangeListResponse. + * + * @param request the request which resulted in this FilesGetRangeListResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesGetRangeListResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, FileGetRangeListHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesListHandlesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesListHandlesResponse.java new file mode 100644 index 0000000000000..20a1d9d78e510 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesListHandlesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listHandles operation. + */ +public final class FilesListHandlesResponse extends ResponseBase { + /** + * Creates an instance of FilesListHandlesResponse. + * + * @param request the request which resulted in this FilesListHandlesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesListHandlesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListHandlesResponse value, FileListHandlesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListHandlesResponse value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetHTTPHeadersResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetHTTPHeadersResponse.java new file mode 100644 index 0000000000000..c21fdbfe01994 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetHTTPHeadersResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setHTTPHeaders operation. + */ +public final class FilesSetHTTPHeadersResponse extends ResponseBase { + /** + * Creates an instance of FilesSetHTTPHeadersResponse. + * + * @param request the request which resulted in this FilesSetHTTPHeadersResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesSetHTTPHeadersResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileSetHTTPHeadersHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetMetadataResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetMetadataResponse.java new file mode 100644 index 0000000000000..c46035850b214 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class FilesSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of FilesSetMetadataResponse. + * + * @param request the request which resulted in this FilesSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileSetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesStartCopyResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesStartCopyResponse.java new file mode 100644 index 0000000000000..c19c3285eb5b4 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesStartCopyResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the startCopy operation. + */ +public final class FilesStartCopyResponse extends ResponseBase { + /** + * Creates an instance of FilesStartCopyResponse. + * + * @param request the request which resulted in this FilesStartCopyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesStartCopyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileStartCopyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/FilesUploadRangeResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesUploadRangeResponse.java new file mode 100644 index 0000000000000..1ed359c9e70b1 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/FilesUploadRangeResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the uploadRange operation. + */ +public final class FilesUploadRangeResponse extends ResponseBase { + /** + * Creates an instance of FilesUploadRangeResponse. + * + * @param request the request which resulted in this FilesUploadRangeResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public FilesUploadRangeResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, FileUploadRangeHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/HandleItem.java b/storage/client/file/src/main/java/com/azure/storage/file/models/HandleItem.java new file mode 100644 index 0000000000000..a6f6d360a65e9 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/HandleItem.java @@ -0,0 +1,251 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * A listed Azure Storage handle item. + */ +@JacksonXmlRootElement(localName = "Handle") +public final class HandleItem { + /* + * XSMB service handle ID + */ + @JsonProperty(value = "HandleId", required = true) + private String handleId; + + /* + * File or directory name including full path starting from share root + */ + @JsonProperty(value = "Path", required = true) + private String path; + + /* + * FileId uniquely identifies the file or directory. + */ + @JsonProperty(value = "FileId", required = true) + private String fileId; + + /* + * ParentId uniquely identifies the parent directory of the object. + */ + @JsonProperty(value = "ParentId") + private String parentId; + + /* + * SMB session ID in context of which the file handle was opened + */ + @JsonProperty(value = "SessionId", required = true) + private String sessionId; + + /* + * Client IP that opened the handle + */ + @JsonProperty(value = "ClientIp", required = true) + private String clientIp; + + /* + * Time when the session that previously opened the handle has last been + * reconnected. (UTC) + */ + @JsonProperty(value = "OpenTime", required = true) + private DateTimeRfc1123 openTime; + + /* + * Time handle was last connected to (UTC) + */ + @JsonProperty(value = "LastReconnectTime") + private DateTimeRfc1123 lastReconnectTime; + + /** + * Get the handleId property: XSMB service handle ID. + * + * @return the handleId value. + */ + public String handleId() { + return this.handleId; + } + + /** + * Set the handleId property: XSMB service handle ID. + * + * @param handleId the handleId value to set. + * @return the HandleItem object itself. + */ + public HandleItem handleId(String handleId) { + this.handleId = handleId; + return this; + } + + /** + * Get the path property: File or directory name including full path + * starting from share root. + * + * @return the path value. + */ + public String path() { + return this.path; + } + + /** + * Set the path property: File or directory name including full path + * starting from share root. + * + * @param path the path value to set. + * @return the HandleItem object itself. + */ + public HandleItem path(String path) { + this.path = path; + return this; + } + + /** + * Get the fileId property: FileId uniquely identifies the file or + * directory. + * + * @return the fileId value. + */ + public String fileId() { + return this.fileId; + } + + /** + * Set the fileId property: FileId uniquely identifies the file or + * directory. + * + * @param fileId the fileId value to set. + * @return the HandleItem object itself. + */ + public HandleItem fileId(String fileId) { + this.fileId = fileId; + return this; + } + + /** + * Get the parentId property: ParentId uniquely identifies the parent + * directory of the object. + * + * @return the parentId value. + */ + public String parentId() { + return this.parentId; + } + + /** + * Set the parentId property: ParentId uniquely identifies the parent + * directory of the object. + * + * @param parentId the parentId value to set. + * @return the HandleItem object itself. + */ + public HandleItem parentId(String parentId) { + this.parentId = parentId; + return this; + } + + /** + * Get the sessionId property: SMB session ID in context of which the file + * handle was opened. + * + * @return the sessionId value. + */ + public String sessionId() { + return this.sessionId; + } + + /** + * Set the sessionId property: SMB session ID in context of which the file + * handle was opened. + * + * @param sessionId the sessionId value to set. + * @return the HandleItem object itself. + */ + public HandleItem sessionId(String sessionId) { + this.sessionId = sessionId; + return this; + } + + /** + * Get the clientIp property: Client IP that opened the handle. + * + * @return the clientIp value. + */ + public String clientIp() { + return this.clientIp; + } + + /** + * Set the clientIp property: Client IP that opened the handle. + * + * @param clientIp the clientIp value to set. + * @return the HandleItem object itself. + */ + public HandleItem clientIp(String clientIp) { + this.clientIp = clientIp; + return this; + } + + /** + * Get the openTime property: Time when the session that previously opened + * the handle has last been reconnected. (UTC). + * + * @return the openTime value. + */ + public OffsetDateTime openTime() { + if (this.openTime == null) { + return null; + } + return this.openTime.dateTime(); + } + + /** + * Set the openTime property: Time when the session that previously opened + * the handle has last been reconnected. (UTC). + * + * @param openTime the openTime value to set. + * @return the HandleItem object itself. + */ + public HandleItem openTime(OffsetDateTime openTime) { + if (openTime == null) { + this.openTime = null; + } else { + this.openTime = new DateTimeRfc1123(openTime); + } + return this; + } + + /** + * Get the lastReconnectTime property: Time handle was last connected to + * (UTC). + * + * @return the lastReconnectTime value. + */ + public OffsetDateTime lastReconnectTime() { + if (this.lastReconnectTime == null) { + return null; + } + return this.lastReconnectTime.dateTime(); + } + + /** + * Set the lastReconnectTime property: Time handle was last connected to + * (UTC). + * + * @param lastReconnectTime the lastReconnectTime value to set. + * @return the HandleItem object itself. + */ + public HandleItem lastReconnectTime(OffsetDateTime lastReconnectTime) { + if (lastReconnectTime == null) { + this.lastReconnectTime = null; + } else { + this.lastReconnectTime = new DateTimeRfc1123(lastReconnectTime); + } + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ListFilesAndDirectoriesSegmentResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ListFilesAndDirectoriesSegmentResponse.java new file mode 100644 index 0000000000000..1ba129b882372 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ListFilesAndDirectoriesSegmentResponse.java @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * An enumeration of directories and files. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListFilesAndDirectoriesSegmentResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The shareName property. + */ + @JacksonXmlProperty(localName = "ShareName", isAttribute = true) + private String shareName; + + /* + * The shareSnapshot property. + */ + @JacksonXmlProperty(localName = "ShareSnapshot", isAttribute = true) + private String shareSnapshot; + + /* + * The directoryPath property. + */ + @JacksonXmlProperty(localName = "DirectoryPath", isAttribute = true) + private String directoryPath; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix", required = true) + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker") + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults") + private Integer maxResults; + + /* + * The segment property. + */ + @JsonProperty(value = "Entries", required = true) + private FilesAndDirectoriesListSegment segment; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the shareName property: The shareName property. + * + * @return the shareName value. + */ + public String shareName() { + return this.shareName; + } + + /** + * Set the shareName property: The shareName property. + * + * @param shareName the shareName value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse shareName(String shareName) { + this.shareName = shareName; + return this; + } + + /** + * Get the shareSnapshot property: The shareSnapshot property. + * + * @return the shareSnapshot value. + */ + public String shareSnapshot() { + return this.shareSnapshot; + } + + /** + * Set the shareSnapshot property: The shareSnapshot property. + * + * @param shareSnapshot the shareSnapshot value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse shareSnapshot(String shareSnapshot) { + this.shareSnapshot = shareSnapshot; + return this; + } + + /** + * Get the directoryPath property: The directoryPath property. + * + * @return the directoryPath value. + */ + public String directoryPath() { + return this.directoryPath; + } + + /** + * Set the directoryPath property: The directoryPath property. + * + * @param directoryPath the directoryPath value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse directoryPath(String directoryPath) { + this.directoryPath = directoryPath; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public Integer maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse maxResults(Integer maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the segment property: The segment property. + * + * @return the segment value. + */ + public FilesAndDirectoriesListSegment segment() { + return this.segment; + } + + /** + * Set the segment property: The segment property. + * + * @param segment the segment value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse segment(FilesAndDirectoriesListSegment segment) { + this.segment = segment; + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListFilesAndDirectoriesSegmentResponse object itself. + */ + public ListFilesAndDirectoriesSegmentResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ListHandlesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ListHandlesResponse.java new file mode 100644 index 0000000000000..0592fa5d4e37e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ListHandlesResponse.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * An enumeration of handles. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListHandlesResponse { + private static final class EntriesWrapper { + @JacksonXmlProperty(localName = "Handle") + private final List items; + + @JsonCreator + private EntriesWrapper(@JacksonXmlProperty(localName = "Handle") List items) { + this.items = items; + } + } + + /* + * The handleList property. + */ + @JsonProperty(value = "Entries") + private EntriesWrapper handleList; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the handleList property: The handleList property. + * + * @return the handleList value. + */ + public List handleList() { + if (this.handleList == null) { + this.handleList = new EntriesWrapper(new ArrayList()); + } + return this.handleList.items; + } + + /** + * Set the handleList property: The handleList property. + * + * @param handleList the handleList value to set. + * @return the ListHandlesResponse object itself. + */ + public ListHandlesResponse handleList(List handleList) { + this.handleList = new EntriesWrapper(handleList); + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListHandlesResponse object itself. + */ + public ListHandlesResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesIncludeType.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesIncludeType.java new file mode 100644 index 0000000000000..381c8539df3cb --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesIncludeType.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for ListSharesIncludeType. + */ +public enum ListSharesIncludeType { + /** + * Enum value snapshots. + */ + SNAPSHOTS("snapshots"), + + /** + * Enum value metadata. + */ + METADATA("metadata"); + + /** + * The actual serialized value for a ListSharesIncludeType instance. + */ + private final String value; + + ListSharesIncludeType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a ListSharesIncludeType instance. + * + * @param value the serialized value to parse. + * @return the parsed ListSharesIncludeType object, or null if unable to parse. + */ + @JsonCreator + public static ListSharesIncludeType fromString(String value) { + ListSharesIncludeType[] items = ListSharesIncludeType.values(); + for (ListSharesIncludeType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesOptions.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesOptions.java new file mode 100644 index 0000000000000..612b95238ea2a --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesOptions.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class ListSharesOptions { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesResponse.java new file mode 100644 index 0000000000000..97a7c340f5b69 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ListSharesResponse.java @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * An enumeration of shares. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListSharesResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix") + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker") + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults") + private Integer maxResults; + + private static final class SharesWrapper { + @JacksonXmlProperty(localName = "Share") + private final List items; + + @JsonCreator + private SharesWrapper(@JacksonXmlProperty(localName = "Share") List items) { + this.items = items; + } + } + + /* + * The shareItems property. + */ + @JsonProperty(value = "Shares") + private SharesWrapper shareItems; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public Integer maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse maxResults(Integer maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the shareItems property: The shareItems property. + * + * @return the shareItems value. + */ + public List shareItems() { + if (this.shareItems == null) { + this.shareItems = new SharesWrapper(new ArrayList()); + } + return this.shareItems.items; + } + + /** + * Set the shareItems property: The shareItems property. + * + * @param shareItems the shareItems value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse shareItems(List shareItems) { + this.shareItems = new SharesWrapper(shareItems); + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListSharesResponse object itself. + */ + public ListSharesResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/Metrics.java b/storage/client/file/src/main/java/com/azure/storage/file/models/Metrics.java new file mode 100644 index 0000000000000..a6272111de5ef --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/Metrics.java @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Storage Analytics metrics for file service. + */ +@JacksonXmlRootElement(localName = "Metrics") +public final class Metrics { + /* + * The version of Storage Analytics to configure. + */ + @JsonProperty(value = "Version", required = true) + private String version; + + /* + * Indicates whether metrics are enabled for the File service. + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates whether metrics should generate summary statistics for called + * API operations. + */ + @JsonProperty(value = "IncludeAPIs") + private Boolean includeAPIs; + + /* + * The retentionPolicy property. + */ + @JsonProperty(value = "RetentionPolicy") + private RetentionPolicy retentionPolicy; + + /** + * Get the version property: The version of Storage Analytics to configure. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: The version of Storage Analytics to configure. + * + * @param version the version value to set. + * @return the Metrics object itself. + */ + public Metrics version(String version) { + this.version = version; + return this; + } + + /** + * Get the enabled property: Indicates whether metrics are enabled for the + * File service. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether metrics are enabled for the + * File service. + * + * @param enabled the enabled value to set. + * @return the Metrics object itself. + */ + public Metrics enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @return the includeAPIs value. + */ + public Boolean includeAPIs() { + return this.includeAPIs; + } + + /** + * Set the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @param includeAPIs the includeAPIs value to set. + * @return the Metrics object itself. + */ + public Metrics includeAPIs(Boolean includeAPIs) { + this.includeAPIs = includeAPIs; + return this; + } + + /** + * Get the retentionPolicy property: The retentionPolicy property. + * + * @return the retentionPolicy value. + */ + public RetentionPolicy retentionPolicy() { + return this.retentionPolicy; + } + + /** + * Set the retentionPolicy property: The retentionPolicy property. + * + * @param retentionPolicy the retentionPolicy value to set. + * @return the Metrics object itself. + */ + public Metrics retentionPolicy(RetentionPolicy retentionPolicy) { + this.retentionPolicy = retentionPolicy; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/Range.java b/storage/client/file/src/main/java/com/azure/storage/file/models/Range.java new file mode 100644 index 0000000000000..d097cb3af18be --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/Range.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * An Azure Storage file range. + */ +@JacksonXmlRootElement(localName = "Range") +public final class Range { + /* + * Start of the range. + */ + @JsonProperty(value = "Start", required = true) + private long start; + + /* + * End of the range. + */ + @JsonProperty(value = "End", required = true) + private long end; + + /** + * Get the start property: Start of the range. + * + * @return the start value. + */ + public long start() { + return this.start; + } + + /** + * Set the start property: Start of the range. + * + * @param start the start value to set. + * @return the Range object itself. + */ + public Range start(long start) { + this.start = start; + return this; + } + + /** + * Get the end property: End of the range. + * + * @return the end value. + */ + public long end() { + return this.end; + } + + /** + * Set the end property: End of the range. + * + * @param end the end value to set. + * @return the Range object itself. + */ + public Range end(long end) { + this.end = end; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/RetentionPolicy.java b/storage/client/file/src/main/java/com/azure/storage/file/models/RetentionPolicy.java new file mode 100644 index 0000000000000..9e8cb19acd17b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/RetentionPolicy.java @@ -0,0 +1,80 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The retention policy. + */ +@JacksonXmlRootElement(localName = "RetentionPolicy") +public final class RetentionPolicy { + /* + * Indicates whether a retention policy is enabled for the File service. If + * false, metrics data is retained, and the user is responsible for + * deleting it. + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates the number of days that metrics data should be retained. All + * data older than this value will be deleted. Metrics data is deleted on a + * best-effort basis after the retention period expires. + */ + @JsonProperty(value = "Days") + private Integer days; + + /** + * Get the enabled property: Indicates whether a retention policy is + * enabled for the File service. If false, metrics data is retained, and + * the user is responsible for deleting it. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether a retention policy is + * enabled for the File service. If false, metrics data is retained, and + * the user is responsible for deleting it. + * + * @param enabled the enabled value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the days property: Indicates the number of days that metrics data + * should be retained. All data older than this value will be deleted. + * Metrics data is deleted on a best-effort basis after the retention + * period expires. + * + * @return the days value. + */ + public Integer days() { + return this.days; + } + + /** + * Set the days property: Indicates the number of days that metrics data + * should be retained. All data older than this value will be deleted. + * Metrics data is deleted on a best-effort basis after the retention + * period expires. + * + * @param days the days value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy days(Integer days) { + this.days = days; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceGetPropertiesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceGetPropertiesHeaders.java new file mode 100644 index 0000000000000..409494366dcf8 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceGetPropertiesHeaders.java @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-GetProperties-Headers") +public final class ServiceGetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceListSharesSegmentHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceListSharesSegmentHeaders.java new file mode 100644 index 0000000000000..a735f1b81589d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceListSharesSegmentHeaders.java @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for ListSharesSegment operation. + */ +@JacksonXmlRootElement(localName = "Service-ListSharesSegment-Headers") +public final class ServiceListSharesSegmentHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceListSharesSegmentHeaders object itself. + */ + public ServiceListSharesSegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ServiceListSharesSegmentHeaders object itself. + */ + public ServiceListSharesSegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceListSharesSegmentHeaders object itself. + */ + public ServiceListSharesSegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceSetPropertiesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceSetPropertiesHeaders.java new file mode 100644 index 0000000000000..43ce484399730 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServiceSetPropertiesHeaders.java @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for SetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-SetProperties-Headers") +public final class ServiceSetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesGetPropertiesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesGetPropertiesResponse.java new file mode 100644 index 0000000000000..267a198ab8b8d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesGetPropertiesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class ServicesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetPropertiesResponse. + * + * @param request the request which resulted in this ServicesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, StorageServiceProperties value, ServiceGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public StorageServiceProperties value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesListSharesSegmentResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesListSharesSegmentResponse.java new file mode 100644 index 0000000000000..62c1b74d4824a --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesListSharesSegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listSharesSegment operation. + */ +public final class ServicesListSharesSegmentResponse extends ResponseBase { + /** + * Creates an instance of ServicesListSharesSegmentResponse. + * + * @param request the request which resulted in this ServicesListSharesSegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesListSharesSegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListSharesResponse value, ServiceListSharesSegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListSharesResponse value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesSetPropertiesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesSetPropertiesResponse.java new file mode 100644 index 0000000000000..db07375b93e7e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ServicesSetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setProperties operation. + */ +public final class ServicesSetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesSetPropertiesResponse. + * + * @param request the request which resulted in this ServicesSetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesSetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ServiceSetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateHeaders.java new file mode 100644 index 0000000000000..32ec5a693c9fc --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "Share-Create-Headers") +public final class ShareCreateHeaders { + /* + * The ETag contains a value which represents the version of the share, in + * quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties or metadata updates the last + * modified time. Operations on files do not affect the last modified time + * of the share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the share, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the share, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * or metadata updates the last modified time. Operations on files do not + * affect the last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * or metadata updates the last modified time. Operations on files do not + * affect the last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareCreateHeaders object itself. + */ + public ShareCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateSnapshotHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateSnapshotHeaders.java new file mode 100644 index 0000000000000..5163b958e1a2d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareCreateSnapshotHeaders.java @@ -0,0 +1,266 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for CreateSnapshot operation. + */ +@JacksonXmlRootElement(localName = "Share-CreateSnapshot-Headers") +public final class ShareCreateSnapshotHeaders { + /* + * This header is a DateTime value that uniquely identifies the share + * snapshot. The value of this header may be used in subsequent requests to + * access the share snapshot. This value is opaque. + */ + @JsonProperty(value = "x-ms-snapshot") + private String snapshot; + + /* + * The ETag contains a value which represents the version of the share + * snapshot, in quotes. A share snapshot cannot be modified, so the ETag of + * a given share snapshot never changes. However, if new metadata was + * supplied with the Snapshot Share request then the ETag of the share + * snapshot differs from that of the base share. If no metadata was + * specified with the request, the ETag of the share snapshot is identical + * to that of the base share at the time the share snapshot was taken. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. A share snapshot + * cannot be modified, so the last modified time of a given share snapshot + * never changes. However, if new metadata was supplied with the Snapshot + * Share request then the last modified time of the share snapshot differs + * from that of the base share. If no metadata was specified with the + * request, the last modified time of the share snapshot is identical to + * that of the base share at the time the share snapshot was taken. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the snapshot property: This header is a DateTime value that uniquely + * identifies the share snapshot. The value of this header may be used in + * subsequent requests to access the share snapshot. This value is opaque. + * + * @return the snapshot value. + */ + public String snapshot() { + return this.snapshot; + } + + /** + * Set the snapshot property: This header is a DateTime value that uniquely + * identifies the share snapshot. The value of this header may be used in + * subsequent requests to access the share snapshot. This value is opaque. + * + * @param snapshot the snapshot value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Get the eTag property: The ETag contains a value which represents the + * version of the share snapshot, in quotes. A share snapshot cannot be + * modified, so the ETag of a given share snapshot never changes. However, + * if new metadata was supplied with the Snapshot Share request then the + * ETag of the share snapshot differs from that of the base share. If no + * metadata was specified with the request, the ETag of the share snapshot + * is identical to that of the base share at the time the share snapshot + * was taken. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value which represents the + * version of the share snapshot, in quotes. A share snapshot cannot be + * modified, so the ETag of a given share snapshot never changes. However, + * if new metadata was supplied with the Snapshot Share request then the + * ETag of the share snapshot differs from that of the base share. If no + * metadata was specified with the request, the ETag of the share snapshot + * is identical to that of the base share at the time the share snapshot + * was taken. + * + * @param eTag the eTag value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. A share snapshot cannot be modified, so the last modified + * time of a given share snapshot never changes. However, if new metadata + * was supplied with the Snapshot Share request then the last modified time + * of the share snapshot differs from that of the base share. If no + * metadata was specified with the request, the last modified time of the + * share snapshot is identical to that of the base share at the time the + * share snapshot was taken. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. A share snapshot cannot be modified, so the last modified + * time of a given share snapshot never changes. However, if new metadata + * was supplied with the Snapshot Share request then the last modified time + * of the share snapshot differs from that of the base share. If no + * metadata was specified with the request, the last modified time of the + * share snapshot is identical to that of the base share at the time the + * share snapshot was taken. + * + * @param lastModified the lastModified value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareCreateSnapshotHeaders object itself. + */ + public ShareCreateSnapshotHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareDeleteHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareDeleteHeaders.java new file mode 100644 index 0000000000000..ce8c796eba7c6 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareDeleteHeaders.java @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "Share-Delete-Headers") +public final class ShareDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareDeleteHeaders object itself. + */ + public ShareDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareDeleteHeaders object itself. + */ + public ShareDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareDeleteHeaders object itself. + */ + public ShareDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareDeleteHeaders object itself. + */ + public ShareDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetAccessPolicyHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..9988562a78509 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetAccessPolicyHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Share-GetAccessPolicy-Headers") +public final class ShareGetAccessPolicyHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareGetAccessPolicyHeaders object itself. + */ + public ShareGetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetPropertiesHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetPropertiesHeaders.java new file mode 100644 index 0000000000000..c9534dc5060b2 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetPropertiesHeaders.java @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Share-GetProperties-Headers") +public final class ShareGetPropertiesHeaders { + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * Returns the current share quota in GB. + */ + @JsonProperty(value = "x-ms-share-quota") + private Integer quota; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the quota property: Returns the current share quota in GB. + * + * @return the quota value. + */ + public Integer quota() { + return this.quota; + } + + /** + * Set the quota property: Returns the current share quota in GB. + * + * @param quota the quota value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders quota(Integer quota) { + this.quota = quota; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareGetPropertiesHeaders object itself. + */ + public ShareGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetStatisticsHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetStatisticsHeaders.java new file mode 100644 index 0000000000000..575cafb0351a9 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareGetStatisticsHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetStatistics operation. + */ +@JacksonXmlRootElement(localName = "Share-GetStatistics-Headers") +public final class ShareGetStatisticsHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareGetStatisticsHeaders object itself. + */ + public ShareGetStatisticsHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareInfo.java new file mode 100644 index 0000000000000..ed706bd02166b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class ShareInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareItem.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareItem.java new file mode 100644 index 0000000000000..23a64ac334548 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareItem.java @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.Map; + +/** + * A listed Azure Storage share item. + */ +@JacksonXmlRootElement(localName = "Share") +public final class ShareItem { + /* + * The name property. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The snapshot property. + */ + @JsonProperty(value = "Snapshot") + private String snapshot; + + /* + * The properties property. + */ + @JsonProperty(value = "Properties", required = true) + private ShareProperties properties; + + /* + * The metadata property. + */ + @JsonProperty(value = "Metadata") + private Map metadata; + + /** + * Get the name property: The name property. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name property. + * + * @param name the name value to set. + * @return the ShareItem object itself. + */ + public ShareItem name(String name) { + this.name = name; + return this; + } + + /** + * Get the snapshot property: The snapshot property. + * + * @return the snapshot value. + */ + public String snapshot() { + return this.snapshot; + } + + /** + * Set the snapshot property: The snapshot property. + * + * @param snapshot the snapshot value to set. + * @return the ShareItem object itself. + */ + public ShareItem snapshot(String snapshot) { + this.snapshot = snapshot; + return this; + } + + /** + * Get the properties property: The properties property. + * + * @return the properties value. + */ + public ShareProperties properties() { + return this.properties; + } + + /** + * Set the properties property: The properties property. + * + * @param properties the properties value to set. + * @return the ShareItem object itself. + */ + public ShareItem properties(ShareProperties properties) { + this.properties = properties; + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the ShareItem object itself. + */ + public ShareItem metadata(Map metadata) { + this.metadata = metadata; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareProperties.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareProperties.java new file mode 100644 index 0000000000000..66e92994f800e --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareProperties.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Properties of a share. + */ +@JacksonXmlRootElement(localName = "ShareProperties") +public final class ShareProperties { + /* + * The lastModified property. + */ + @JsonProperty(value = "Last-Modified", required = true) + private DateTimeRfc1123 lastModified; + + /* + * The etag property. + */ + @JsonProperty(value = "Etag", required = true) + private String etag; + + /* + * The quota property. + */ + @JsonProperty(value = "Quota", required = true) + private int quota; + + /** + * Get the lastModified property: The lastModified property. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: The lastModified property. + * + * @param lastModified the lastModified value to set. + * @return the ShareProperties object itself. + */ + public ShareProperties lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the etag property: The etag property. + * + * @return the etag value. + */ + public String etag() { + return this.etag; + } + + /** + * Set the etag property: The etag property. + * + * @param etag the etag value to set. + * @return the ShareProperties object itself. + */ + public ShareProperties etag(String etag) { + this.etag = etag; + return this; + } + + /** + * Get the quota property: The quota property. + * + * @return the quota value. + */ + public int quota() { + return this.quota; + } + + /** + * Set the quota property: The quota property. + * + * @param quota the quota value to set. + * @return the ShareProperties object itself. + */ + public ShareProperties quota(int quota) { + this.quota = quota; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetAccessPolicyHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..4a688b1d61e4d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetAccessPolicyHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Share-SetAccessPolicy-Headers") +public final class ShareSetAccessPolicyHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareSetAccessPolicyHeaders object itself. + */ + public ShareSetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetMetadataHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetMetadataHeaders.java new file mode 100644 index 0000000000000..f92662e355a14 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetMetadataHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "Share-SetMetadata-Headers") +public final class ShareSetMetadataHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareSetMetadataHeaders object itself. + */ + public ShareSetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetQuotaHeaders.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetQuotaHeaders.java new file mode 100644 index 0000000000000..819b1046c923b --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSetQuotaHeaders.java @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetQuota operation. + */ +@JacksonXmlRootElement(localName = "Share-SetQuota-Headers") +public final class ShareSetQuotaHeaders { + /* + * The ETag contains a value that you can use to perform operations + * conditionally, in quotes. + */ + @JsonProperty(value = "ETag") + private String eTag; + + /* + * Returns the date and time the share was last modified. Any operation + * that modifies the share or its properties updates the last modified + * time. Operations on files do not affect the last modified time of the + * share. + */ + @JsonProperty(value = "Last-Modified") + private DateTimeRfc1123 lastModified; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the File service used to execute the request. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * A UTC date/time value generated by the service that indicates the time + * at which the response was initiated. + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @return the eTag value. + */ + public String eTag() { + return this.eTag; + } + + /** + * Set the eTag property: The ETag contains a value that you can use to + * perform operations conditionally, in quotes. + * + * @param eTag the eTag value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders eTag(String eTag) { + this.eTag = eTag; + return this; + } + + /** + * Get the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @return the lastModified value. + */ + public OffsetDateTime lastModified() { + if (this.lastModified == null) { + return null; + } + return this.lastModified.dateTime(); + } + + /** + * Set the lastModified property: Returns the date and time the share was + * last modified. Any operation that modifies the share or its properties + * updates the last modified time. Operations on files do not affect the + * last modified time of the share. + * + * @param lastModified the lastModified value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders lastModified(OffsetDateTime lastModified) { + if (lastModified == null) { + this.lastModified = null; + } else { + this.lastModified = new DateTimeRfc1123(lastModified); + } + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the File service used + * to execute the request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the File service used + * to execute the request. + * + * @param version the version value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: A UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ShareSetQuotaHeaders object itself. + */ + public ShareSetQuotaHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSnapshotInfo.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSnapshotInfo.java new file mode 100644 index 0000000000000..2a3e17d8ad01d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareSnapshotInfo.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class ShareSnapshotInfo { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStatistics.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStatistics.java new file mode 100644 index 0000000000000..aef819551c53f --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStatistics.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.file.models; + +public final class ShareStatistics { +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStats.java b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStats.java new file mode 100644 index 0000000000000..6738332eb4709 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/ShareStats.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Stats for the share. + */ +@JacksonXmlRootElement(localName = "ShareStats") +public final class ShareStats { + /* + * The approximate size of the data stored in bytes, rounded up to the + * nearest gigabyte. Note that this value may not include all recently + * created or recently resized files. + */ + @JsonProperty(value = "ShareUsageBytes", required = true) + private int shareUsageBytes; + + /** + * Get the shareUsageBytes property: The approximate size of the data + * stored in bytes, rounded up to the nearest gigabyte. Note that this + * value may not include all recently created or recently resized files. + * + * @return the shareUsageBytes value. + */ + public int shareUsageBytes() { + return this.shareUsageBytes; + } + + /** + * Set the shareUsageBytes property: The approximate size of the data + * stored in bytes, rounded up to the nearest gigabyte. Note that this + * value may not include all recently created or recently resized files. + * + * @param shareUsageBytes the shareUsageBytes value to set. + * @return the ShareStats object itself. + */ + public ShareStats shareUsageBytes(int shareUsageBytes) { + this.shareUsageBytes = shareUsageBytes; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateResponse.java new file mode 100644 index 0000000000000..240af8232a16d --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class SharesCreateResponse extends ResponseBase { + /** + * Creates an instance of SharesCreateResponse. + * + * @param request the request which resulted in this SharesCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateSnapshotResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateSnapshotResponse.java new file mode 100644 index 0000000000000..b9f9d375c2803 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesCreateSnapshotResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the createSnapshot operation. + */ +public final class SharesCreateSnapshotResponse extends ResponseBase { + /** + * Creates an instance of SharesCreateSnapshotResponse. + * + * @param request the request which resulted in this SharesCreateSnapshotResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesCreateSnapshotResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareCreateSnapshotHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesDeleteResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesDeleteResponse.java new file mode 100644 index 0000000000000..9477ce4c7e8b8 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class SharesDeleteResponse extends ResponseBase { + /** + * Creates an instance of SharesDeleteResponse. + * + * @param request the request which resulted in this SharesDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetAccessPolicyResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetAccessPolicyResponse.java new file mode 100644 index 0000000000000..a48f3b3b30834 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetAccessPolicyResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the getAccessPolicy operation. + */ +public final class SharesGetAccessPolicyResponse extends ResponseBase> { + /** + * Creates an instance of SharesGetAccessPolicyResponse. + * + * @param request the request which resulted in this SharesGetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesGetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, ShareGetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetPropertiesResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetPropertiesResponse.java new file mode 100644 index 0000000000000..9716a989187a0 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class SharesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of SharesGetPropertiesResponse. + * + * @param request the request which resulted in this SharesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetStatisticsResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetStatisticsResponse.java new file mode 100644 index 0000000000000..ff9d976a06066 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesGetStatisticsResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getStatistics operation. + */ +public final class SharesGetStatisticsResponse extends ResponseBase { + /** + * Creates an instance of SharesGetStatisticsResponse. + * + * @param request the request which resulted in this SharesGetStatisticsResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesGetStatisticsResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ShareStats value, ShareGetStatisticsHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ShareStats value() { + return super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetAccessPolicyResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetAccessPolicyResponse.java new file mode 100644 index 0000000000000..e510ad67fc75c --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetAccessPolicyResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setAccessPolicy operation. + */ +public final class SharesSetAccessPolicyResponse extends ResponseBase { + /** + * Creates an instance of SharesSetAccessPolicyResponse. + * + * @param request the request which resulted in this SharesSetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesSetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareSetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetMetadataResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetMetadataResponse.java new file mode 100644 index 0000000000000..ee0c5437446a7 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class SharesSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of SharesSetMetadataResponse. + * + * @param request the request which resulted in this SharesSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareSetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetQuotaResponse.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetQuotaResponse.java new file mode 100644 index 0000000000000..af406592123d5 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SharesSetQuotaResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setQuota operation. + */ +public final class SharesSetQuotaResponse extends ResponseBase { + /** + * Creates an instance of SharesSetQuotaResponse. + * + * @param request the request which resulted in this SharesSetQuotaResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public SharesSetQuotaResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ShareSetQuotaHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/SignedIdentifier.java b/storage/client/file/src/main/java/com/azure/storage/file/models/SignedIdentifier.java new file mode 100644 index 0000000000000..566ab7070c713 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/SignedIdentifier.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Signed identifier. + */ +@JacksonXmlRootElement(localName = "SignedIdentifier") +public final class SignedIdentifier { + /* + * A unique id. + */ + @JsonProperty(value = "Id", required = true) + private String id; + + /* + * The access policy. + */ + @JsonProperty(value = "AccessPolicy") + private AccessPolicy accessPolicy; + + /** + * Get the id property: A unique id. + * + * @return the id value. + */ + public String id() { + return this.id; + } + + /** + * Set the id property: A unique id. + * + * @param id the id value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier id(String id) { + this.id = id; + return this; + } + + /** + * Get the accessPolicy property: The access policy. + * + * @return the accessPolicy value. + */ + public AccessPolicy accessPolicy() { + return this.accessPolicy; + } + + /** + * Set the accessPolicy property: The access policy. + * + * @param accessPolicy the accessPolicy value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier accessPolicy(AccessPolicy accessPolicy) { + this.accessPolicy = accessPolicy; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/StorageError.java b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageError.java new file mode 100644 index 0000000000000..801db72d87c0a --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageError.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The StorageError model. + */ +@JacksonXmlRootElement(localName = "StorageError") +public final class StorageError { + /* + * The message property. + */ + @JsonProperty(value = "Message") + private String message; + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String message() { + return this.message; + } + + /** + * Set the message property: The message property. + * + * @param message the message value to set. + * @return the StorageError object itself. + */ + public StorageError message(String message) { + this.message = message; + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorCode.java b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorCode.java new file mode 100644 index 0000000000000..682ff493c1918 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorCode.java @@ -0,0 +1,332 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for StorageErrorCode. + */ +public final class StorageErrorCode extends ExpandableStringEnum { + /** + * Static value AccountAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_ALREADY_EXISTS = fromString("AccountAlreadyExists"); + + /** + * Static value AccountBeingCreated for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_BEING_CREATED = fromString("AccountBeingCreated"); + + /** + * Static value AccountIsDisabled for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_IS_DISABLED = fromString("AccountIsDisabled"); + + /** + * Static value AuthenticationFailed for StorageErrorCode. + */ + public static final StorageErrorCode AUTHENTICATION_FAILED = fromString("AuthenticationFailed"); + + /** + * Static value AuthorizationFailure for StorageErrorCode. + */ + public static final StorageErrorCode AUTHORIZATION_FAILURE = fromString("AuthorizationFailure"); + + /** + * Static value ConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_HEADERS_NOT_SUPPORTED = fromString("ConditionHeadersNotSupported"); + + /** + * Static value ConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_NOT_MET = fromString("ConditionNotMet"); + + /** + * Static value EmptyMetadataKey for StorageErrorCode. + */ + public static final StorageErrorCode EMPTY_METADATA_KEY = fromString("EmptyMetadataKey"); + + /** + * Static value InsufficientAccountPermissions for StorageErrorCode. + */ + public static final StorageErrorCode INSUFFICIENT_ACCOUNT_PERMISSIONS = fromString("InsufficientAccountPermissions"); + + /** + * Static value InternalError for StorageErrorCode. + */ + public static final StorageErrorCode INTERNAL_ERROR = fromString("InternalError"); + + /** + * Static value InvalidAuthenticationInfo for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_AUTHENTICATION_INFO = fromString("InvalidAuthenticationInfo"); + + /** + * Static value InvalidHeaderValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HEADER_VALUE = fromString("InvalidHeaderValue"); + + /** + * Static value InvalidHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HTTP_VERB = fromString("InvalidHttpVerb"); + + /** + * Static value InvalidInput for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_INPUT = fromString("InvalidInput"); + + /** + * Static value InvalidMd5 for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_MD5 = fromString("InvalidMd5"); + + /** + * Static value InvalidMetadata for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_METADATA = fromString("InvalidMetadata"); + + /** + * Static value InvalidQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_QUERY_PARAMETER_VALUE = fromString("InvalidQueryParameterValue"); + + /** + * Static value InvalidRange for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RANGE = fromString("InvalidRange"); + + /** + * Static value InvalidResourceName for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RESOURCE_NAME = fromString("InvalidResourceName"); + + /** + * Static value InvalidUri for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_URI = fromString("InvalidUri"); + + /** + * Static value InvalidXmlDocument for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_DOCUMENT = fromString("InvalidXmlDocument"); + + /** + * Static value InvalidXmlNodeValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_NODE_VALUE = fromString("InvalidXmlNodeValue"); + + /** + * Static value Md5Mismatch for StorageErrorCode. + */ + public static final StorageErrorCode MD5MISMATCH = fromString("Md5Mismatch"); + + /** + * Static value MetadataTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode METADATA_TOO_LARGE = fromString("MetadataTooLarge"); + + /** + * Static value MissingContentLengthHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_CONTENT_LENGTH_HEADER = fromString("MissingContentLengthHeader"); + + /** + * Static value MissingRequiredQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_QUERY_PARAMETER = fromString("MissingRequiredQueryParameter"); + + /** + * Static value MissingRequiredHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_HEADER = fromString("MissingRequiredHeader"); + + /** + * Static value MissingRequiredXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_XML_NODE = fromString("MissingRequiredXmlNode"); + + /** + * Static value MultipleConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = fromString("MultipleConditionHeadersNotSupported"); + + /** + * Static value OperationTimedOut for StorageErrorCode. + */ + public static final StorageErrorCode OPERATION_TIMED_OUT = fromString("OperationTimedOut"); + + /** + * Static value OutOfRangeInput for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_INPUT = fromString("OutOfRangeInput"); + + /** + * Static value OutOfRangeQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_QUERY_PARAMETER_VALUE = fromString("OutOfRangeQueryParameterValue"); + + /** + * Static value RequestBodyTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_BODY_TOO_LARGE = fromString("RequestBodyTooLarge"); + + /** + * Static value ResourceTypeMismatch for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_TYPE_MISMATCH = fromString("ResourceTypeMismatch"); + + /** + * Static value RequestUrlFailedToParse for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_URL_FAILED_TO_PARSE = fromString("RequestUrlFailedToParse"); + + /** + * Static value ResourceAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_ALREADY_EXISTS = fromString("ResourceAlreadyExists"); + + /** + * Static value ResourceNotFound for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_NOT_FOUND = fromString("ResourceNotFound"); + + /** + * Static value ServerBusy for StorageErrorCode. + */ + public static final StorageErrorCode SERVER_BUSY = fromString("ServerBusy"); + + /** + * Static value UnsupportedHeader for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HEADER = fromString("UnsupportedHeader"); + + /** + * Static value UnsupportedXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_XML_NODE = fromString("UnsupportedXmlNode"); + + /** + * Static value UnsupportedQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_QUERY_PARAMETER = fromString("UnsupportedQueryParameter"); + + /** + * Static value UnsupportedHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HTTP_VERB = fromString("UnsupportedHttpVerb"); + + /** + * Static value CannotDeleteFileOrDirectory for StorageErrorCode. + */ + public static final StorageErrorCode CANNOT_DELETE_FILE_OR_DIRECTORY = fromString("CannotDeleteFileOrDirectory"); + + /** + * Static value ClientCacheFlushDelay for StorageErrorCode. + */ + public static final StorageErrorCode CLIENT_CACHE_FLUSH_DELAY = fromString("ClientCacheFlushDelay"); + + /** + * Static value DeletePending for StorageErrorCode. + */ + public static final StorageErrorCode DELETE_PENDING = fromString("DeletePending"); + + /** + * Static value DirectoryNotEmpty for StorageErrorCode. + */ + public static final StorageErrorCode DIRECTORY_NOT_EMPTY = fromString("DirectoryNotEmpty"); + + /** + * Static value FileLockConflict for StorageErrorCode. + */ + public static final StorageErrorCode FILE_LOCK_CONFLICT = fromString("FileLockConflict"); + + /** + * Static value InvalidFileOrDirectoryPathName for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_FILE_OR_DIRECTORY_PATH_NAME = fromString("InvalidFileOrDirectoryPathName"); + + /** + * Static value ParentNotFound for StorageErrorCode. + */ + public static final StorageErrorCode PARENT_NOT_FOUND = fromString("ParentNotFound"); + + /** + * Static value ReadOnlyAttribute for StorageErrorCode. + */ + public static final StorageErrorCode READ_ONLY_ATTRIBUTE = fromString("ReadOnlyAttribute"); + + /** + * Static value ShareAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_ALREADY_EXISTS = fromString("ShareAlreadyExists"); + + /** + * Static value ShareBeingDeleted for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_BEING_DELETED = fromString("ShareBeingDeleted"); + + /** + * Static value ShareDisabled for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_DISABLED = fromString("ShareDisabled"); + + /** + * Static value ShareNotFound for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_NOT_FOUND = fromString("ShareNotFound"); + + /** + * Static value SharingViolation for StorageErrorCode. + */ + public static final StorageErrorCode SHARING_VIOLATION = fromString("SharingViolation"); + + /** + * Static value ShareSnapshotInProgress for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_SNAPSHOT_IN_PROGRESS = fromString("ShareSnapshotInProgress"); + + /** + * Static value ShareSnapshotCountExceeded for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_SNAPSHOT_COUNT_EXCEEDED = fromString("ShareSnapshotCountExceeded"); + + /** + * Static value ShareSnapshotOperationNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_SNAPSHOT_OPERATION_NOT_SUPPORTED = fromString("ShareSnapshotOperationNotSupported"); + + /** + * Static value ShareHasSnapshots for StorageErrorCode. + */ + public static final StorageErrorCode SHARE_HAS_SNAPSHOTS = fromString("ShareHasSnapshots"); + + /** + * Static value ContainerQuotaDowngradeNotAllowed for StorageErrorCode. + */ + public static final StorageErrorCode CONTAINER_QUOTA_DOWNGRADE_NOT_ALLOWED = fromString("ContainerQuotaDowngradeNotAllowed"); + + /** + * Creates or finds a StorageErrorCode from its string representation. + * + * @param name a name to look for. + * @return the corresponding StorageErrorCode. + */ + @JsonCreator + public static StorageErrorCode fromString(String name) { + return fromString(name, StorageErrorCode.class); + } + + /** + * @return known StorageErrorCode values. + */ + public static Collection values() { + return values(StorageErrorCode.class); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorException.java b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorException.java new file mode 100644 index 0000000000000..76a6def9161fd --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageErrorException.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; + +/** + * Exception thrown for an invalid response with StorageError information. + */ +public final class StorageErrorException extends HttpResponseException { + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + */ + public StorageErrorException(String message, HttpResponse response) { + super(message, response); + } + + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + * @param value the deserialized response value. + */ + public StorageErrorException(String message, HttpResponse response, StorageError value) { + super(message, response, value); + } + + @Override + public StorageError value() { + return (StorageError) super.value(); + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/StorageServiceProperties.java b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageServiceProperties.java new file mode 100644 index 0000000000000..360b85491edf1 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/StorageServiceProperties.java @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.file.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Storage service properties. + */ +@JacksonXmlRootElement(localName = "StorageServiceProperties") +public final class StorageServiceProperties { + /* + * A summary of request statistics grouped by API in hourly aggregates for + * files. + */ + @JsonProperty(value = "HourMetrics") + private Metrics hourMetrics; + + /* + * A summary of request statistics grouped by API in minute aggregates for + * files. + */ + @JsonProperty(value = "MinuteMetrics") + private Metrics minuteMetrics; + + private static final class CorsWrapper { + @JacksonXmlProperty(localName = "CorsRule") + private final List items; + + @JsonCreator + private CorsWrapper(@JacksonXmlProperty(localName = "CorsRule") List items) { + this.items = items; + } + } + + /* + * The set of CORS rules. + */ + @JsonProperty(value = "Cors") + private CorsWrapper cors; + + /** + * Get the hourMetrics property: A summary of request statistics grouped by + * API in hourly aggregates for files. + * + * @return the hourMetrics value. + */ + public Metrics hourMetrics() { + return this.hourMetrics; + } + + /** + * Set the hourMetrics property: A summary of request statistics grouped by + * API in hourly aggregates for files. + * + * @param hourMetrics the hourMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties hourMetrics(Metrics hourMetrics) { + this.hourMetrics = hourMetrics; + return this; + } + + /** + * Get the minuteMetrics property: A summary of request statistics grouped + * by API in minute aggregates for files. + * + * @return the minuteMetrics value. + */ + public Metrics minuteMetrics() { + return this.minuteMetrics; + } + + /** + * Set the minuteMetrics property: A summary of request statistics grouped + * by API in minute aggregates for files. + * + * @param minuteMetrics the minuteMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties minuteMetrics(Metrics minuteMetrics) { + this.minuteMetrics = minuteMetrics; + return this; + } + + /** + * Get the cors property: The set of CORS rules. + * + * @return the cors value. + */ + public List cors() { + if (this.cors == null) { + this.cors = new CorsWrapper(new ArrayList()); + } + return this.cors.items; + } + + /** + * Set the cors property: The set of CORS rules. + * + * @param cors the cors value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties cors(List cors) { + this.cors = new CorsWrapper(cors); + return this; + } +} diff --git a/storage/client/file/src/main/java/com/azure/storage/file/models/package-info.java b/storage/client/file/src/main/java/com/azure/storage/file/models/package-info.java new file mode 100644 index 0000000000000..b21cb828d0f54 --- /dev/null +++ b/storage/client/file/src/main/java/com/azure/storage/file/models/package-info.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the data models for AzureFileStorage. + */ +package com.azure.storage.file.models; diff --git a/storage/client/queue/README.md b/storage/client/queue/README.md new file mode 100644 index 0000000000000..7b4dbbf1afadd --- /dev/null +++ b/storage/client/queue/README.md @@ -0,0 +1,377 @@ +# Azure Storage Queue client library for Java +Azure Queue storage is a service for storing large numbers of messages that can be accessed from anywhere in the world via authenticated calls using HTTP or HTTPS. +A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account. + +[Source code][source_code] | [Package (Maven)][package] | [API reference documentation][api_documentation] | [Product documentation][storage_docs] + +## Getting started + +### Prerequisites + +- [Java Development Kit (JDK)][jdk] with version 8 or above +- [Azure Subscription][azure_subscription] +- [Create Strorage Account][storage_account] + +### Adding the package to your product + +```xml + + com.azure + azure-storage + 12.0.0 + +``` + +### Create a Storage Account +To create a Storage Account you can use the Azure Portal or [Azure CLI][azure_cli]. + +```Powershell +az group create \ + --name storage-resource-group \ + --location westus +``` + +### Authenticate the client + +In order to interact with the Storage service (Blob, Queue, Message, MessageId, File) you'll need to create an instance of the Service Client class. +To make this possible you'll need the Account SAS (shared access signature) string of Storage account. Learn more at [SAS Token][sas_token] + +#### Get Credentials + +- **SAS Token** + +a. Use the [Azure CLI][azure_cli] snippet below to get the SAS token from the Storage account. + +```Powershell +az storage queue generate-sas + --name {queue name} + --expiry {date/time to expire SAS token} + --permission {permission to grant} + --connection-string {connection string of the storage account} +``` + +```Powershell +CONNECTION_STRING= +#usage example +az storage queue generate-sas + --name javasdksas + --expiry 2019-06-05 + --permission rpau + --connection-string $CONNECTION_STRING +``` +b. Alternatively, get the Account SAS Token from the Azure Portal. +``` +Go to your storage account -> Shared access signature -> Click on Generate SAS and connection string (after setup) +``` + +- **Shared Key Credential** + +a. Use account name and account key. Account name is your storage account name. +``` +// Here is where we get the key +Go to your storage account -> Access keys -> Key 1/ Key 2 -> Key +``` +b. Use the connection string +``` +// Here is where we get the key +Go to your storage account -> Access Keys -> Keys 1/ Key 2 -> Connection string +``` +## Key concepts +### URL format +Queues are addressable using the following URL format: +https://.queue.core.windows.net/ +The following URL addresses a queue in the diagram: +https://myaccount.queue.core.windows.net/images-to-download + +#### Resource URI Syntax +For the storage account, the base URI for queue operations includes the name of the account only: +```$xslt +https://myaccount.queue.core.windows.net +``` +For a queue, the base URI includes the name of the account and the name of the queue: +```$xslt +https://myaccount.queue.core.windows.net/myqueue +``` + +### Handling Exceptions + +```java +TODO +``` + +### Queue Names +Every queue within an account must have a unique name. The queue name must be a valid DNS name, and cannot be changed once created. Queue names must confirm to the following rules: +1. A queue name must start with a letter or number, and can only contain letters, numbers, and the dash (-) character. +1. The first and last letters in the queue name must be alphanumeric. The dash (-) character cannot be the first or last character. Consecutive dash characters are not permitted in the queue name. +1. All letters in a queue name must be lowercase. +1. A queue name must be from 3 through 63 characters long. + +### Queue Services +The queue service do operations on the queues in the storage account and manage the queue properties. + +### Queue Service Client + +The client performs the interactions with the Queue service, create or delete a queue, getting and setting Queue properties, list queues in account, and get queue statistics. An asynchronous, `QueueServiceAsyncClient`, and synchronous, `QueueClient`, client exists in the SDK allowing for selection of a client based on an application's use case. +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${sasToken}`. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); +``` + +or + +```Java +String queueServiceAsyncURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceAsyncClient queueServiceAsyncClient = QueueServiceAsyncClient.builder().endpoint(queueServiceAsyncURL).build(); +queueServiceAsyncClient.createQueue("newAsyncQueue").subscribe( + result -> { + // do something when new queue created + }, + error -> { + // do something if something wrong happened + }, + () -> { + // completed, do something + }); +``` + +### Queue +Azure Queue storage is a service for storing large numbers of messages that can be accessed from anywhere in the world via authenticated calls using HTTP or HTTPS. +A single queue message can be up to 64 KB in size, and a queue can contain millions of messages, up to the total capacity limit of a storage account. + +### QueueClient +Once you have the value of the SASToken you can create the queue service client with `${accountName}`, `${queueName}`, `${sasToken}`. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +// metadata is map of key-value pair, timeout is client side timeout +QueueClient newQueueClient = queueClient.create(metadata, timeout); +``` + +or + +```Java +String queueAsyncURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueAsyncName, sasToken) +QueueAsyncClient queueAsyncClient = QueueAsyncClient.builder().endpoint(queueAsyncURL).build(); +queueAsyncClient.create(metadata, timeout).subscribe( + result -> { + // do something when new queue created + }, + error -> { + // do something if something wrong happened + }, + () -> { + // completed, do something + }); +``` + +## Examples + +The following sections provide several code snippets covering some of the most common Configuration Service tasks, including: +- [Create a Queue](#Create-a-queue) +- [Delete a queue](#Delete-a-queue) +- [List the queues in account](#List-queues-in-account) +- [Get propertiesin Queue account](#Get-properties-in-queue-account) +- [Set propertiesin Queue account](#Set-properties-in-queue-account) +- [Get statistcs of queue](#Get-queue-service-statistics) +- [Enqueue message into a queue](#Enqueue-message-into-a-queue) +- [Update message into a queue](#Update-message-into-a-queue) +- [Peek messages into a queue](#Peek-messages-into-a-queue) +- [Dequeue messages from a queue](#Dequeue-messages-from-a-queue) +- [Delete message from a queue](#Delete-message-from-a-queue) +- [Get a Queue properties](#Get-a-queue-properties) +- [Set/Update a Queue metadata](#Set-a-queue-metadata) +### Create a queue + +Create a queue in the Storage Account. Throws StorageErrorException If the queue fails to be created. + +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.createQueue("myqueue"); +``` +### Delete a queue + +Delete a queue in the Storage Account. Throws StorageErrorException If the queue fails to be deleted. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +QueueClient newQueueServiceClient = queueServiceClient.deleteQueue("myqueue"); +``` + +### List queues in account + +List all the queues in account. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); +// @param marker: Starting point to list the queues +// @param options: Filter for queue selection +queueServiceClient.listQueuesSegment(marker, options).forEach{ + queueItem -> {//do something} +}; +``` + +### Get properties in queue account + +Get queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +Response properties = queueServiceClient.getProperties(); +``` + +### Set properties in queue account + +Set queue properties in account, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +StorageServiceProperties properties = new StorageServiceProperties() { + // logging: some logging; + // HourMetrics: some metrics + // MinuteMetrics: some metrics + // Cors: some cors +} + +queueServiceClient.setProperties(properties); +``` + +### Get queue service statistics +he `Get Queue Service Stats` operation retrieves statistics related to replication for the Queue service. +It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. +```Java +String queueServiceURL = String.format("https://%s.queue.core.windows.net/%s", accountName, sasToken) +QueueServiceClient queueServiceClient = QueueServiceClient.builder().endpoint(queueURL).build(); + +Response queueStats = queueServiceClient.getStatistics(); +``` + +### Enqueue message into a queue +The operation adds a new message to the back of the message queue. A visibility timeout can also be specified to make the message invisible until the visibility timeout expires. +A message must be in a format that can be included in an XML request with UTF-8 encoding. The encoded message can be up to 64 KB in size for versions 2011-08-18 and newer, or 8 KB in size for previous versions. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.enqueueMessage("myMessage"); +``` + +### Update messaged from a queue +The operation updates a message in the message queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); +// @param messageId Id of the message +// @param popReceipt Unique identifier that must match the message for it to be updated +// @param visibilityTimeout How long the message will be invisible in the queue in seconds +queueClient.updateMessage(messageId, "new message", popReceipt, visibilityTimeout); +``` + +### Peek messages from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.peekMessages().forEach(message-> {print message.messageText();}); +``` + + +### Dequeue messages from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.dequeueMessage("myMessage").forEach(message-> {print message.messageText();}); +``` + + +### Delete message from a queue +The operation retrieves one or more messages from the front of the queue. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +queueClient.deleteMessage(messageId, popReceipt); +``` + +### Get a queue properties +The operation retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +Response properties = queueClient.getProperties(); +``` + +### Set a queue metadata +The operation sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. +```Java +String queueURL = String.format("https://%s.queue.core.windows.net/%s%s", accountName, queueName, sasToken); +QueueClient queueClient = QueueClient.builder().endpoint(queueURL).build(); + +Map metadata = new HashMap<>() {{ + put("key1", "val1"); + put("key2", "val2"); +}}; +queueClient.setMetadata(metadata); +``` + + +## Troubleshooting + +## General + +When you interact with queue using this Java client library, errors returned by the service correspond to the same HTTP status codes returned for [REST API][storage_rest] requests. For example, if you try to retrieve a queue that doesn't exist in your Storage Account, a `404` error is returned, indicating `Not Found`. + +## Next steps + +### More Samples +- QueueServiceSample +- MessageSample +- QueueExceptionSample +- AsyncSample + +[Quickstart: Create a Java Spring app with App Configuration](https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-java-spring-app) + +## Contributing +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html). + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + + +[source_code]: to-be-continue +[package]: to-be-continue +[api_documentation]: https://docs.microsoft.com/en-us/rest/api/storageservices/queue-service-rest-api +[storage_docs]: https://docs.microsoft.com/en-us/azure/storage/queues/storage-queues-introduction +[jdk]: https://docs.microsoft.com/en-us/java/azure/java-supported-jdk-runtime?view=azure-java-stable +[maven]: https://maven.apache.org/ +[azure_subscription]: https://azure.microsoft.com/en-us/free/ +[storage_account]: https://docs.microsoft.com/en-us/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal +[azure_cli]: https://docs.microsoft.com/cli/azure +[sas_token]: https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 +[storage_rest]: https://docs.microsoft.com/en-us/rest/api/storageservices/queue-service-error-codes diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java new file mode 100644 index 0000000000000..fe93273e3f64e --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SASTokenCredential.java @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; + +import java.util.HashMap; + +/** + * Holds a SAS token used for authenticating requests. + */ +public final class SASTokenCredential { + // Required SAS token pieces + private static final String SIGNED_VERSION = "sv"; + private static final String SIGNED_SERVICES = "ss"; + private static final String SIGNED_RESOURCE_TYPES = "srt"; + private static final String SIGNED_PERMISSIONS = "sp"; + private static final String SIGNED_EXPIRY = "se"; + private static final String SIGNATURE = "sig"; + + // Optional SAS token pieces + private static final String SIGNED_START = "st"; + private static final String SIGNED_PROTOCOL = "spr"; + private static final String SIGNED_IP = "sip"; + + private final String sasToken; + + /** + * Creates a SAS token credential from the passed SAS token. + * @param sasToken SAS token used to authenticate requests with the service. + */ + public SASTokenCredential(String sasToken) { + this.sasToken = sasToken; + } + + /** + * @return the SAS token + */ + public String sasToken() { + return sasToken; + } + + /** + * Creates a SAS token credential from the passed URL query string + * @param query URL query used to build the SAS token + * @return a SAS token credential if the query param contains all the necessary pieces + */ + public static SASTokenCredential fromQuery(String query) { + if (ImplUtils.isNullOrEmpty(query)) { + return null; + } + + HashMap queryParams = new HashMap<>(); + for (String queryParam : query.split("&")) { + String key = queryParam.split("=", 2)[0]; + queryParams.put(key, queryParam); + } + + if (queryParams.size() < 6 + || !queryParams.containsKey(SIGNED_VERSION) + || !queryParams.containsKey(SIGNED_SERVICES) + || !queryParams.containsKey(SIGNED_RESOURCE_TYPES) + || !queryParams.containsKey(SIGNED_PERMISSIONS) + || !queryParams.containsKey(SIGNED_EXPIRY) + || !queryParams.containsKey(SIGNATURE)) { + return null; + } + + StringBuilder sasTokenBuilder = new StringBuilder(queryParams.get(SIGNED_VERSION)) + .append("&").append(queryParams.get(SIGNED_SERVICES)) + .append("&").append(queryParams.get(SIGNED_RESOURCE_TYPES)) + .append("&").append(queryParams.get(SIGNED_PERMISSIONS)); + + // SIGNED_START is optional + if (queryParams.containsKey(SIGNED_START)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_START)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_EXPIRY)); + + // SIGNED_IP is optional + if (queryParams.containsKey(SIGNED_IP)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_IP)); + } + + // SIGNED_PROTOCOL is optional + if (queryParams.containsKey(SIGNED_PROTOCOL)) { + sasTokenBuilder.append("&").append(queryParams.get(SIGNED_PROTOCOL)); + } + + sasTokenBuilder.append("&").append(queryParams.get(SIGNATURE)); + + return new SASTokenCredential(sasTokenBuilder.toString()); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java new file mode 100644 index 0000000000000..19b2b4c307221 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/SharedKeyCredential.java @@ -0,0 +1,230 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.credentials; + +import com.azure.core.implementation.util.ImplUtils; +import io.netty.handler.codec.http.QueryStringDecoder; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * SharedKey credential policy that is put into a header to authorize requests. + */ +public final class SharedKeyCredential { + private static final String AUTHORIZATION_HEADER_FORMAT = "SharedKey %s:%s"; + + // Pieces of the connection string that are needed. + private static final String ACCOUNT_NAME = "AccountName".toLowerCase(); + private static final String ACCOUNT_KEY = "AccountKey".toLowerCase(); + + private final String accountName; + private final byte[] accountKey; + + /** + * Initializes a new instance of SharedKeyCredential contains an account's name and its primary or secondary + * accountKey. + * + * @param accountName The account name associated with the request. + * @param accountKey The account access key used to authenticate the request. + */ + public SharedKeyCredential(String accountName, String accountKey) { + Objects.requireNonNull(accountName); + Objects.requireNonNull(accountKey); + this.accountName = accountName; + this.accountKey = Base64.getDecoder().decode(accountKey); + } + + /** + * Creates a SharedKey credential from the passed connection string. + * @param connectionString Connection string used to build the SharedKey credential. + * @return a SharedKey credential if the connection string contains AccountName and AccountKey + * @throws IllegalArgumentException If {@code connectionString} doesn't have AccountName or AccountKey. + */ + public static SharedKeyCredential fromConnectionString(String connectionString) { + HashMap connectionStringPieces = new HashMap<>(); + for (String connectionStringPiece : connectionString.split(";")) { + String[] kvp = connectionStringPiece.split("=", 2); + connectionStringPieces.put(kvp[0].toLowerCase(), kvp[1]); + } + + String accountName = connectionStringPieces.get(ACCOUNT_NAME); + String accountKey = connectionStringPieces.get(ACCOUNT_KEY); + + if (ImplUtils.isNullOrEmpty(accountName) || ImplUtils.isNullOrEmpty(accountKey)) { + throw new IllegalArgumentException("Connection string must contain 'AccountName' and 'AccountKey'."); + } + + return new SharedKeyCredential(accountName, accountKey); + } + + /** + * Gets the account name associated with the request. + * + * @return The account name. + */ + public String accountName() { + return accountName; + } + + /** + * Generates the SharedKey Authorization value from information in the request. + * @param requestURL URL of the request + * @param httpMethod HTTP method being used + * @param headers Headers on the request + * @return the SharedKey authorization value + */ + public String generateAuthorizationHeader(URL requestURL, String httpMethod, Map headers) { + return computeHMACSHA256(buildStringToSign(requestURL, httpMethod, headers)); + } + + /** + * Computes a signature for the specified string using the HMAC-SHA256 algorithm. + * Package-private because it is used to generate SAS signatures. + * + * @param stringToSign The UTF-8-encoded string to sign. + * @return A {@code String} that contains the HMAC-SHA256-encoded signature. + * @throws InvalidKeyException If the accountKey is not a valid Base64-encoded string. + */ + public String computeHmac256(final String stringToSign) throws InvalidKeyException { + try { + /* + We must get a new instance of the Mac calculator for each signature calculated because the instances are + not threadsafe and there is some suggestion online that they may not even be safe for reuse, so we use a + new one each time to be sure. + */ + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(this.accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + return Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + } catch (final NoSuchAlgorithmException e) { + throw new Error(e); + } + } + + private String buildStringToSign(URL requestURL, String httpMethod, Map headers) { + String contentLength = headers.get("Content-Length"); + contentLength = contentLength.equals("0") ? "" : contentLength; + + // If the x-ms-header exists ignore the Date header + String dateHeader = (headers.containsKey("x-ms-date")) ? "" : getStandardHeaderValue(headers,"Date"); + + return String.join("\n", + httpMethod, + getStandardHeaderValue(headers,"Content-Encoding"), + getStandardHeaderValue(headers,"Content-Language"), + contentLength, + getStandardHeaderValue(headers,"Content-MD5"), + getStandardHeaderValue(headers,"Content-Type"), + dateHeader, + getStandardHeaderValue(headers,"If-Modified-Since"), + getStandardHeaderValue(headers,"If-Match"), + getStandardHeaderValue(headers, "If-None-Match"), + getStandardHeaderValue(headers,"If-Unmodified-Since"), + getStandardHeaderValue(headers, "Range"), + getAdditionalXmsHeaders(headers), + getCanonicalizedResource(requestURL)); + } + + /* + * Returns an empty string if the header value is null or empty. + */ + private String getStandardHeaderValue(Map headers, String headerName) { + final String headerValue = headers.get(headerName); + + return headerValue == null ? "" : headerValue; + } + + private String getAdditionalXmsHeaders(Map headers) { + // Add only headers that begin with 'x-ms-' + final List xmsHeaderNameArray = headers.entrySet().stream() + .filter(entry -> entry.getKey().toLowerCase(Locale.ROOT).startsWith("x-ms-")) + .filter(entry -> entry.getValue() != null) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + if (xmsHeaderNameArray.isEmpty()) { + return ""; + } + + Collections.sort(xmsHeaderNameArray); + + final StringBuilder canonicalizedHeaders = new StringBuilder(); + for (final String key : xmsHeaderNameArray) { + if (canonicalizedHeaders.length() > 0) { + canonicalizedHeaders.append('\n'); + } + + canonicalizedHeaders.append(key) + .append(':') + .append(headers.get(key)); + } + + return canonicalizedHeaders.toString(); + } + + private String getCanonicalizedResource(URL requestURL) { + + // Resource path + final StringBuilder canonicalizedResource = new StringBuilder("/"); + canonicalizedResource.append(accountName); + + // Note that AbsolutePath starts with a '/'. + if (requestURL.getPath().length() > 0) { + canonicalizedResource.append(requestURL.getPath()); + } else { + canonicalizedResource.append('/'); + } + + // check for no query params and return + if (requestURL.getQuery() == null) { + return canonicalizedResource.toString(); + } + + // The URL object's query field doesn't include the '?'. The QueryStringDecoder expects it. + QueryStringDecoder queryDecoder = new QueryStringDecoder("?" + requestURL.getQuery()); + Map> queryParams = queryDecoder.parameters(); + + ArrayList queryParamNames = new ArrayList<>(queryParams.keySet()); + Collections.sort(queryParamNames); + + for (String queryParamName : queryParamNames) { + final List queryParamValues = queryParams.get(queryParamName); + Collections.sort(queryParamValues); + String queryParamValuesStr = String.join(",", queryParamValues); + canonicalizedResource.append("\n") + .append(queryParamName.toLowerCase(Locale.ROOT)) + .append(":") + .append(queryParamValuesStr); + } + + // append to main string builder the join of completed params with new line + return canonicalizedResource.toString(); + } + + private String computeHMACSHA256(String stringToSign) { + try { + Mac hmacSha256 = Mac.getInstance("HmacSHA256"); + hmacSha256.init(new SecretKeySpec(accountKey, "HmacSHA256")); + byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8); + String signature = Base64.getEncoder().encodeToString(hmacSha256.doFinal(utf8Bytes)); + return String.format(AUTHORIZATION_HEADER_FORMAT, accountName, signature); + } catch (NoSuchAlgorithmException | InvalidKeyException ex) { + throw new Error(ex); + } + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/credentials/package-info.java b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/package-info.java new file mode 100644 index 0000000000000..b03314b4cc0b0 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/credentials/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains credentials used by Azure Storage services. + */ +package com.azure.storage.common.credentials; diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java new file mode 100644 index 0000000000000..edeaf6484ea6a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryOptions.java @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import java.util.concurrent.TimeUnit; + +/** + * Options for configuring the {@link RequestRetryPolicy}. Please refer to the Factory for more information. Note + * that there is no option for overall operation timeout. This is because Rx object have a timeout field which provides + * this functionality. + */ +public final class RequestRetryOptions { + + private final int maxTries; + private final int tryTimeout; + private final long retryDelayInMs; + private final long maxRetryDelayInMs; + /** + * A {@link RetryPolicyType} telling the pipeline what kind of retry policy to use. + */ + private RetryPolicyType retryPolicyType; + private String secondaryHost; + + /** + * Constructor with default retry values: Exponential backoff, maxTries=4, tryTimeout=30, retryDelayInMs=4000, + * maxRetryDelayInMs=120000, secondaryHost=null. + */ + public RequestRetryOptions() { + this(RetryPolicyType.EXPONENTIAL, null, + null, null, null, null); + } + + /** + * Configures how the {@link com.azure.core.http.HttpPipeline} should retry requests. + * + * @param retryPolicyType + * A {@link RetryPolicyType} specifying the type of retry pattern to use. A value of {@code null} accepts + * the default. + * @param maxTries + * Specifies the maximum number of attempts an operation will be tried before producing an error. A value of + * {@code null} means that you accept our default policy. A value of 1 means 1 try and no retries. + * @param tryTimeout + * Indicates the maximum time allowed for any single try of an HTTP request. A value of {@code null} means + * that you accept our default. NOTE: When transferring large amounts of data, the default TryTimeout will + * probably not be sufficient. You should override this value based on the bandwidth available to the host + * machine and proximity to the Storage service. A good starting point may be something like (60 seconds per + * MB of anticipated-payload-size). + * @param retryDelayInMs + * Specifies the amount of delay to use before retrying an operation. A value of {@code null} means you + * accept the default value. The delay increases (exponentially or linearly) with each retry up to a maximum + * specified by MaxRetryDelay. If you specify {@code null}, then you must also specify {@code null} for + * MaxRetryDelay. + * @param maxRetryDelayInMs + * Specifies the maximum delay allowed before retrying an operation. A value of {@code null} means you + * accept the default value. If you specify {@code null}, then you must also specify {@code null} for + * RetryDelay. + * @param secondaryHost + * If a secondaryHost is specified, retries will be tried against this host. If secondaryHost is + * {@code null} (the default) then operations are not retried against another host. NOTE: Before setting + * this field, make sure you understand the issues around reading stale and potentially-inconsistent data at + * this webpage + * + *

    Sample Code

    + * + *

    For more samples, please see the samples file

    + */ + public RequestRetryOptions(RetryPolicyType retryPolicyType, Integer maxTries, Integer tryTimeout, + Long retryDelayInMs, Long maxRetryDelayInMs, String secondaryHost) { + this.retryPolicyType = retryPolicyType == null ? RetryPolicyType.EXPONENTIAL : retryPolicyType; + if (maxTries != null) { + assertInBounds("maxRetries", maxTries, 1, Integer.MAX_VALUE); + this.maxTries = maxTries; + } else { + this.maxTries = 4; + } + + if (tryTimeout != null) { + assertInBounds("tryTimeout", tryTimeout, 1, Integer.MAX_VALUE); + this.tryTimeout = tryTimeout; + } else { + this.tryTimeout = 60; + } + + if ((retryDelayInMs == null && maxRetryDelayInMs != null) + || (retryDelayInMs != null && maxRetryDelayInMs == null)) { + throw new IllegalArgumentException("Both retryDelay and maxRetryDelay must be null or neither can be null"); + } + + if (retryDelayInMs != null && maxRetryDelayInMs != null) { + assertInBounds("maxRetryDelayInMs", maxRetryDelayInMs, 1, Long.MAX_VALUE); + assertInBounds("retryDelayInMs", retryDelayInMs, 1, maxRetryDelayInMs); + this.maxRetryDelayInMs = maxRetryDelayInMs; + this.retryDelayInMs = retryDelayInMs; + } else { + switch (this.retryPolicyType) { + case EXPONENTIAL: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(4); + break; + case FIXED: + this.retryDelayInMs = TimeUnit.SECONDS.toMillis(30); + break; + default: + throw new IllegalArgumentException("Unrecognize retry policy type."); + } + this.maxRetryDelayInMs = TimeUnit.SECONDS.toMillis(120); + } + + this.secondaryHost = secondaryHost; + } + + int maxTries() { + return this.maxTries; + } + + int tryTimeout() { + return this.tryTimeout; + } + + String secondaryHost() { + return this.secondaryHost; + } + + long retryDelayInMs() { + return retryDelayInMs; + } + + long maxRetryDelayInMs() { + return maxRetryDelayInMs; + } + + /** + * Calculates how long to delay before sending the next request. + * + * @param tryCount + * An {@code int} indicating which try we are on. + * + * @return A {@code long} value of how many milliseconds to delay. + */ + long calculateDelayInMs(int tryCount) { + long delay = 0; + switch (this.retryPolicyType) { + case EXPONENTIAL: + delay = (pow(2L, tryCount - 1) - 1L) * this.retryDelayInMs; + break; + + case FIXED: + delay = this.retryDelayInMs; + break; + default: + throw new IllegalArgumentException("Invalid retry policy type."); + } + + return Math.min(delay, this.maxRetryDelayInMs); + } + + private long pow(long number, int exponent) { + long result = 1; + for (int i = 0; i < exponent; i++) { + result *= number; + } + + return result; + } + + private static void assertInBounds(final String param, final long value, final long min, final long max) { + if (value < min || value > max) { + throw new IllegalArgumentException(String.format("The value of the parameter '%s' should be between %s and %s.", param, min, max)); + } + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java new file mode 100644 index 0000000000000..b862b76928af0 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RequestRetryPolicy.java @@ -0,0 +1,192 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + + +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.http.UrlBuilder; +import io.netty.buffer.ByteBuf; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.time.Duration; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeoutException; + +/** + * This is a request policy in an {@link com.azure.core.http.HttpPipeline} for retrying a given HTTP request. The request + * that is retried will be identical each time it is reissued. Retries will try against a secondary if one is specified + * and the type of operation/error indicates that the secondary can handle the request. Exponential and fixed backoff are + * supported. The policy must only be used directly when creating a custom pipeline. + */ +public final class RequestRetryPolicy implements HttpPipelinePolicy { + private final RequestRetryOptions requestRetryOptions; + + public RequestRetryPolicy(RequestRetryOptions requestRetryOptions) { + this.requestRetryOptions = requestRetryOptions; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + HttpRequest httpRequest = context.httpRequest(); + boolean considerSecondary = (httpRequest.httpMethod().equals(HttpMethod.GET) + || httpRequest.httpMethod().equals(HttpMethod.HEAD)) + && (this.requestRetryOptions.secondaryHost() != null); + + return this.attemptAsync(httpRequest, next, 1, considerSecondary, 1); + } + + /** + * This method actually attempts to send the request and determines if we should attempt again and, if so, how + * long to wait before sending out the next request. + *

    + * Exponential retry algorithm: ((2 ^ attempt) - 1) * delay * random(0.8, 1.2) When to retry: connection failure + * or an HTTP status code of 500 or greater, except 501 and 505 If using a secondary: Odd tries go against + * primary; even tries go against the secondary For a primary wait ((2 ^ primaryTries - 1) * delay * random(0.8, + * 1.2) If secondary gets a 404, don't fail, retry but future retries are only against the primary When retrying + * against a secondary, ignore the retry count and wait (.1 second * random(0.8, 1.2)) + * + * @param httpRequest + * The request to try. + * @param primaryTry + * This indicates how man tries we've attempted against the primary DC. + * @param considerSecondary + * Before each try, we'll select either the primary or secondary URL if appropriate. + * @param attempt + * This indicates the total number of attempts to send the request. + * + * @return A single containing either the successful response or an error that was not retryable because either + * the maxTries was exceeded or retries will not mitigate the issue. + */ + private Mono attemptAsync(final HttpRequest httpRequest, HttpPipelineNextPolicy next, final int primaryTry, + final boolean considerSecondary, + final int attempt) { + + // Determine which endpoint to try. It's primary if there is no secondary or if it is an odd number attempt. + final boolean tryingPrimary = !considerSecondary || (attempt % 2 != 0); + + // Select the correct host and delay. + long delayMs; + if (tryingPrimary) { + // The first attempt returns 0 delay. + delayMs = this.requestRetryOptions.calculateDelayInMs(primaryTry); + } else { + // Delay with some jitter before trying the secondary. + delayMs = (long) ((ThreadLocalRandom.current().nextFloat() / 2 + 0.8) * 1000); // Add jitter + } + + /* + Clone the original request to ensure that each try starts with the original (unmutated) request. We cannot + simply call httpRequest.buffer() because although the body will start emitting from the beginning of the + stream, the buffers that were emitted will have already been consumed (their position set to their limit), + so it is not a true reset. By adding the map function, we ensure that anything which consumes the + ByteBuffers downstream will only actually consume a duplicate so the original is preserved. This only + duplicates the ByteBuffer object, not the underlying data. + */ + Flux bufferedBody = httpRequest.body() == null + ? null : httpRequest.body().map(ByteBuf::duplicate); + httpRequest.body(bufferedBody); + if (!tryingPrimary) { + UrlBuilder builder = UrlBuilder.parse(httpRequest.url()); + builder.host(this.requestRetryOptions.secondaryHost()); + try { + httpRequest.url(builder.toURL()); + } catch (MalformedURLException e) { + return Mono.error(e); + } + } + + /* + We want to send the request with a given timeout, but we don't want to kickoff that timeout-bound operation + until after the retry backoff delay, so we call delaySubscription. + */ + return next.clone().process() + .timeout(Duration.ofSeconds(this.requestRetryOptions.tryTimeout())) + .delaySubscription(Duration.ofMillis(delayMs)) + .flatMap(response -> { + boolean newConsiderSecondary = considerSecondary; + String action; + int statusCode = response.statusCode(); + + /* + If attempt was against the secondary & it returned a StatusNotFound (404), then the + resource was not found. This may be due to replication delay. So, in this case, + we'll never try the secondary again for this operation. + */ + if (!tryingPrimary && statusCode == 404) { + newConsiderSecondary = false; + action = "Retry: Secondary URL returned 404"; + } else if (statusCode == 503 || statusCode == 500) { + action = "Retry: Temporary error or server timeout"; + } else { + action = "NoRetry: Successful HTTP request"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, newConsiderSecondary, + attempt + 1); + } + return Mono.just(response); + }) + .onErrorResume(throwable -> { + /* + It is likely that many users will not realize that their Flux must be replayable and + get an error upon retries when the provided data length does not match the length of the exact + data. We cannot enforce the desired Flux behavior, so we provide a hint when this is likely + the root cause. + */ + if (throwable instanceof IllegalStateException && attempt > 1) { + return Mono.error(new IllegalStateException("The request failed because the " + + "size of the contents of the provided Flux did not match the provided " + + "data size upon attempting to retry. This is likely caused by the Flux " + + "not being replayable. To support retries, all Fluxes must produce the " + + "same data for each subscriber. Please ensure this behavior.", throwable)); + } + + /* + IOException is a catch-all for IO related errors. Technically it includes many types which may + not be network exceptions, but we should not hit those unless there is a bug in our logic. In + either case, it is better to optimistically retry instead of failing too soon. + A Timeout Exception is a client-side timeout coming from Rx. + */ + String action; + if (throwable instanceof IOException) { + action = "Retry: Network error"; + } else if (throwable instanceof TimeoutException) { + action = "Retry: Client timeout"; + } else { + action = "NoRetry: Unknown error"; + } + + if (action.charAt(0) == 'R' && attempt < requestRetryOptions.maxTries()) { + /* + We increment primaryTry if we are about to try the primary again (which is when we + consider the secondary and tried the secondary this time (tryingPrimary==false) or + we do not consider the secondary at all (considerSecondary==false)). This will + ensure primaryTry is correct when passed to calculate the delay. + */ + int newPrimaryTry = !tryingPrimary || !considerSecondary + ? primaryTry + 1 : primaryTry; + return attemptAsync(httpRequest, next, newPrimaryTry, considerSecondary, + attempt + 1); + } + return Mono.error(throwable); + }); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java new file mode 100644 index 0000000000000..bee125775e55d --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/RetryPolicyType.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +/** + * This type holds possible options for retry backoff algorithms. They may be used with {@link RequestRetryOptions}. + */ +public enum RetryPolicyType { + /** + * Tells the pipeline to use an exponential back-off retry policy. + */ + EXPONENTIAL, + + /** + * Tells the pipeline to use a fixed back-off retry policy. + */ + FIXED +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java new file mode 100644 index 0000000000000..ba2debfcd3620 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/SASTokenCredentialPolicy.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.implementation.util.ImplUtils; +import com.azure.storage.common.credentials.SASTokenCredential; +import reactor.core.publisher.Mono; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Policy that adds the SAS token to the request URL's query. + */ +public final class SASTokenCredentialPolicy implements HttpPipelinePolicy { + private final SASTokenCredential credential; + + /** + * Creates a SAS token credential policy that appends the SAS token to the request URL's query. + * @param credential SAS token credential + */ + public SASTokenCredentialPolicy(SASTokenCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + try { + URL requestURL = context.httpRequest().url(); + String delimiter = !ImplUtils.isNullOrEmpty(requestURL.getQuery()) ? "&" : "?"; + + String newURL = requestURL.toString() + delimiter + credential.sasToken(); + context.httpRequest().url(new URL(newURL)); + } catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + + return next.process(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java new file mode 100644 index 0000000000000..8ee1284591dd2 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/SharedKeyCredentialPolicy.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.policy; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.storage.common.credentials.SharedKeyCredential; +import reactor.core.publisher.Mono; + +/** + * Policy that adds the SharedKey into the request's Authorization header. + */ +public final class SharedKeyCredentialPolicy implements HttpPipelinePolicy { + private final SharedKeyCredential credential; + + /** + * Creates a SharedKey pipeline policy that adds the SharedKey into the request's authorization header. + * @param credential the SharedKey credential used to create the policy. + */ + public SharedKeyCredentialPolicy(SharedKeyCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + String authorizationValue = credential.generateAuthorizationHeader(context.httpRequest().url(), + context.httpRequest().httpMethod().toString(), + context.httpRequest().headers().toMap()); + context.httpRequest().header("Authorization", authorizationValue); + return next.process(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/common/policy/package-info.java b/storage/client/queue/src/main/java/com/azure/storage/common/policy/package-info.java new file mode 100644 index 0000000000000..6f36065ea580b --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/common/policy/package-info.java @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** + * This package contains policies used by Azure Storage services. + */ +package com.azure.storage.common.policy; diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java new file mode 100644 index 0000000000000..eab2a19707d5c --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClient.java @@ -0,0 +1,29 @@ +package com.azure.storage.queue; + +import com.azure.core.ServiceClient; +import com.azure.core.http.HttpPipeline; +import com.azure.storage.queue.implementation.AzureQueueStorageBuilder; +import com.azure.storage.queue.implementation.AzureQueueStorageImpl; + +import java.net.URL; + +public class QueueAsyncClient extends ServiceClient { + private final String endpoint; + private final AzureQueueStorageImpl generateClient; + private final String apiVersion; + + private QueueAsyncClient(URL endpoint, HttpPipeline httpPipeline) { + super(httpPipeline); + this.endpoint = endpoint.toString(); + this.generateClient = new AzureQueueStorageBuilder().pipeline(httpPipeline).url(this.endpoint).build(); + this.apiVersion = this.generateClient.version(); + } + + /** + * Creates a appendBlobClientBuilder that can configure options for the SecretAsyncClient before creating an instance of it. + * @return A new appendBlobClientBuilder to create a SecretAsyncClient from. + */ + public static QueueAsyncClientBuilder builder() { + return new QueueAsyncClientBuilder(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java new file mode 100644 index 0000000000000..b76c9c63e8700 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/QueueAsyncClientBuilder.java @@ -0,0 +1,5 @@ +package com.azure.storage.queue; + +public class QueueAsyncClientBuilder { + +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java new file mode 100644 index 0000000000000..4f678dfe10832 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageBuilder.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * A appendBlobClientBuilder for creating a new instance of the AzureQueueStorage type. + */ +public final class AzureQueueStorageBuilder { + /* + * The URL of the service account, queue or message that is the targe of the desired operation. + */ + private String url; + + /** + * Sets The URL of the service account, queue or message that is the targe of the desired operation. + * + * @param url the url value. + * @return the AzureQueueStorageBuilder. + */ + public AzureQueueStorageBuilder url(String url) { + this.url = url; + return this; + } + + /* + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the AzureQueueStorageBuilder. + */ + public AzureQueueStorageBuilder version(String version) { + this.version = version; + return this; + } + + /* + * The HTTP pipeline to send requests through + */ + private HttpPipeline pipeline; + + /** + * Sets The HTTP pipeline to send requests through. + * + * @param pipeline the pipeline value. + * @return the AzureQueueStorageBuilder. + */ + public AzureQueueStorageBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + /** + * Builds an instance of AzureQueueStorageImpl with the provided parameters. + * + * @return an instance of AzureQueueStorageImpl. + */ + public AzureQueueStorageImpl build() { + if (version == null) { + this.version = "2018-03-28"; + } + if (pipeline == null) { + this.pipeline = RestProxy.createDefaultPipeline(); + } + AzureQueueStorageImpl client = new AzureQueueStorageImpl(pipeline); + if (this.url != null) { + client.url(this.url); + } + if (this.version != null) { + client.version(this.version); + } + return client; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageImpl.java new file mode 100644 index 0000000000000..1573b9c7e05bd --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/AzureQueueStorageImpl.java @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.ServiceClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.implementation.RestProxy; + +/** + * Initializes a new instance of the AzureQueueStorage type. + */ +public final class AzureQueueStorageImpl extends ServiceClient { + /** + * The URL of the service account, queue or message that is the targe of the desired operation. + */ + private String url; + + /** + * Gets The URL of the service account, queue or message that is the targe of the desired operation. + * + * @return the url value. + */ + public String url() { + return this.url; + } + + /** + * Sets The URL of the service account, queue or message that is the targe of the desired operation. + * + * @param url the url value. + * @return the service client itself. + */ + AzureQueueStorageImpl url(String url) { + this.url = url; + return this; + } + + /** + * Specifies the version of the operation to use for this request. + */ + private String version; + + /** + * Gets Specifies the version of the operation to use for this request. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Sets Specifies the version of the operation to use for this request. + * + * @param version the version value. + * @return the service client itself. + */ + AzureQueueStorageImpl version(String version) { + this.version = version; + return this; + } + + /** + * The ServicesImpl object to access its operations. + */ + private ServicesImpl services; + + /** + * Gets the ServicesImpl object to access its operations. + * + * @return the ServicesImpl object. + */ + public ServicesImpl services() { + return this.services; + } + + /** + * The QueuesImpl object to access its operations. + */ + private QueuesImpl queues; + + /** + * Gets the QueuesImpl object to access its operations. + * + * @return the QueuesImpl object. + */ + public QueuesImpl queues() { + return this.queues; + } + + /** + * The MessagesImpl object to access its operations. + */ + private MessagesImpl messages; + + /** + * Gets the MessagesImpl object to access its operations. + * + * @return the MessagesImpl object. + */ + public MessagesImpl messages() { + return this.messages; + } + + /** + * The MessageIdsImpl object to access its operations. + */ + private MessageIdsImpl messageIds; + + /** + * Gets the MessageIdsImpl object to access its operations. + * + * @return the MessageIdsImpl object. + */ + public MessageIdsImpl messageIds() { + return this.messageIds; + } + + /** + * Initializes an instance of AzureQueueStorage client. + */ + public AzureQueueStorageImpl() { + this(RestProxy.createDefaultPipeline()); + } + + /** + * Initializes an instance of AzureQueueStorage client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + */ + public AzureQueueStorageImpl(HttpPipeline httpPipeline) { + super(httpPipeline); + this.services = new ServicesImpl(this); + this.queues = new QueuesImpl(this); + this.messages = new MessagesImpl(this); + this.messageIds = new MessageIdsImpl(this); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ListQueuesIncludeTypeWrapper.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ListQueuesIncludeTypeWrapper.java new file mode 100644 index 0000000000000..661e1de266a2d --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ListQueuesIncludeTypeWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.storage.queue.models.ListQueuesIncludeType; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<ListQueuesIncludeType> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "ListQueuesIncludeType") +public final class ListQueuesIncludeTypeWrapper { + @JacksonXmlProperty(localName = "ListQueuesIncludeType") + private final List listQueuesIncludeType; + + /** + * Creates an instance of ListQueuesIncludeTypeWrapper. + * + * @param listQueuesIncludeType the list. + */ + @JsonCreator + public ListQueuesIncludeTypeWrapper(@JsonProperty("ListQueuesIncludeType") List listQueuesIncludeType) { + this.listQueuesIncludeType = listQueuesIncludeType; + } + + /** + * Get the List<ListQueuesIncludeType> contained in this wrapper. + * + * @return the List<ListQueuesIncludeType>. + */ + public List items() { + return listQueuesIncludeType; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java new file mode 100644 index 0000000000000..8a705fe7e4af7 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessageIdsImpl.java @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.queue.models.MessageIdsDeleteResponse; +import com.azure.storage.queue.models.MessageIdsUpdateResponse; +import com.azure.storage.queue.models.QueueMessage; +import com.azure.storage.queue.models.StorageErrorException; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in + * MessageIds. + */ +public final class MessageIdsImpl { + /** + * The proxy service used to perform REST calls. + */ + private MessageIdsService service; + + /** + * The service client containing this operation class. + */ + private AzureQueueStorageImpl client; + + /** + * Initializes an instance of MessageIdsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public MessageIdsImpl(AzureQueueStorageImpl client) { + this.service = RestProxy.create(MessageIdsService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for MessageIds to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Queues MessageId") + private interface MessageIdsService { + @PUT("{queueName}/messages/{messageid}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono update(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("popreceipt") String popReceipt, @QueryParam("visibilitytimeout") int visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @DELETE("{queueName}/messages/{messageid}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@HostParam("url") String url, @QueryParam("popreceipt") String popReceipt, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + } + + /** + * The Update operation was introduced with version 2011-08-18 of the Queue service API. The Update Message operation updates the visibility timeout of a message. You can also use this operation to update the contents of a message. A message must be in a format that can be included in an XML request with UTF-8 encoding, and the encoded message can be up to 64KB in size. + * + * @param queueMessage A Message object which can be stored in a Queue. + * @param popReceipt Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update Message operation. + * @param visibilitytimeout Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value is 30 seconds. A specified value must be larger than or equal to 1 second, and cannot be larger than 7 days, or larger than 2 hours on REST protocol versions prior to version 2011-08-18. The visibility timeout of a message can be set to a value later than the expiry time. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono updateWithRestResponseAsync(QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Context context) { + final Integer timeout = null; + final String requestId = null; + return service.update(this.client.url(), queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); + } + + /** + * The Update operation was introduced with version 2011-08-18 of the Queue service API. The Update Message operation updates the visibility timeout of a message. You can also use this operation to update the contents of a message. A message must be in a format that can be included in an XML request with UTF-8 encoding, and the encoded message can be up to 64KB in size. + * + * @param queueMessage A Message object which can be stored in a Queue. + * @param popReceipt Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update Message operation. + * @param visibilitytimeout Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value is 30 seconds. A specified value must be larger than or equal to 1 second, and cannot be larger than 7 days, or larger than 2 hours on REST protocol versions prior to version 2011-08-18. The visibility timeout of a message can be set to a value later than the expiry time. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono updateWithRestResponseAsync(QueueMessage queueMessage, String popReceipt, int visibilitytimeout, Integer timeout, String requestId, Context context) { + return service.update(this.client.url(), queueMessage, popReceipt, visibilitytimeout, timeout, this.client.version(), requestId, context); + } + + /** + * The Delete operation deletes the specified message. + * + * @param popReceipt Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update Message operation. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String popReceipt, Context context) { + final Integer timeout = null; + final String requestId = null; + return service.delete(this.client.url(), popReceipt, timeout, this.client.version(), requestId, context); + } + + /** + * The Delete operation deletes the specified message. + * + * @param popReceipt Required. Specifies the valid pop receipt value returned from an earlier call to the Get Messages or Update Message operation. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(String popReceipt, Integer timeout, String requestId, Context context) { + return service.delete(this.client.url(), popReceipt, timeout, this.client.version(), requestId, context); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java new file mode 100644 index 0000000000000..ee59aae16b63f --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/MessagesImpl.java @@ -0,0 +1,198 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.POST; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.queue.models.MessagesClearResponse; +import com.azure.storage.queue.models.MessagesDequeueResponse; +import com.azure.storage.queue.models.MessagesEnqueueResponse; +import com.azure.storage.queue.models.MessagesPeekResponse; +import com.azure.storage.queue.models.QueueMessage; +import com.azure.storage.queue.models.StorageErrorException; +import reactor.core.publisher.Mono; + +/** + * An instance of this class provides access to all the operations defined in + * Messages. + */ +public final class MessagesImpl { + /** + * The proxy service used to perform REST calls. + */ + private MessagesService service; + + /** + * The service client containing this operation class. + */ + private AzureQueueStorageImpl client; + + /** + * Initializes an instance of MessagesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public MessagesImpl(AzureQueueStorageImpl client) { + this.service = RestProxy.create(MessagesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Messages to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Queues Messages") + private interface MessagesService { + @GET("{queueName}/messages") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono dequeue(@HostParam("url") String url, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @DELETE("{queueName}/messages") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono clear(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @POST("{queueName}/messages") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono enqueue(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") QueueMessage queueMessage, @QueryParam("visibilitytimeout") Integer visibilitytimeout, @QueryParam("messagettl") Integer messageTimeToLive, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @GET("{queueName}/messages") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono peek(@HostParam("url") String url, @QueryParam("numofmessages") Integer numberOfMessages, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("peekonly") String peekonly, Context context); + } + + /** + * The Dequeue operation retrieves one or more messages from the front of the queue. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono dequeueWithRestResponseAsync(Context context) { + final Integer numberOfMessages = null; + final Integer visibilitytimeout = null; + final Integer timeout = null; + final String requestId = null; + return service.dequeue(this.client.url(), numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); + } + + /** + * The Dequeue operation retrieves one or more messages from the front of the queue. + * + * @param numberOfMessages Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the queue with this operation. + * @param visibilitytimeout Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value is 30 seconds. A specified value must be larger than or equal to 1 second, and cannot be larger than 7 days, or larger than 2 hours on REST protocol versions prior to version 2011-08-18. The visibility timeout of a message can be set to a value later than the expiry time. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono dequeueWithRestResponseAsync(Integer numberOfMessages, Integer visibilitytimeout, Integer timeout, String requestId, Context context) { + return service.dequeue(this.client.url(), numberOfMessages, visibilitytimeout, timeout, this.client.version(), requestId, context); + } + + /** + * The Clear operation deletes all messages from the specified queue. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono clearWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + return service.clear(this.client.url(), timeout, this.client.version(), requestId, context); + } + + /** + * The Clear operation deletes all messages from the specified queue. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono clearWithRestResponseAsync(Integer timeout, String requestId, Context context) { + return service.clear(this.client.url(), timeout, this.client.version(), requestId, context); + } + + /** + * The Enqueue operation adds a new message to the back of the message queue. A visibility timeout can also be specified to make the message invisible until the visibility timeout expires. A message must be in a format that can be included in an XML request with UTF-8 encoding. The encoded message can be up to 64 KB in size for versions 2011-08-18 and newer, or 8 KB in size for previous versions. + * + * @param queueMessage A Message object which can be stored in a Queue. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono enqueueWithRestResponseAsync(QueueMessage queueMessage, Context context) { + final Integer visibilitytimeout = null; + final Integer messageTimeToLive = null; + final Integer timeout = null; + final String requestId = null; + return service.enqueue(this.client.url(), queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); + } + + /** + * The Enqueue operation adds a new message to the back of the message queue. A visibility timeout can also be specified to make the message invisible until the visibility timeout expires. A message must be in a format that can be included in an XML request with UTF-8 encoding. The encoded message can be up to 64 KB in size for versions 2011-08-18 and newer, or 8 KB in size for previous versions. + * + * @param queueMessage A Message object which can be stored in a Queue. + * @param visibilitytimeout Optional. Specifies the new visibility timeout value, in seconds, relative to server time. The default value is 30 seconds. A specified value must be larger than or equal to 1 second, and cannot be larger than 7 days, or larger than 2 hours on REST protocol versions prior to version 2011-08-18. The visibility timeout of a message can be set to a value later than the expiry time. + * @param messageTimeToLive Optional. Specifies the time-to-live interval for the message, in seconds. Prior to version 2017-07-29, the maximum time-to-live allowed is 7 days. For version 2017-07-29 or later, the maximum time-to-live can be any positive number, as well as -1 indicating that the message does not expire. If this parameter is omitted, the default time-to-live is 7 days. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono enqueueWithRestResponseAsync(QueueMessage queueMessage, Integer visibilitytimeout, Integer messageTimeToLive, Integer timeout, String requestId, Context context) { + return service.enqueue(this.client.url(), queueMessage, visibilitytimeout, messageTimeToLive, timeout, this.client.version(), requestId, context); + } + + /** + * The Peek operation retrieves one or more messages from the front of the queue, but does not alter the visibility of the message. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono peekWithRestResponseAsync(Context context) { + final Integer numberOfMessages = null; + final Integer timeout = null; + final String requestId = null; + final String peekonly = "true"; + return service.peek(this.client.url(), numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); + } + + /** + * The Peek operation retrieves one or more messages from the front of the queue, but does not alter the visibility of the message. + * + * @param numberOfMessages Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the queue with this operation. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono peekWithRestResponseAsync(Integer numberOfMessages, Integer timeout, String requestId, Context context) { + final String peekonly = "true"; + return service.peek(this.client.url(), numberOfMessages, timeout, this.client.version(), requestId, peekonly, context); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java new file mode 100644 index 0000000000000..2eb2d4d1ec2e2 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/QueuesImpl.java @@ -0,0 +1,266 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.DELETE; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.RestProxy; +import com.azure.core.util.Context; +import com.azure.storage.queue.models.QueuesCreateResponse; +import com.azure.storage.queue.models.QueuesDeleteResponse; +import com.azure.storage.queue.models.QueuesGetAccessPolicyResponse; +import com.azure.storage.queue.models.QueuesGetPropertiesResponse; +import com.azure.storage.queue.models.QueuesSetAccessPolicyResponse; +import com.azure.storage.queue.models.QueuesSetMetadataResponse; +import com.azure.storage.queue.models.SignedIdentifier; +import com.azure.storage.queue.models.StorageErrorException; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; + +/** + * An instance of this class provides access to all the operations defined in + * Queues. + */ +public final class QueuesImpl { + /** + * The proxy service used to perform REST calls. + */ + private QueuesService service; + + /** + * The service client containing this operation class. + */ + private AzureQueueStorageImpl client; + + /** + * Initializes an instance of QueuesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public QueuesImpl(AzureQueueStorageImpl client) { + this.service = RestProxy.create(QueuesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Queues to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Queues Queue") + private interface QueuesService { + @PUT("{queueName}") + @ExpectedResponses({201, 204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono create(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @DELETE("{queueName}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono delete(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, Context context); + + @GET("{queueName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + + @PUT("{queueName}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setMetadata(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-meta-") Map metadata, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + + @GET("{queueName}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getAccessPolicy(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + + @PUT("{queueName}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setAccessPolicy(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") SignedIdentifiersWrapper queueAcl, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + } + + /** + * creates a new queue under the given account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String requestId = null; + return service.create(this.client.url(), timeout, metadata, this.client.version(), requestId, context); + } + + /** + * creates a new queue under the given account. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param metadata Optional. Include this parameter to specify that the queue's metadata be returned as part of the response body. Note that metadata requested with this parameter must be stored in accordance with the naming restrictions imposed by the 2009-09-19 version of the Queue service. Beginning with this version, all metadata names must adhere to the naming conventions for C# identifiers. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono createWithRestResponseAsync(Integer timeout, Map metadata, String requestId, Context context) { + return service.create(this.client.url(), timeout, metadata, this.client.version(), requestId, context); + } + + /** + * operation permanently deletes the specified queue. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + return service.delete(this.client.url(), timeout, this.client.version(), requestId, context); + } + + /** + * operation permanently deletes the specified queue. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono deleteWithRestResponseAsync(Integer timeout, String requestId, Context context) { + return service.delete(this.client.url(), timeout, this.client.version(), requestId, context); + } + + /** + * Retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "metadata"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * Retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String comp = "metadata"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Context context) { + final Integer timeout = null; + final Map metadata = null; + final String requestId = null; + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), requestId, comp, context); + } + + /** + * sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param metadata Optional. Include this parameter to specify that the queue's metadata be returned as part of the response body. Note that metadata requested with this parameter must be stored in accordance with the naming restrictions imposed by the 2009-09-19 version of the Queue service. Beginning with this version, all metadata names must adhere to the naming conventions for C# identifiers. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setMetadataWithRestResponseAsync(Integer timeout, Map metadata, String requestId, Context context) { + final String comp = "metadata"; + return service.setMetadata(this.client.url(), timeout, metadata, this.client.version(), requestId, comp, context); + } + + /** + * returns details about any stored access policies specified on the queue that may be used with Shared Access Signatures. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "acl"; + return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * returns details about any stored access policies specified on the queue that may be used with Shared Access Signatures. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getAccessPolicyWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String comp = "acl"; + return service.getAccessPolicy(this.client.url(), timeout, this.client.version(), requestId, comp, context); + } + + /** + * sets stored access policies for the queue that may be used with Shared Access Signatures. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String comp = "acl"; + SignedIdentifiersWrapper queueAclConverted = new SignedIdentifiersWrapper(null); + return service.setAccessPolicy(this.client.url(), queueAclConverted, timeout, this.client.version(), requestId, comp, context); + } + + /** + * sets stored access policies for the queue that may be used with Shared Access Signatures. + * + * @param queueAcl the acls for the queue. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setAccessPolicyWithRestResponseAsync(List queueAcl, Integer timeout, String requestId, Context context) { + final String comp = "acl"; + SignedIdentifiersWrapper queueAclConverted = new SignedIdentifiersWrapper(queueAcl); + return service.setAccessPolicy(this.client.url(), queueAclConverted, timeout, this.client.version(), requestId, comp, context); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java new file mode 100644 index 0000000000000..dc353d45f5243 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/ServicesImpl.java @@ -0,0 +1,213 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.core.annotations.BodyParam; +import com.azure.core.annotations.ExpectedResponses; +import com.azure.core.annotations.GET; +import com.azure.core.annotations.HeaderParam; +import com.azure.core.annotations.Host; +import com.azure.core.annotations.HostParam; +import com.azure.core.annotations.PUT; +import com.azure.core.annotations.QueryParam; +import com.azure.core.annotations.Service; +import com.azure.core.annotations.UnexpectedResponseExceptionType; +import com.azure.core.implementation.CollectionFormat; +import com.azure.core.implementation.RestProxy; +import com.azure.core.implementation.serializer.jackson.JacksonAdapter; +import com.azure.core.util.Context; +import com.azure.storage.queue.models.ListQueuesIncludeType; +import com.azure.storage.queue.models.ServicesGetPropertiesResponse; +import com.azure.storage.queue.models.ServicesGetStatisticsResponse; +import com.azure.storage.queue.models.ServicesListQueuesSegmentResponse; +import com.azure.storage.queue.models.ServicesSetPropertiesResponse; +import com.azure.storage.queue.models.StorageErrorException; +import com.azure.storage.queue.models.StorageServiceProperties; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * An instance of this class provides access to all the operations defined in + * Services. + */ +public final class ServicesImpl { + /** + * The proxy service used to perform REST calls. + */ + private ServicesService service; + + /** + * The service client containing this operation class. + */ + private AzureQueueStorageImpl client; + + /** + * Initializes an instance of ServicesImpl. + * + * @param client the instance of the service client containing this operation class. + */ + public ServicesImpl(AzureQueueStorageImpl client) { + this.service = RestProxy.create(ServicesService.class, client); + this.client = client; + } + + /** + * The interface defining all the services for Services to be used by the + * proxy service to perform REST calls. + */ + @Host("{url}") + @Service("Storage Queues Services") + private interface ServicesService { + @PUT("") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono setProperties(@HostParam("url") String url, @BodyParam("application/xml; charset=utf-8") StorageServiceProperties storageServiceProperties, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getProperties(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono getStatistics(@HostParam("url") String url, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("restype") String restype, @QueryParam("comp") String comp, Context context); + + @GET("") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(StorageErrorException.class) + Mono listQueuesSegment(@HostParam("url") String url, @QueryParam("prefix") String prefix, @QueryParam("marker") String marker, @QueryParam("maxresults") Integer maxresults, @QueryParam("include") String include, @QueryParam("timeout") Integer timeout, @HeaderParam("x-ms-version") String version, @HeaderParam("x-ms-client-request-id") String requestId, @QueryParam("comp") String comp, Context context); + } + + /** + * Sets properties for a storage account's Queue service endpoint, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Sets properties for a storage account's Queue service endpoint, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param storageServiceProperties The StorageService properties. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono setPropertiesWithRestResponseAsync(StorageServiceProperties storageServiceProperties, Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.setProperties(this.client.url(), storageServiceProperties, timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * gets the properties of a storage account's Queue service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * gets the properties of a storage account's Queue service, including properties for Storage Analytics and CORS (Cross-Origin Resource Sharing) rules. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getPropertiesWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "properties"; + return service.getProperties(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Retrieves statistics related to replication for the Queue service. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Context context) { + final Integer timeout = null; + final String requestId = null; + final String restype = "service"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * Retrieves statistics related to replication for the Queue service. It is only available on the secondary location endpoint when read-access geo-redundant replication is enabled for the storage account. + * + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono getStatisticsWithRestResponseAsync(Integer timeout, String requestId, Context context) { + final String restype = "service"; + final String comp = "stats"; + return service.getStatistics(this.client.url(), timeout, this.client.version(), requestId, restype, comp, context); + } + + /** + * The List Queues Segment operation returns a list of the queues under the specified account. + * + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listQueuesSegmentWithRestResponseAsync(Context context) { + final String prefix = null; + final String marker = null; + final Integer maxresults = null; + final Integer timeout = null; + final String requestId = null; + final String comp = "list"; + String includeConverted = null; + return service.listQueuesSegment(this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, comp, context); + } + + /** + * The List Queues Segment operation returns a list of the queues under the specified account. + * + * @param prefix Filters the results to return only queues whose name begins with the specified prefix. + * @param marker A string value that identifies the portion of the list of queues to be returned with the next listing operation. The operation returns the NextMarker value within the response body if the listing operation did not return all queues remaining to be listed with the current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request the next page of list items. The marker value is opaque to the client. + * @param maxresults Specifies the maximum number of queues to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the service will return fewer results than specified by maxresults, or than the default of 5000. + * @param include Include this parameter to specify that the queues's metadata be returned as part of the response body. + * @param timeout The The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/setting-timeouts-for-queue-service-operations>Setting Timeouts for Queue Service Operations.</a>. + * @param requestId Provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @return a Mono which performs the network request upon subscription. + */ + public Mono listQueuesSegmentWithRestResponseAsync(String prefix, String marker, Integer maxresults, List include, Integer timeout, String requestId, Context context) { + final String comp = "list"; + String includeConverted = JacksonAdapter.createDefaultSerializerAdapter().serializeList(include, CollectionFormat.CSV); + return service.listQueuesSegment(this.client.url(), prefix, marker, maxresults, includeConverted, timeout, this.client.version(), requestId, comp, context); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/SignedIdentifiersWrapper.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/SignedIdentifiersWrapper.java new file mode 100644 index 0000000000000..092e242ac8b8a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/SignedIdentifiersWrapper.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.implementation; + +import com.azure.storage.queue.models.SignedIdentifier; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.List; + +/** + * A wrapper around List<SignedIdentifier> which provides top-level metadata for serialization. + */ +@JacksonXmlRootElement(localName = "SignedIdentifiers") +public final class SignedIdentifiersWrapper { + @JacksonXmlProperty(localName = "SignedIdentifier") + private final List signedIdentifiers; + + /** + * Creates an instance of SignedIdentifiersWrapper. + * + * @param signedIdentifiers the list. + */ + @JsonCreator + public SignedIdentifiersWrapper(@JsonProperty("SignedIdentifier") List signedIdentifiers) { + this.signedIdentifiers = signedIdentifiers; + } + + /** + * Get the List<SignedIdentifier> contained in this wrapper. + * + * @return the List<SignedIdentifier>. + */ + public List items() { + return signedIdentifiers; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/package-info.java b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/package-info.java new file mode 100644 index 0000000000000..80e51df7f9675 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/implementation/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the implementations and inner classes for + * AzureQueueStorage. + */ +package com.azure.storage.queue.implementation; diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/AccessPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/AccessPolicy.java new file mode 100644 index 0000000000000..e2a86de1dcbcd --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/AccessPolicy.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * An Access policy. + */ +@JacksonXmlRootElement(localName = "AccessPolicy") +public final class AccessPolicy { + /* + * the date-time the policy is active + */ + @JsonProperty(value = "Start", required = true) + private OffsetDateTime start; + + /* + * the date-time the policy expires + */ + @JsonProperty(value = "Expiry", required = true) + private OffsetDateTime expiry; + + /* + * the permissions for the acl policy + */ + @JsonProperty(value = "Permission", required = true) + private String permission; + + /** + * Get the start property: the date-time the policy is active. + * + * @return the start value. + */ + public OffsetDateTime start() { + return this.start; + } + + /** + * Set the start property: the date-time the policy is active. + * + * @param start the start value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy start(OffsetDateTime start) { + this.start = start; + return this; + } + + /** + * Get the expiry property: the date-time the policy expires. + * + * @return the expiry value. + */ + public OffsetDateTime expiry() { + return this.expiry; + } + + /** + * Set the expiry property: the date-time the policy expires. + * + * @param expiry the expiry value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy expiry(OffsetDateTime expiry) { + this.expiry = expiry; + return this; + } + + /** + * Get the permission property: the permissions for the acl policy. + * + * @return the permission value. + */ + public String permission() { + return this.permission; + } + + /** + * Set the permission property: the permissions for the acl policy. + * + * @param permission the permission value to set. + * @return the AccessPolicy object itself. + */ + public AccessPolicy permission(String permission) { + this.permission = permission; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/CorsRule.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/CorsRule.java new file mode 100644 index 0000000000000..e5836439cdf3e --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/CorsRule.java @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * CORS is an HTTP feature that enables a web application running under one + * domain to access resources in another domain. Web browsers implement a + * security restriction known as same-origin policy that prevents a web page + * from calling APIs in a different domain; CORS provides a secure way to allow + * one domain (the origin domain) to call APIs in another domain. + */ +@JacksonXmlRootElement(localName = "CorsRule") +public final class CorsRule { + /* + * The origin domains that are permitted to make a request against the + * storage service via CORS. The origin domain is the domain from which the + * request originates. Note that the origin must be an exact case-sensitive + * match with the origin that the user age sends to the service. You can + * also use the wildcard character '*' to allow all origin domains to make + * requests via CORS. + */ + @JsonProperty(value = "AllowedOrigins", required = true) + private String allowedOrigins; + + /* + * The methods (HTTP request verbs) that the origin domain may use for a + * CORS request. (comma separated) + */ + @JsonProperty(value = "AllowedMethods", required = true) + private String allowedMethods; + + /* + * the request headers that the origin domain may specify on the CORS + * request. + */ + @JsonProperty(value = "AllowedHeaders", required = true) + private String allowedHeaders; + + /* + * The response headers that may be sent in the response to the CORS + * request and exposed by the browser to the request issuer + */ + @JsonProperty(value = "ExposedHeaders", required = true) + private String exposedHeaders; + + /* + * The maximum amount time that a browser should cache the preflight + * OPTIONS request. + */ + @JsonProperty(value = "MaxAgeInSeconds", required = true) + private int maxAgeInSeconds; + + /** + * Get the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @return the allowedOrigins value. + */ + public String allowedOrigins() { + return this.allowedOrigins; + } + + /** + * Set the allowedOrigins property: The origin domains that are permitted + * to make a request against the storage service via CORS. The origin + * domain is the domain from which the request originates. Note that the + * origin must be an exact case-sensitive match with the origin that the + * user age sends to the service. You can also use the wildcard character + * '*' to allow all origin domains to make requests via CORS. + * + * @param allowedOrigins the allowedOrigins value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedOrigins(String allowedOrigins) { + this.allowedOrigins = allowedOrigins; + return this; + } + + /** + * Get the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @return the allowedMethods value. + */ + public String allowedMethods() { + return this.allowedMethods; + } + + /** + * Set the allowedMethods property: The methods (HTTP request verbs) that + * the origin domain may use for a CORS request. (comma separated). + * + * @param allowedMethods the allowedMethods value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedMethods(String allowedMethods) { + this.allowedMethods = allowedMethods; + return this; + } + + /** + * Get the allowedHeaders property: the request headers that the origin + * domain may specify on the CORS request. + * + * @return the allowedHeaders value. + */ + public String allowedHeaders() { + return this.allowedHeaders; + } + + /** + * Set the allowedHeaders property: the request headers that the origin + * domain may specify on the CORS request. + * + * @param allowedHeaders the allowedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule allowedHeaders(String allowedHeaders) { + this.allowedHeaders = allowedHeaders; + return this; + } + + /** + * Get the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @return the exposedHeaders value. + */ + public String exposedHeaders() { + return this.exposedHeaders; + } + + /** + * Set the exposedHeaders property: The response headers that may be sent + * in the response to the CORS request and exposed by the browser to the + * request issuer. + * + * @param exposedHeaders the exposedHeaders value to set. + * @return the CorsRule object itself. + */ + public CorsRule exposedHeaders(String exposedHeaders) { + this.exposedHeaders = exposedHeaders; + return this; + } + + /** + * Get the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @return the maxAgeInSeconds value. + */ + public int maxAgeInSeconds() { + return this.maxAgeInSeconds; + } + + /** + * Set the maxAgeInSeconds property: The maximum amount time that a browser + * should cache the preflight OPTIONS request. + * + * @param maxAgeInSeconds the maxAgeInSeconds value to set. + * @return the CorsRule object itself. + */ + public CorsRule maxAgeInSeconds(int maxAgeInSeconds) { + this.maxAgeInSeconds = maxAgeInSeconds; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java new file mode 100644 index 0000000000000..7febd2c02758d --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/DequeuedMessageItem.java @@ -0,0 +1,233 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * The object returned in the QueueMessageList array when calling Get Messages + * on a Queue. + */ +@JacksonXmlRootElement(localName = "QueueMessage") +public final class DequeuedMessageItem { + /* + * The Id of the Message. + */ + @JsonProperty(value = "MessageId", required = true) + private String messageId; + + /* + * The time the Message was inserted into the Queue. + */ + @JsonProperty(value = "InsertionTime", required = true) + private DateTimeRfc1123 insertionTime; + + /* + * The time that the Message will expire and be automatically deleted. + */ + @JsonProperty(value = "ExpirationTime", required = true) + private DateTimeRfc1123 expirationTime; + + /* + * This value is required to delete the Message. If deletion fails using + * this popreceipt then the message has been dequeued by another client. + */ + @JsonProperty(value = "PopReceipt", required = true) + private String popReceipt; + + /* + * The time that the message will again become visible in the Queue. + */ + @JsonProperty(value = "TimeNextVisible", required = true) + private DateTimeRfc1123 timeNextVisible; + + /* + * The number of times the message has been dequeued. + */ + @JsonProperty(value = "DequeueCount", required = true) + private long dequeueCount; + + /* + * The content of the Message. + */ + @JsonProperty(value = "MessageText", required = true) + private String messageText; + + /** + * Get the messageId property: The Id of the Message. + * + * @return the messageId value. + */ + public String messageId() { + return this.messageId; + } + + /** + * Set the messageId property: The Id of the Message. + * + * @param messageId the messageId value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem messageId(String messageId) { + this.messageId = messageId; + return this; + } + + /** + * Get the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @return the insertionTime value. + */ + public OffsetDateTime insertionTime() { + if (this.insertionTime == null) { + return null; + } + return this.insertionTime.dateTime(); + } + + /** + * Set the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @param insertionTime the insertionTime value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem insertionTime(OffsetDateTime insertionTime) { + if (insertionTime == null) { + this.insertionTime = null; + } else { + this.insertionTime = new DateTimeRfc1123(insertionTime); + } + return this; + } + + /** + * Get the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @return the expirationTime value. + */ + public OffsetDateTime expirationTime() { + if (this.expirationTime == null) { + return null; + } + return this.expirationTime.dateTime(); + } + + /** + * Set the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @param expirationTime the expirationTime value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem expirationTime(OffsetDateTime expirationTime) { + if (expirationTime == null) { + this.expirationTime = null; + } else { + this.expirationTime = new DateTimeRfc1123(expirationTime); + } + return this; + } + + /** + * Get the popReceipt property: This value is required to delete the + * Message. If deletion fails using this popreceipt then the message has + * been dequeued by another client. + * + * @return the popReceipt value. + */ + public String popReceipt() { + return this.popReceipt; + } + + /** + * Set the popReceipt property: This value is required to delete the + * Message. If deletion fails using this popreceipt then the message has + * been dequeued by another client. + * + * @param popReceipt the popReceipt value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem popReceipt(String popReceipt) { + this.popReceipt = popReceipt; + return this; + } + + /** + * Get the timeNextVisible property: The time that the message will again + * become visible in the Queue. + * + * @return the timeNextVisible value. + */ + public OffsetDateTime timeNextVisible() { + if (this.timeNextVisible == null) { + return null; + } + return this.timeNextVisible.dateTime(); + } + + /** + * Set the timeNextVisible property: The time that the message will again + * become visible in the Queue. + * + * @param timeNextVisible the timeNextVisible value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem timeNextVisible(OffsetDateTime timeNextVisible) { + if (timeNextVisible == null) { + this.timeNextVisible = null; + } else { + this.timeNextVisible = new DateTimeRfc1123(timeNextVisible); + } + return this; + } + + /** + * Get the dequeueCount property: The number of times the message has been + * dequeued. + * + * @return the dequeueCount value. + */ + public long dequeueCount() { + return this.dequeueCount; + } + + /** + * Set the dequeueCount property: The number of times the message has been + * dequeued. + * + * @param dequeueCount the dequeueCount value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem dequeueCount(long dequeueCount) { + this.dequeueCount = dequeueCount; + return this; + } + + /** + * Get the messageText property: The content of the Message. + * + * @return the messageText value. + */ + public String messageText() { + return this.messageText; + } + + /** + * Set the messageText property: The content of the Message. + * + * @param messageText the messageText value to set. + * @return the DequeuedMessageItem object itself. + */ + public DequeuedMessageItem messageText(String messageText) { + this.messageText = messageText; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/EnqueuedMessage.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/EnqueuedMessage.java new file mode 100644 index 0000000000000..16f1cccb9e244 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/EnqueuedMessage.java @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * The object returned in the QueueMessageList array when calling Put Message + * on a Queue. + */ +@JacksonXmlRootElement(localName = "QueueMessage") +public final class EnqueuedMessage { + /* + * The Id of the Message. + */ + @JsonProperty(value = "MessageId", required = true) + private String messageId; + + /* + * The time the Message was inserted into the Queue. + */ + @JsonProperty(value = "InsertionTime", required = true) + private DateTimeRfc1123 insertionTime; + + /* + * The time that the Message will expire and be automatically deleted. + */ + @JsonProperty(value = "ExpirationTime", required = true) + private DateTimeRfc1123 expirationTime; + + /* + * This value is required to delete the Message. If deletion fails using + * this popreceipt then the message has been dequeued by another client. + */ + @JsonProperty(value = "PopReceipt", required = true) + private String popReceipt; + + /* + * The time that the message will again become visible in the Queue. + */ + @JsonProperty(value = "TimeNextVisible", required = true) + private DateTimeRfc1123 timeNextVisible; + + /** + * Get the messageId property: The Id of the Message. + * + * @return the messageId value. + */ + public String messageId() { + return this.messageId; + } + + /** + * Set the messageId property: The Id of the Message. + * + * @param messageId the messageId value to set. + * @return the EnqueuedMessage object itself. + */ + public EnqueuedMessage messageId(String messageId) { + this.messageId = messageId; + return this; + } + + /** + * Get the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @return the insertionTime value. + */ + public OffsetDateTime insertionTime() { + if (this.insertionTime == null) { + return null; + } + return this.insertionTime.dateTime(); + } + + /** + * Set the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @param insertionTime the insertionTime value to set. + * @return the EnqueuedMessage object itself. + */ + public EnqueuedMessage insertionTime(OffsetDateTime insertionTime) { + if (insertionTime == null) { + this.insertionTime = null; + } else { + this.insertionTime = new DateTimeRfc1123(insertionTime); + } + return this; + } + + /** + * Get the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @return the expirationTime value. + */ + public OffsetDateTime expirationTime() { + if (this.expirationTime == null) { + return null; + } + return this.expirationTime.dateTime(); + } + + /** + * Set the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @param expirationTime the expirationTime value to set. + * @return the EnqueuedMessage object itself. + */ + public EnqueuedMessage expirationTime(OffsetDateTime expirationTime) { + if (expirationTime == null) { + this.expirationTime = null; + } else { + this.expirationTime = new DateTimeRfc1123(expirationTime); + } + return this; + } + + /** + * Get the popReceipt property: This value is required to delete the + * Message. If deletion fails using this popreceipt then the message has + * been dequeued by another client. + * + * @return the popReceipt value. + */ + public String popReceipt() { + return this.popReceipt; + } + + /** + * Set the popReceipt property: This value is required to delete the + * Message. If deletion fails using this popreceipt then the message has + * been dequeued by another client. + * + * @param popReceipt the popReceipt value to set. + * @return the EnqueuedMessage object itself. + */ + public EnqueuedMessage popReceipt(String popReceipt) { + this.popReceipt = popReceipt; + return this; + } + + /** + * Get the timeNextVisible property: The time that the message will again + * become visible in the Queue. + * + * @return the timeNextVisible value. + */ + public OffsetDateTime timeNextVisible() { + if (this.timeNextVisible == null) { + return null; + } + return this.timeNextVisible.dateTime(); + } + + /** + * Set the timeNextVisible property: The time that the message will again + * become visible in the Queue. + * + * @param timeNextVisible the timeNextVisible value to set. + * @return the EnqueuedMessage object itself. + */ + public EnqueuedMessage timeNextVisible(OffsetDateTime timeNextVisible) { + if (timeNextVisible == null) { + this.timeNextVisible = null; + } else { + this.timeNextVisible = new DateTimeRfc1123(timeNextVisible); + } + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplication.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplication.java new file mode 100644 index 0000000000000..1fc313b4a45b2 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplication.java @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * The GeoReplication model. + */ +@JacksonXmlRootElement(localName = "GeoReplication") +public final class GeoReplication { + /* + * The status of the secondary location. Possible values include: 'live', + * 'bootstrap', 'unavailable' + */ + @JsonProperty(value = "Status", required = true) + private GeoReplicationStatusType status; + + /* + * A GMT date/time value, to the second. All primary writes preceding this + * value are guaranteed to be available for read operations at the + * secondary. Primary writes after this point in time may or may not be + * available for reads. + */ + @JsonProperty(value = "LastSyncTime", required = true) + private DateTimeRfc1123 lastSyncTime; + + /** + * Get the status property: The status of the secondary location. Possible + * values include: 'live', 'bootstrap', 'unavailable'. + * + * @return the status value. + */ + public GeoReplicationStatusType status() { + return this.status; + } + + /** + * Set the status property: The status of the secondary location. Possible + * values include: 'live', 'bootstrap', 'unavailable'. + * + * @param status the status value to set. + * @return the GeoReplication object itself. + */ + public GeoReplication status(GeoReplicationStatusType status) { + this.status = status; + return this; + } + + /** + * Get the lastSyncTime property: A GMT date/time value, to the second. All + * primary writes preceding this value are guaranteed to be available for + * read operations at the secondary. Primary writes after this point in + * time may or may not be available for reads. + * + * @return the lastSyncTime value. + */ + public OffsetDateTime lastSyncTime() { + if (this.lastSyncTime == null) { + return null; + } + return this.lastSyncTime.dateTime(); + } + + /** + * Set the lastSyncTime property: A GMT date/time value, to the second. All + * primary writes preceding this value are guaranteed to be available for + * read operations at the secondary. Primary writes after this point in + * time may or may not be available for reads. + * + * @param lastSyncTime the lastSyncTime value to set. + * @return the GeoReplication object itself. + */ + public GeoReplication lastSyncTime(OffsetDateTime lastSyncTime) { + if (lastSyncTime == null) { + this.lastSyncTime = null; + } else { + this.lastSyncTime = new DateTimeRfc1123(lastSyncTime); + } + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplicationStatusType.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplicationStatusType.java new file mode 100644 index 0000000000000..0238afe0211ec --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/GeoReplicationStatusType.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for GeoReplicationStatusType. + */ +public final class GeoReplicationStatusType extends ExpandableStringEnum { + /** + * Static value live for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType LIVE = fromString("live"); + + /** + * Static value bootstrap for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType BOOTSTRAP = fromString("bootstrap"); + + /** + * Static value unavailable for GeoReplicationStatusType. + */ + public static final GeoReplicationStatusType UNAVAILABLE = fromString("unavailable"); + + /** + * Creates or finds a GeoReplicationStatusType from its string representation. + * + * @param name a name to look for. + * @return the corresponding GeoReplicationStatusType. + */ + @JsonCreator + public static GeoReplicationStatusType fromString(String name) { + return fromString(name, GeoReplicationStatusType.class); + } + + /** + * @return known GeoReplicationStatusType values. + */ + public static Collection values() { + return values(GeoReplicationStatusType.class); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesIncludeType.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesIncludeType.java new file mode 100644 index 0000000000000..e2d7974714006 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesIncludeType.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Defines values for ListQueuesIncludeType. + */ +public enum ListQueuesIncludeType { + /** + * Enum value metadata. + */ + METADATA("metadata"); + + /** + * The actual serialized value for a ListQueuesIncludeType instance. + */ + private final String value; + + ListQueuesIncludeType(String value) { + this.value = value; + } + + /** + * Parses a serialized value to a ListQueuesIncludeType instance. + * + * @param value the serialized value to parse. + * @return the parsed ListQueuesIncludeType object, or null if unable to parse. + */ + @JsonCreator + public static ListQueuesIncludeType fromString(String value) { + ListQueuesIncludeType[] items = ListQueuesIncludeType.values(); + for (ListQueuesIncludeType item : items) { + if (item.toString().equalsIgnoreCase(value)) { + return item; + } + } + return null; + } + + @JsonValue + @Override + public String toString() { + return this.value; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesSegmentResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesSegmentResponse.java new file mode 100644 index 0000000000000..8e34bc50503ba --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ListQueuesSegmentResponse.java @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * The object returned when calling List Queues on a Queue Service. + */ +@JacksonXmlRootElement(localName = "EnumerationResults") +public final class ListQueuesSegmentResponse { + /* + * The serviceEndpoint property. + */ + @JacksonXmlProperty(localName = "ServiceEndpoint", isAttribute = true) + private String serviceEndpoint; + + /* + * The prefix property. + */ + @JsonProperty(value = "Prefix", required = true) + private String prefix; + + /* + * The marker property. + */ + @JsonProperty(value = "Marker") + private String marker; + + /* + * The maxResults property. + */ + @JsonProperty(value = "MaxResults", required = true) + private int maxResults; + + private static final class QueuesWrapper { + @JacksonXmlProperty(localName = "Queue") + private final List items; + + @JsonCreator + private QueuesWrapper(@JacksonXmlProperty(localName = "Queue") List items) { + this.items = items; + } + } + + /* + * The queueItems property. + */ + @JsonProperty(value = "Queues") + private QueuesWrapper queueItems; + + /* + * The nextMarker property. + */ + @JsonProperty(value = "NextMarker", required = true) + private String nextMarker; + + /** + * Get the serviceEndpoint property: The serviceEndpoint property. + * + * @return the serviceEndpoint value. + */ + public String serviceEndpoint() { + return this.serviceEndpoint; + } + + /** + * Set the serviceEndpoint property: The serviceEndpoint property. + * + * @param serviceEndpoint the serviceEndpoint value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse serviceEndpoint(String serviceEndpoint) { + this.serviceEndpoint = serviceEndpoint; + return this; + } + + /** + * Get the prefix property: The prefix property. + * + * @return the prefix value. + */ + public String prefix() { + return this.prefix; + } + + /** + * Set the prefix property: The prefix property. + * + * @param prefix the prefix value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse prefix(String prefix) { + this.prefix = prefix; + return this; + } + + /** + * Get the marker property: The marker property. + * + * @return the marker value. + */ + public String marker() { + return this.marker; + } + + /** + * Set the marker property: The marker property. + * + * @param marker the marker value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse marker(String marker) { + this.marker = marker; + return this; + } + + /** + * Get the maxResults property: The maxResults property. + * + * @return the maxResults value. + */ + public int maxResults() { + return this.maxResults; + } + + /** + * Set the maxResults property: The maxResults property. + * + * @param maxResults the maxResults value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse maxResults(int maxResults) { + this.maxResults = maxResults; + return this; + } + + /** + * Get the queueItems property: The queueItems property. + * + * @return the queueItems value. + */ + public List queueItems() { + if (this.queueItems == null) { + this.queueItems = new QueuesWrapper(new ArrayList()); + } + return this.queueItems.items; + } + + /** + * Set the queueItems property: The queueItems property. + * + * @param queueItems the queueItems value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse queueItems(List queueItems) { + this.queueItems = new QueuesWrapper(queueItems); + return this; + } + + /** + * Get the nextMarker property: The nextMarker property. + * + * @return the nextMarker value. + */ + public String nextMarker() { + return this.nextMarker; + } + + /** + * Set the nextMarker property: The nextMarker property. + * + * @param nextMarker the nextMarker value to set. + * @return the ListQueuesSegmentResponse object itself. + */ + public ListQueuesSegmentResponse nextMarker(String nextMarker) { + this.nextMarker = nextMarker; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/Logging.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/Logging.java new file mode 100644 index 0000000000000..c5289b4fb5a50 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/Logging.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Azure Analytics Logging settings. + */ +@JacksonXmlRootElement(localName = "Logging") +public final class Logging { + /* + * The version of Storage Analytics to configure. + */ + @JsonProperty(value = "Version", required = true) + private String version; + + /* + * Indicates whether all delete requests should be logged. + */ + @JsonProperty(value = "Delete", required = true) + private boolean delete; + + /* + * Indicates whether all read requests should be logged. + */ + @JsonProperty(value = "Read", required = true) + private boolean read; + + /* + * Indicates whether all write requests should be logged. + */ + @JsonProperty(value = "Write", required = true) + private boolean write; + + /* + * The retentionPolicy property. + */ + @JsonProperty(value = "RetentionPolicy", required = true) + private RetentionPolicy retentionPolicy; + + /** + * Get the version property: The version of Storage Analytics to configure. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: The version of Storage Analytics to configure. + * + * @param version the version value to set. + * @return the Logging object itself. + */ + public Logging version(String version) { + this.version = version; + return this; + } + + /** + * Get the delete property: Indicates whether all delete requests should be + * logged. + * + * @return the delete value. + */ + public boolean delete() { + return this.delete; + } + + /** + * Set the delete property: Indicates whether all delete requests should be + * logged. + * + * @param delete the delete value to set. + * @return the Logging object itself. + */ + public Logging delete(boolean delete) { + this.delete = delete; + return this; + } + + /** + * Get the read property: Indicates whether all read requests should be + * logged. + * + * @return the read value. + */ + public boolean read() { + return this.read; + } + + /** + * Set the read property: Indicates whether all read requests should be + * logged. + * + * @param read the read value to set. + * @return the Logging object itself. + */ + public Logging read(boolean read) { + this.read = read; + return this; + } + + /** + * Get the write property: Indicates whether all write requests should be + * logged. + * + * @return the write value. + */ + public boolean write() { + return this.write; + } + + /** + * Set the write property: Indicates whether all write requests should be + * logged. + * + * @param write the write value to set. + * @return the Logging object itself. + */ + public Logging write(boolean write) { + this.write = write; + return this; + } + + /** + * Get the retentionPolicy property: The retentionPolicy property. + * + * @return the retentionPolicy value. + */ + public RetentionPolicy retentionPolicy() { + return this.retentionPolicy; + } + + /** + * Set the retentionPolicy property: The retentionPolicy property. + * + * @param retentionPolicy the retentionPolicy value to set. + * @return the Logging object itself. + */ + public Logging retentionPolicy(RetentionPolicy retentionPolicy) { + this.retentionPolicy = retentionPolicy; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdDeleteHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdDeleteHeaders.java new file mode 100644 index 0000000000000..e369a4d60c99d --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdDeleteHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "MessageId-Delete-Headers") +public final class MessageIdDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessageIdDeleteHeaders object itself. + */ + public MessageIdDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessageIdDeleteHeaders object itself. + */ + public MessageIdDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessageIdDeleteHeaders object itself. + */ + public MessageIdDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessageIdDeleteHeaders object itself. + */ + public MessageIdDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdUpdateHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdUpdateHeaders.java new file mode 100644 index 0000000000000..a0129420618db --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdUpdateHeaders.java @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Update operation. + */ +@JacksonXmlRootElement(localName = "MessageId-Update-Headers") +public final class MessageIdUpdateHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The pop receipt of the queue message. + */ + @JsonProperty(value = "x-ms-popreceipt") + private String popReceipt; + + /* + * A UTC date/time value that represents when the message will be visible + * on the queue. + */ + @JsonProperty(value = "x-ms-time-next-visible") + private DateTimeRfc1123 timeNextVisible; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the popReceipt property: The pop receipt of the queue message. + * + * @return the popReceipt value. + */ + public String popReceipt() { + return this.popReceipt; + } + + /** + * Set the popReceipt property: The pop receipt of the queue message. + * + * @param popReceipt the popReceipt value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders popReceipt(String popReceipt) { + this.popReceipt = popReceipt; + return this; + } + + /** + * Get the timeNextVisible property: A UTC date/time value that represents + * when the message will be visible on the queue. + * + * @return the timeNextVisible value. + */ + public OffsetDateTime timeNextVisible() { + if (this.timeNextVisible == null) { + return null; + } + return this.timeNextVisible.dateTime(); + } + + /** + * Set the timeNextVisible property: A UTC date/time value that represents + * when the message will be visible on the queue. + * + * @param timeNextVisible the timeNextVisible value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders timeNextVisible(OffsetDateTime timeNextVisible) { + if (timeNextVisible == null) { + this.timeNextVisible = null; + } else { + this.timeNextVisible = new DateTimeRfc1123(timeNextVisible); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessageIdUpdateHeaders object itself. + */ + public MessageIdUpdateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsDeleteResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsDeleteResponse.java new file mode 100644 index 0000000000000..3639b840adfdd --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class MessageIdsDeleteResponse extends ResponseBase { + /** + * Creates an instance of MessageIdsDeleteResponse. + * + * @param request the request which resulted in this MessageIdsDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessageIdsDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, MessageIdDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsUpdateResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsUpdateResponse.java new file mode 100644 index 0000000000000..4305b7c915ec9 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessageIdsUpdateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the update operation. + */ +public final class MessageIdsUpdateResponse extends ResponseBase { + /** + * Creates an instance of MessageIdsUpdateResponse. + * + * @param request the request which resulted in this MessageIdsUpdateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessageIdsUpdateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, MessageIdUpdateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearHeaders.java new file mode 100644 index 0000000000000..6bb1165cb4de1 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Clear operation. + */ +@JacksonXmlRootElement(localName = "Messages-Clear-Headers") +public final class MessagesClearHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessagesClearHeaders object itself. + */ + public MessagesClearHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessagesClearHeaders object itself. + */ + public MessagesClearHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessagesClearHeaders object itself. + */ + public MessagesClearHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessagesClearHeaders object itself. + */ + public MessagesClearHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearResponse.java new file mode 100644 index 0000000000000..d21b99d0f839a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesClearResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the clear operation. + */ +public final class MessagesClearResponse extends ResponseBase { + /** + * Creates an instance of MessagesClearResponse. + * + * @param request the request which resulted in this MessagesClearResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessagesClearResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, MessagesClearHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueHeaders.java new file mode 100644 index 0000000000000..3957cd8a79d41 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Dequeue operation. + */ +@JacksonXmlRootElement(localName = "Messages-Dequeue-Headers") +public final class MessagesDequeueHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessagesDequeueHeaders object itself. + */ + public MessagesDequeueHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessagesDequeueHeaders object itself. + */ + public MessagesDequeueHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessagesDequeueHeaders object itself. + */ + public MessagesDequeueHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessagesDequeueHeaders object itself. + */ + public MessagesDequeueHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java new file mode 100644 index 0000000000000..4ab4b09a4a620 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesDequeueResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the dequeue operation. + */ +public final class MessagesDequeueResponse extends ResponseBase> { + /** + * Creates an instance of MessagesDequeueResponse. + * + * @param request the request which resulted in this MessagesDequeueResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessagesDequeueResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, MessagesDequeueHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueHeaders.java new file mode 100644 index 0000000000000..39dc57ed0c2a1 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Enqueue operation. + */ +@JacksonXmlRootElement(localName = "Messages-Enqueue-Headers") +public final class MessagesEnqueueHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessagesEnqueueHeaders object itself. + */ + public MessagesEnqueueHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessagesEnqueueHeaders object itself. + */ + public MessagesEnqueueHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessagesEnqueueHeaders object itself. + */ + public MessagesEnqueueHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessagesEnqueueHeaders object itself. + */ + public MessagesEnqueueHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueResponse.java new file mode 100644 index 0000000000000..079778e006762 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesEnqueueResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the enqueue operation. + */ +public final class MessagesEnqueueResponse extends ResponseBase> { + /** + * Creates an instance of MessagesEnqueueResponse. + * + * @param request the request which resulted in this MessagesEnqueueResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessagesEnqueueResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, MessagesEnqueueHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekHeaders.java new file mode 100644 index 0000000000000..4733069112ace --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Peek operation. + */ +@JacksonXmlRootElement(localName = "Messages-Peek-Headers") +public final class MessagesPeekHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the MessagesPeekHeaders object itself. + */ + public MessagesPeekHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the MessagesPeekHeaders object itself. + */ + public MessagesPeekHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the MessagesPeekHeaders object itself. + */ + public MessagesPeekHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the MessagesPeekHeaders object itself. + */ + public MessagesPeekHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java new file mode 100644 index 0000000000000..8ca8ed06fd99c --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/MessagesPeekResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the peek operation. + */ +public final class MessagesPeekResponse extends ResponseBase> { + /** + * Creates an instance of MessagesPeekResponse. + * + * @param request the request which resulted in this MessagesPeekResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public MessagesPeekResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, MessagesPeekHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/Metrics.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/Metrics.java new file mode 100644 index 0000000000000..8c9b2fe7923ae --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/Metrics.java @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The Metrics model. + */ +@JacksonXmlRootElement(localName = "Metrics") +public final class Metrics { + /* + * The version of Storage Analytics to configure. + */ + @JsonProperty(value = "Version") + private String version; + + /* + * Indicates whether metrics are enabled for the Queue service. + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates whether metrics should generate summary statistics for called + * API operations. + */ + @JsonProperty(value = "IncludeAPIs") + private Boolean includeAPIs; + + /* + * The retentionPolicy property. + */ + @JsonProperty(value = "RetentionPolicy") + private RetentionPolicy retentionPolicy; + + /** + * Get the version property: The version of Storage Analytics to configure. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: The version of Storage Analytics to configure. + * + * @param version the version value to set. + * @return the Metrics object itself. + */ + public Metrics version(String version) { + this.version = version; + return this; + } + + /** + * Get the enabled property: Indicates whether metrics are enabled for the + * Queue service. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether metrics are enabled for the + * Queue service. + * + * @param enabled the enabled value to set. + * @return the Metrics object itself. + */ + public Metrics enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @return the includeAPIs value. + */ + public Boolean includeAPIs() { + return this.includeAPIs; + } + + /** + * Set the includeAPIs property: Indicates whether metrics should generate + * summary statistics for called API operations. + * + * @param includeAPIs the includeAPIs value to set. + * @return the Metrics object itself. + */ + public Metrics includeAPIs(Boolean includeAPIs) { + this.includeAPIs = includeAPIs; + return this; + } + + /** + * Get the retentionPolicy property: The retentionPolicy property. + * + * @return the retentionPolicy value. + */ + public RetentionPolicy retentionPolicy() { + return this.retentionPolicy; + } + + /** + * Set the retentionPolicy property: The retentionPolicy property. + * + * @param retentionPolicy the retentionPolicy value to set. + * @return the Metrics object itself. + */ + public Metrics retentionPolicy(RetentionPolicy retentionPolicy) { + this.retentionPolicy = retentionPolicy; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java new file mode 100644 index 0000000000000..d86bdab8c2305 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/PeekedMessageItem.java @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * The object returned in the QueueMessageList array when calling Peek Messages + * on a Queue. + */ +@JacksonXmlRootElement(localName = "QueueMessage") +public final class PeekedMessageItem { + /* + * The Id of the Message. + */ + @JsonProperty(value = "MessageId", required = true) + private String messageId; + + /* + * The time the Message was inserted into the Queue. + */ + @JsonProperty(value = "InsertionTime", required = true) + private DateTimeRfc1123 insertionTime; + + /* + * The time that the Message will expire and be automatically deleted. + */ + @JsonProperty(value = "ExpirationTime", required = true) + private DateTimeRfc1123 expirationTime; + + /* + * The number of times the message has been dequeued. + */ + @JsonProperty(value = "DequeueCount", required = true) + private long dequeueCount; + + /* + * The content of the Message. + */ + @JsonProperty(value = "MessageText", required = true) + private String messageText; + + /** + * Get the messageId property: The Id of the Message. + * + * @return the messageId value. + */ + public String messageId() { + return this.messageId; + } + + /** + * Set the messageId property: The Id of the Message. + * + * @param messageId the messageId value to set. + * @return the PeekedMessageItem object itself. + */ + public PeekedMessageItem messageId(String messageId) { + this.messageId = messageId; + return this; + } + + /** + * Get the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @return the insertionTime value. + */ + public OffsetDateTime insertionTime() { + if (this.insertionTime == null) { + return null; + } + return this.insertionTime.dateTime(); + } + + /** + * Set the insertionTime property: The time the Message was inserted into + * the Queue. + * + * @param insertionTime the insertionTime value to set. + * @return the PeekedMessageItem object itself. + */ + public PeekedMessageItem insertionTime(OffsetDateTime insertionTime) { + if (insertionTime == null) { + this.insertionTime = null; + } else { + this.insertionTime = new DateTimeRfc1123(insertionTime); + } + return this; + } + + /** + * Get the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @return the expirationTime value. + */ + public OffsetDateTime expirationTime() { + if (this.expirationTime == null) { + return null; + } + return this.expirationTime.dateTime(); + } + + /** + * Set the expirationTime property: The time that the Message will expire + * and be automatically deleted. + * + * @param expirationTime the expirationTime value to set. + * @return the PeekedMessageItem object itself. + */ + public PeekedMessageItem expirationTime(OffsetDateTime expirationTime) { + if (expirationTime == null) { + this.expirationTime = null; + } else { + this.expirationTime = new DateTimeRfc1123(expirationTime); + } + return this; + } + + /** + * Get the dequeueCount property: The number of times the message has been + * dequeued. + * + * @return the dequeueCount value. + */ + public long dequeueCount() { + return this.dequeueCount; + } + + /** + * Set the dequeueCount property: The number of times the message has been + * dequeued. + * + * @param dequeueCount the dequeueCount value to set. + * @return the PeekedMessageItem object itself. + */ + public PeekedMessageItem dequeueCount(long dequeueCount) { + this.dequeueCount = dequeueCount; + return this; + } + + /** + * Get the messageText property: The content of the Message. + * + * @return the messageText value. + */ + public String messageText() { + return this.messageText; + } + + /** + * Set the messageText property: The content of the Message. + * + * @param messageText the messageText value to set. + * @return the PeekedMessageItem object itself. + */ + public PeekedMessageItem messageText(String messageText) { + this.messageText = messageText; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueCreateHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueCreateHeaders.java new file mode 100644 index 0000000000000..7e0bee9cd7eb4 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueCreateHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Create operation. + */ +@JacksonXmlRootElement(localName = "Queue-Create-Headers") +public final class QueueCreateHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueCreateHeaders object itself. + */ + public QueueCreateHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueCreateHeaders object itself. + */ + public QueueCreateHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueCreateHeaders object itself. + */ + public QueueCreateHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueCreateHeaders object itself. + */ + public QueueCreateHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueDeleteHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueDeleteHeaders.java new file mode 100644 index 0000000000000..5a29a098628c2 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueDeleteHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for Delete operation. + */ +@JacksonXmlRootElement(localName = "Queue-Delete-Headers") +public final class QueueDeleteHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueDeleteHeaders object itself. + */ + public QueueDeleteHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueDeleteHeaders object itself. + */ + public QueueDeleteHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueDeleteHeaders object itself. + */ + public QueueDeleteHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueDeleteHeaders object itself. + */ + public QueueDeleteHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetAccessPolicyHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..65fa98edf8aa2 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetAccessPolicyHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Queue-GetAccessPolicy-Headers") +public final class QueueGetAccessPolicyHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueGetAccessPolicyHeaders object itself. + */ + public QueueGetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueGetAccessPolicyHeaders object itself. + */ + public QueueGetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueGetAccessPolicyHeaders object itself. + */ + public QueueGetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueGetAccessPolicyHeaders object itself. + */ + public QueueGetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetPropertiesHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetPropertiesHeaders.java new file mode 100644 index 0000000000000..20286e8a0ddb3 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueGetPropertiesHeaders.java @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.annotations.HeaderCollection; +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Queue-GetProperties-Headers") +public final class QueueGetPropertiesHeaders { + /* + * The metadata property. + */ + @HeaderCollection("x-ms-meta-") + private Map metadata; + + /* + * The approximate number of messages in the queue. This number is not + * lower than the actual number of messages in the queue, but could be + * higher. + */ + @JsonProperty(value = "x-ms-approximate-messages-count") + private Integer approximateMessagesCount; + + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders metadata(Map metadata) { + this.metadata = metadata; + return this; + } + + /** + * Get the approximateMessagesCount property: The approximate number of + * messages in the queue. This number is not lower than the actual number + * of messages in the queue, but could be higher. + * + * @return the approximateMessagesCount value. + */ + public Integer approximateMessagesCount() { + return this.approximateMessagesCount; + } + + /** + * Set the approximateMessagesCount property: The approximate number of + * messages in the queue. This number is not lower than the actual number + * of messages in the queue, but could be higher. + * + * @param approximateMessagesCount the approximateMessagesCount value to + * set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders approximateMessagesCount(Integer approximateMessagesCount) { + this.approximateMessagesCount = approximateMessagesCount; + return this; + } + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueGetPropertiesHeaders object itself. + */ + public QueueGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueItem.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueItem.java new file mode 100644 index 0000000000000..1575af6babcb8 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueItem.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.Map; + +/** + * An Azure Storage Queue. + */ +@JacksonXmlRootElement(localName = "Queue") +public final class QueueItem { + /* + * The name of the Queue. + */ + @JsonProperty(value = "Name", required = true) + private String name; + + /* + * The metadata property. + */ + @JsonProperty(value = "Metadata") + private Map metadata; + + /** + * Get the name property: The name of the Queue. + * + * @return the name value. + */ + public String name() { + return this.name; + } + + /** + * Set the name property: The name of the Queue. + * + * @param name the name value to set. + * @return the QueueItem object itself. + */ + public QueueItem name(String name) { + this.name = name; + return this; + } + + /** + * Get the metadata property: The metadata property. + * + * @return the metadata value. + */ + public Map metadata() { + return this.metadata; + } + + /** + * Set the metadata property: The metadata property. + * + * @param metadata the metadata value to set. + * @return the QueueItem object itself. + */ + public QueueItem metadata(Map metadata) { + this.metadata = metadata; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueMessage.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueMessage.java new file mode 100644 index 0000000000000..204825759ab0c --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueMessage.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * A Message object which can be stored in a Queue. + */ +@JacksonXmlRootElement(localName = "QueueMessage") +public final class QueueMessage { + /* + * The content of the message + */ + @JsonProperty(value = "MessageText", required = true) + private String messageText; + + /** + * Get the messageText property: The content of the message. + * + * @return the messageText value. + */ + public String messageText() { + return this.messageText; + } + + /** + * Set the messageText property: The content of the message. + * + * @param messageText the messageText value to set. + * @return the QueueMessage object itself. + */ + public QueueMessage messageText(String messageText) { + this.messageText = messageText; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetAccessPolicyHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetAccessPolicyHeaders.java new file mode 100644 index 0000000000000..c2152ccc6a5cb --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetAccessPolicyHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetAccessPolicy operation. + */ +@JacksonXmlRootElement(localName = "Queue-SetAccessPolicy-Headers") +public final class QueueSetAccessPolicyHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueSetAccessPolicyHeaders object itself. + */ + public QueueSetAccessPolicyHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueSetAccessPolicyHeaders object itself. + */ + public QueueSetAccessPolicyHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueSetAccessPolicyHeaders object itself. + */ + public QueueSetAccessPolicyHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueSetAccessPolicyHeaders object itself. + */ + public QueueSetAccessPolicyHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetMetadataHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetMetadataHeaders.java new file mode 100644 index 0000000000000..f68e00835afaa --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueueSetMetadataHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for SetMetadata operation. + */ +@JacksonXmlRootElement(localName = "Queue-SetMetadata-Headers") +public final class QueueSetMetadataHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the QueueSetMetadataHeaders object itself. + */ + public QueueSetMetadataHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the QueueSetMetadataHeaders object itself. + */ + public QueueSetMetadataHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the QueueSetMetadataHeaders object itself. + */ + public QueueSetMetadataHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the QueueSetMetadataHeaders object itself. + */ + public QueueSetMetadataHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesCreateResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesCreateResponse.java new file mode 100644 index 0000000000000..b191cf79d5a0a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesCreateResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the create operation. + */ +public final class QueuesCreateResponse extends ResponseBase { + /** + * Creates an instance of QueuesCreateResponse. + * + * @param request the request which resulted in this QueuesCreateResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesCreateResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, QueueCreateHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesDeleteResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesDeleteResponse.java new file mode 100644 index 0000000000000..8023feab3bbe6 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesDeleteResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the delete operation. + */ +public final class QueuesDeleteResponse extends ResponseBase { + /** + * Creates an instance of QueuesDeleteResponse. + * + * @param request the request which resulted in this QueuesDeleteResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesDeleteResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, QueueDeleteHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetAccessPolicyResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetAccessPolicyResponse.java new file mode 100644 index 0000000000000..d2fa4cc44c29e --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetAccessPolicyResponse.java @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; +import java.util.List; + +/** + * Contains all response data for the getAccessPolicy operation. + */ +public final class QueuesGetAccessPolicyResponse extends ResponseBase> { + /** + * Creates an instance of QueuesGetAccessPolicyResponse. + * + * @param request the request which resulted in this QueuesGetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesGetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, List value, QueueGetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public List value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetPropertiesResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetPropertiesResponse.java new file mode 100644 index 0000000000000..971f32275b2a7 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesGetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class QueuesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of QueuesGetPropertiesResponse. + * + * @param request the request which resulted in this QueuesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, QueueGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetAccessPolicyResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetAccessPolicyResponse.java new file mode 100644 index 0000000000000..c1828b8668da5 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetAccessPolicyResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setAccessPolicy operation. + */ +public final class QueuesSetAccessPolicyResponse extends ResponseBase { + /** + * Creates an instance of QueuesSetAccessPolicyResponse. + * + * @param request the request which resulted in this QueuesSetAccessPolicyResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesSetAccessPolicyResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, QueueSetAccessPolicyHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetMetadataResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetMetadataResponse.java new file mode 100644 index 0000000000000..b33125bc20d6a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/QueuesSetMetadataResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setMetadata operation. + */ +public final class QueuesSetMetadataResponse extends ResponseBase { + /** + * Creates an instance of QueuesSetMetadataResponse. + * + * @param request the request which resulted in this QueuesSetMetadataResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public QueuesSetMetadataResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, QueueSetMetadataHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/RetentionPolicy.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/RetentionPolicy.java new file mode 100644 index 0000000000000..045580d2c31ad --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/RetentionPolicy.java @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * the retention policy. + */ +@JacksonXmlRootElement(localName = "RetentionPolicy") +public final class RetentionPolicy { + /* + * Indicates whether a retention policy is enabled for the storage service + */ + @JsonProperty(value = "Enabled", required = true) + private boolean enabled; + + /* + * Indicates the number of days that metrics or logging or soft-deleted + * data should be retained. All data older than this value will be deleted + */ + @JsonProperty(value = "Days") + private Integer days; + + /** + * Get the enabled property: Indicates whether a retention policy is + * enabled for the storage service. + * + * @return the enabled value. + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Set the enabled property: Indicates whether a retention policy is + * enabled for the storage service. + * + * @param enabled the enabled value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy enabled(boolean enabled) { + this.enabled = enabled; + return this; + } + + /** + * Get the days property: Indicates the number of days that metrics or + * logging or soft-deleted data should be retained. All data older than + * this value will be deleted. + * + * @return the days value. + */ + public Integer days() { + return this.days; + } + + /** + * Set the days property: Indicates the number of days that metrics or + * logging or soft-deleted data should be retained. All data older than + * this value will be deleted. + * + * @param days the days value to set. + * @return the RetentionPolicy object itself. + */ + public RetentionPolicy days(Integer days) { + this.days = days; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetPropertiesHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetPropertiesHeaders.java new file mode 100644 index 0000000000000..e58eab15aff92 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetPropertiesHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for GetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-GetProperties-Headers") +public final class ServiceGetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetPropertiesHeaders object itself. + */ + public ServiceGetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetStatisticsHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetStatisticsHeaders.java new file mode 100644 index 0000000000000..ac56fc0624e8d --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceGetStatisticsHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for GetStatistics operation. + */ +@JacksonXmlRootElement(localName = "Service-GetStatistics-Headers") +public final class ServiceGetStatisticsHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceGetStatisticsHeaders object itself. + */ + public ServiceGetStatisticsHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceListQueuesSegmentHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceListQueuesSegmentHeaders.java new file mode 100644 index 0000000000000..341fd32e50a97 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceListQueuesSegmentHeaders.java @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.implementation.DateTimeRfc1123; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.time.OffsetDateTime; + +/** + * Defines headers for ListQueuesSegment operation. + */ +@JacksonXmlRootElement(localName = "Service-ListQueuesSegment-Headers") +public final class ServiceListQueuesSegmentHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * UTC date/time value generated by the service that indicates the time at + * which the response was initiated + */ + @JsonProperty(value = "Date") + private DateTimeRfc1123 dateProperty; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceListQueuesSegmentHeaders object itself. + */ + public ServiceListQueuesSegmentHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceListQueuesSegmentHeaders object itself. + */ + public ServiceListQueuesSegmentHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @return the dateProperty value. + */ + public OffsetDateTime dateProperty() { + if (this.dateProperty == null) { + return null; + } + return this.dateProperty.dateTime(); + } + + /** + * Set the dateProperty property: UTC date/time value generated by the + * service that indicates the time at which the response was initiated. + * + * @param dateProperty the dateProperty value to set. + * @return the ServiceListQueuesSegmentHeaders object itself. + */ + public ServiceListQueuesSegmentHeaders dateProperty(OffsetDateTime dateProperty) { + if (dateProperty == null) { + this.dateProperty = null; + } else { + this.dateProperty = new DateTimeRfc1123(dateProperty); + } + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceListQueuesSegmentHeaders object itself. + */ + public ServiceListQueuesSegmentHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceSetPropertiesHeaders.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceSetPropertiesHeaders.java new file mode 100644 index 0000000000000..aa98c955afe48 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServiceSetPropertiesHeaders.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Defines headers for SetProperties operation. + */ +@JacksonXmlRootElement(localName = "Service-SetProperties-Headers") +public final class ServiceSetPropertiesHeaders { + /* + * This header uniquely identifies the request that was made and can be + * used for troubleshooting the request. + */ + @JsonProperty(value = "x-ms-request-id") + private String requestId; + + /* + * Indicates the version of the Queue service used to execute the request. + * This header is returned for requests made against version 2009-09-19 and + * above. + */ + @JsonProperty(value = "x-ms-version") + private String version; + + /* + * The errorCode property. + */ + @JsonProperty(value = "x-ms-error-code") + private String errorCode; + + /** + * Get the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @return the requestId value. + */ + public String requestId() { + return this.requestId; + } + + /** + * Set the requestId property: This header uniquely identifies the request + * that was made and can be used for troubleshooting the request. + * + * @param requestId the requestId value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders requestId(String requestId) { + this.requestId = requestId; + return this; + } + + /** + * Get the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @return the version value. + */ + public String version() { + return this.version; + } + + /** + * Set the version property: Indicates the version of the Queue service + * used to execute the request. This header is returned for requests made + * against version 2009-09-19 and above. + * + * @param version the version value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders version(String version) { + this.version = version; + return this; + } + + /** + * Get the errorCode property: The errorCode property. + * + * @return the errorCode value. + */ + public String errorCode() { + return this.errorCode; + } + + /** + * Set the errorCode property: The errorCode property. + * + * @param errorCode the errorCode value to set. + * @return the ServiceSetPropertiesHeaders object itself. + */ + public ServiceSetPropertiesHeaders errorCode(String errorCode) { + this.errorCode = errorCode; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetPropertiesResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetPropertiesResponse.java new file mode 100644 index 0000000000000..7374eddcc1b66 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetPropertiesResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getProperties operation. + */ +public final class ServicesGetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetPropertiesResponse. + * + * @param request the request which resulted in this ServicesGetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, StorageServiceProperties value, ServiceGetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public StorageServiceProperties value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetStatisticsResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetStatisticsResponse.java new file mode 100644 index 0000000000000..5c3538a95fec0 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesGetStatisticsResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the getStatistics operation. + */ +public final class ServicesGetStatisticsResponse extends ResponseBase { + /** + * Creates an instance of ServicesGetStatisticsResponse. + * + * @param request the request which resulted in this ServicesGetStatisticsResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesGetStatisticsResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, StorageServiceStats value, ServiceGetStatisticsHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public StorageServiceStats value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesListQueuesSegmentResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesListQueuesSegmentResponse.java new file mode 100644 index 0000000000000..e7bbf195f61bb --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesListQueuesSegmentResponse.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the listQueuesSegment operation. + */ +public final class ServicesListQueuesSegmentResponse extends ResponseBase { + /** + * Creates an instance of ServicesListQueuesSegmentResponse. + * + * @param request the request which resulted in this ServicesListQueuesSegmentResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesListQueuesSegmentResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, ListQueuesSegmentResponse value, ServiceListQueuesSegmentHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } + + /** + * @return the deserialized response body. + */ + @Override + public ListQueuesSegmentResponse value() { + return super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesSetPropertiesResponse.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesSetPropertiesResponse.java new file mode 100644 index 0000000000000..7086534101a95 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/ServicesSetPropertiesResponse.java @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.ResponseBase; + +/** + * Contains all response data for the setProperties operation. + */ +public final class ServicesSetPropertiesResponse extends ResponseBase { + /** + * Creates an instance of ServicesSetPropertiesResponse. + * + * @param request the request which resulted in this ServicesSetPropertiesResponse. + * @param statusCode the status code of the HTTP response. + * @param rawHeaders the raw headers of the HTTP response. + * @param value the deserialized value of the HTTP response. + * @param headers the deserialized headers of the HTTP response. + */ + public ServicesSetPropertiesResponse(HttpRequest request, int statusCode, HttpHeaders rawHeaders, Void value, ServiceSetPropertiesHeaders headers) { + super(request, statusCode, rawHeaders, value, headers); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/SignedIdentifier.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/SignedIdentifier.java new file mode 100644 index 0000000000000..7764f3a25ea75 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/SignedIdentifier.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * signed identifier. + */ +@JacksonXmlRootElement(localName = "SignedIdentifier") +public final class SignedIdentifier { + /* + * a unique id + */ + @JsonProperty(value = "Id", required = true) + private String id; + + /* + * The access policy + */ + @JsonProperty(value = "AccessPolicy", required = true) + private AccessPolicy accessPolicy; + + /** + * Get the id property: a unique id. + * + * @return the id value. + */ + public String id() { + return this.id; + } + + /** + * Set the id property: a unique id. + * + * @param id the id value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier id(String id) { + this.id = id; + return this; + } + + /** + * Get the accessPolicy property: The access policy. + * + * @return the accessPolicy value. + */ + public AccessPolicy accessPolicy() { + return this.accessPolicy; + } + + /** + * Set the accessPolicy property: The access policy. + * + * @param accessPolicy the accessPolicy value to set. + * @return the SignedIdentifier object itself. + */ + public SignedIdentifier accessPolicy(AccessPolicy accessPolicy) { + this.accessPolicy = accessPolicy; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageError.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageError.java new file mode 100644 index 0000000000000..0e264e6da0b82 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageError.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * The StorageError model. + */ +@JacksonXmlRootElement(localName = "StorageError") +public final class StorageError { + /* + * The message property. + */ + @JsonProperty(value = "Message") + private String message; + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String message() { + return this.message; + } + + /** + * Set the message property: The message property. + * + * @param message the message value to set. + * @return the StorageError object itself. + */ + public StorageError message(String message) { + this.message = message; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorCode.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorCode.java new file mode 100644 index 0000000000000..dfa27d5fed947 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorCode.java @@ -0,0 +1,287 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** + * Defines values for StorageErrorCode. + */ +public final class StorageErrorCode extends ExpandableStringEnum { + /** + * Static value AccountAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_ALREADY_EXISTS = fromString("AccountAlreadyExists"); + + /** + * Static value AccountBeingCreated for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_BEING_CREATED = fromString("AccountBeingCreated"); + + /** + * Static value AccountIsDisabled for StorageErrorCode. + */ + public static final StorageErrorCode ACCOUNT_IS_DISABLED = fromString("AccountIsDisabled"); + + /** + * Static value AuthenticationFailed for StorageErrorCode. + */ + public static final StorageErrorCode AUTHENTICATION_FAILED = fromString("AuthenticationFailed"); + + /** + * Static value AuthorizationFailure for StorageErrorCode. + */ + public static final StorageErrorCode AUTHORIZATION_FAILURE = fromString("AuthorizationFailure"); + + /** + * Static value ConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_HEADERS_NOT_SUPPORTED = fromString("ConditionHeadersNotSupported"); + + /** + * Static value ConditionNotMet for StorageErrorCode. + */ + public static final StorageErrorCode CONDITION_NOT_MET = fromString("ConditionNotMet"); + + /** + * Static value EmptyMetadataKey for StorageErrorCode. + */ + public static final StorageErrorCode EMPTY_METADATA_KEY = fromString("EmptyMetadataKey"); + + /** + * Static value InsufficientAccountPermissions for StorageErrorCode. + */ + public static final StorageErrorCode INSUFFICIENT_ACCOUNT_PERMISSIONS = fromString("InsufficientAccountPermissions"); + + /** + * Static value InternalError for StorageErrorCode. + */ + public static final StorageErrorCode INTERNAL_ERROR = fromString("InternalError"); + + /** + * Static value InvalidAuthenticationInfo for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_AUTHENTICATION_INFO = fromString("InvalidAuthenticationInfo"); + + /** + * Static value InvalidHeaderValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HEADER_VALUE = fromString("InvalidHeaderValue"); + + /** + * Static value InvalidHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_HTTP_VERB = fromString("InvalidHttpVerb"); + + /** + * Static value InvalidInput for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_INPUT = fromString("InvalidInput"); + + /** + * Static value InvalidMd5 for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_MD5 = fromString("InvalidMd5"); + + /** + * Static value InvalidMetadata for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_METADATA = fromString("InvalidMetadata"); + + /** + * Static value InvalidQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_QUERY_PARAMETER_VALUE = fromString("InvalidQueryParameterValue"); + + /** + * Static value InvalidRange for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RANGE = fromString("InvalidRange"); + + /** + * Static value InvalidResourceName for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_RESOURCE_NAME = fromString("InvalidResourceName"); + + /** + * Static value InvalidUri for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_URI = fromString("InvalidUri"); + + /** + * Static value InvalidXmlDocument for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_DOCUMENT = fromString("InvalidXmlDocument"); + + /** + * Static value InvalidXmlNodeValue for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_XML_NODE_VALUE = fromString("InvalidXmlNodeValue"); + + /** + * Static value Md5Mismatch for StorageErrorCode. + */ + public static final StorageErrorCode MD5MISMATCH = fromString("Md5Mismatch"); + + /** + * Static value MetadataTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode METADATA_TOO_LARGE = fromString("MetadataTooLarge"); + + /** + * Static value MissingContentLengthHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_CONTENT_LENGTH_HEADER = fromString("MissingContentLengthHeader"); + + /** + * Static value MissingRequiredQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_QUERY_PARAMETER = fromString("MissingRequiredQueryParameter"); + + /** + * Static value MissingRequiredHeader for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_HEADER = fromString("MissingRequiredHeader"); + + /** + * Static value MissingRequiredXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode MISSING_REQUIRED_XML_NODE = fromString("MissingRequiredXmlNode"); + + /** + * Static value MultipleConditionHeadersNotSupported for StorageErrorCode. + */ + public static final StorageErrorCode MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = fromString("MultipleConditionHeadersNotSupported"); + + /** + * Static value OperationTimedOut for StorageErrorCode. + */ + public static final StorageErrorCode OPERATION_TIMED_OUT = fromString("OperationTimedOut"); + + /** + * Static value OutOfRangeInput for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_INPUT = fromString("OutOfRangeInput"); + + /** + * Static value OutOfRangeQueryParameterValue for StorageErrorCode. + */ + public static final StorageErrorCode OUT_OF_RANGE_QUERY_PARAMETER_VALUE = fromString("OutOfRangeQueryParameterValue"); + + /** + * Static value RequestBodyTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_BODY_TOO_LARGE = fromString("RequestBodyTooLarge"); + + /** + * Static value ResourceTypeMismatch for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_TYPE_MISMATCH = fromString("ResourceTypeMismatch"); + + /** + * Static value RequestUrlFailedToParse for StorageErrorCode. + */ + public static final StorageErrorCode REQUEST_URL_FAILED_TO_PARSE = fromString("RequestUrlFailedToParse"); + + /** + * Static value ResourceAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_ALREADY_EXISTS = fromString("ResourceAlreadyExists"); + + /** + * Static value ResourceNotFound for StorageErrorCode. + */ + public static final StorageErrorCode RESOURCE_NOT_FOUND = fromString("ResourceNotFound"); + + /** + * Static value ServerBusy for StorageErrorCode. + */ + public static final StorageErrorCode SERVER_BUSY = fromString("ServerBusy"); + + /** + * Static value UnsupportedHeader for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HEADER = fromString("UnsupportedHeader"); + + /** + * Static value UnsupportedXmlNode for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_XML_NODE = fromString("UnsupportedXmlNode"); + + /** + * Static value UnsupportedQueryParameter for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_QUERY_PARAMETER = fromString("UnsupportedQueryParameter"); + + /** + * Static value UnsupportedHttpVerb for StorageErrorCode. + */ + public static final StorageErrorCode UNSUPPORTED_HTTP_VERB = fromString("UnsupportedHttpVerb"); + + /** + * Static value InvalidMarker for StorageErrorCode. + */ + public static final StorageErrorCode INVALID_MARKER = fromString("InvalidMarker"); + + /** + * Static value MessageNotFound for StorageErrorCode. + */ + public static final StorageErrorCode MESSAGE_NOT_FOUND = fromString("MessageNotFound"); + + /** + * Static value MessageTooLarge for StorageErrorCode. + */ + public static final StorageErrorCode MESSAGE_TOO_LARGE = fromString("MessageTooLarge"); + + /** + * Static value PopReceiptMismatch for StorageErrorCode. + */ + public static final StorageErrorCode POP_RECEIPT_MISMATCH = fromString("PopReceiptMismatch"); + + /** + * Static value QueueAlreadyExists for StorageErrorCode. + */ + public static final StorageErrorCode QUEUE_ALREADY_EXISTS = fromString("QueueAlreadyExists"); + + /** + * Static value QueueBeingDeleted for StorageErrorCode. + */ + public static final StorageErrorCode QUEUE_BEING_DELETED = fromString("QueueBeingDeleted"); + + /** + * Static value QueueDisabled for StorageErrorCode. + */ + public static final StorageErrorCode QUEUE_DISABLED = fromString("QueueDisabled"); + + /** + * Static value QueueNotEmpty for StorageErrorCode. + */ + public static final StorageErrorCode QUEUE_NOT_EMPTY = fromString("QueueNotEmpty"); + + /** + * Static value QueueNotFound for StorageErrorCode. + */ + public static final StorageErrorCode QUEUE_NOT_FOUND = fromString("QueueNotFound"); + + /** + * Creates or finds a StorageErrorCode from its string representation. + * + * @param name a name to look for. + * @return the corresponding StorageErrorCode. + */ + @JsonCreator + public static StorageErrorCode fromString(String name) { + return fromString(name, StorageErrorCode.class); + } + + /** + * @return known StorageErrorCode values. + */ + public static Collection values() { + return values(StorageErrorCode.class); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorException.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorException.java new file mode 100644 index 0000000000000..2459f69111692 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageErrorException.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; + +/** + * Exception thrown for an invalid response with StorageError information. + */ +public final class StorageErrorException extends HttpResponseException { + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + */ + public StorageErrorException(String message, HttpResponse response) { + super(message, response); + } + + /** + * Initializes a new instance of the StorageErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + * @param value the deserialized response value. + */ + public StorageErrorException(String message, HttpResponse response, StorageError value) { + super(message, response, value); + } + + @Override + public StorageError value() { + return (StorageError) super.value(); + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceProperties.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceProperties.java new file mode 100644 index 0000000000000..e13cbde9e5cfb --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceProperties.java @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Storage Service Properties. + */ +@JacksonXmlRootElement(localName = "StorageServiceProperties") +public final class StorageServiceProperties { + /* + * Azure Analytics Logging settings + */ + @JsonProperty(value = "Logging") + private Logging logging; + + /* + * A summary of request statistics grouped by API in hourly aggregates for + * queues + */ + @JsonProperty(value = "HourMetrics") + private Metrics hourMetrics; + + /* + * a summary of request statistics grouped by API in minute aggregates for + * queues + */ + @JsonProperty(value = "MinuteMetrics") + private Metrics minuteMetrics; + + private static final class CorsWrapper { + @JacksonXmlProperty(localName = "CorsRule") + private final List items; + + @JsonCreator + private CorsWrapper(@JacksonXmlProperty(localName = "CorsRule") List items) { + this.items = items; + } + } + + /* + * The set of CORS rules. + */ + @JsonProperty(value = "Cors") + private CorsWrapper cors; + + /** + * Get the logging property: Azure Analytics Logging settings. + * + * @return the logging value. + */ + public Logging logging() { + return this.logging; + } + + /** + * Set the logging property: Azure Analytics Logging settings. + * + * @param logging the logging value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties logging(Logging logging) { + this.logging = logging; + return this; + } + + /** + * Get the hourMetrics property: A summary of request statistics grouped by + * API in hourly aggregates for queues. + * + * @return the hourMetrics value. + */ + public Metrics hourMetrics() { + return this.hourMetrics; + } + + /** + * Set the hourMetrics property: A summary of request statistics grouped by + * API in hourly aggregates for queues. + * + * @param hourMetrics the hourMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties hourMetrics(Metrics hourMetrics) { + this.hourMetrics = hourMetrics; + return this; + } + + /** + * Get the minuteMetrics property: a summary of request statistics grouped + * by API in minute aggregates for queues. + * + * @return the minuteMetrics value. + */ + public Metrics minuteMetrics() { + return this.minuteMetrics; + } + + /** + * Set the minuteMetrics property: a summary of request statistics grouped + * by API in minute aggregates for queues. + * + * @param minuteMetrics the minuteMetrics value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties minuteMetrics(Metrics minuteMetrics) { + this.minuteMetrics = minuteMetrics; + return this; + } + + /** + * Get the cors property: The set of CORS rules. + * + * @return the cors value. + */ + public List cors() { + if (this.cors == null) { + this.cors = new CorsWrapper(new ArrayList()); + } + return this.cors.items; + } + + /** + * Set the cors property: The set of CORS rules. + * + * @param cors the cors value to set. + * @return the StorageServiceProperties object itself. + */ + public StorageServiceProperties cors(List cors) { + this.cors = new CorsWrapper(cors); + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceStats.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceStats.java new file mode 100644 index 0000000000000..d70c794bda65a --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/StorageServiceStats.java @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.storage.queue.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +/** + * Stats for the storage service. + */ +@JacksonXmlRootElement(localName = "StorageServiceStats") +public final class StorageServiceStats { + /* + * Geo-Replication information for the Secondary Storage Service + */ + @JsonProperty(value = "GeoReplication") + private GeoReplication geoReplication; + + /** + * Get the geoReplication property: Geo-Replication information for the + * Secondary Storage Service. + * + * @return the geoReplication value. + */ + public GeoReplication geoReplication() { + return this.geoReplication; + } + + /** + * Set the geoReplication property: Geo-Replication information for the + * Secondary Storage Service. + * + * @param geoReplication the geoReplication value to set. + * @return the StorageServiceStats object itself. + */ + public StorageServiceStats geoReplication(GeoReplication geoReplication) { + this.geoReplication = geoReplication; + return this; + } +} diff --git a/storage/client/queue/src/main/java/com/azure/storage/queue/models/package-info.java b/storage/client/queue/src/main/java/com/azure/storage/queue/models/package-info.java new file mode 100644 index 0000000000000..92606a7993c12 --- /dev/null +++ b/storage/client/queue/src/main/java/com/azure/storage/queue/models/package-info.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** + * This package contains the data models for AzureQueueStorage. + */ +package com.azure.storage.queue.models; diff --git a/storage/client/tests.yml b/storage/client/tests.yml new file mode 100644 index 0000000000000..5e0fa24fa24b7 --- /dev/null +++ b/storage/client/tests.yml @@ -0,0 +1,19 @@ +trigger: none + +jobs: + # When migrating change path to ../../eng/pipelines/templates/jobs/archetype-sdk-tests.yml + - template: ../../eng/pipelines/templates/jobs/archetype-sdk-tests-pre-sdk.yml + parameters: + # When migrating use ServiceDirectory + PomFilePath: './storage/client/pom.xml' + EnvVars: + AZURE_TEST_MODE: RECORD + MICROSOFT_AD_TENANT_ID: $(microsoft-active-directory-tenant-id) + PRIMARY_STORAGE_ACCOUNT_NAME: $(java-storage-test-primary-account-name) + PRIMARY_STORAGE_ACCOUNT_KEY: $(java-storage-test-primary-account-key) + SECONDARY_STORAGE_ACCOUNT_NAME: $(java-storage-test-secondary-account-name) + SECONDARY_STORAGE_ACCOUNT_KEY: $(java-storage-test-secondary-account-key) + BLOB_STORAGE_ACCOUNT_NAME: $(java-storage-test-blob-account-name) + BLOB_STORAGE_ACCOUNT_KEY: $(java-storage-test-blob-account-key) + PREMIUM_STORAGE_ACCOUNT_NAME: $(java-storage-test-premium-account-name) + PREMIUM_STORAGE_ACCOUNT_KEY: $(java-storage-test-premium-account-key) \ No newline at end of file diff --git a/storage/data-plane/pom.xml b/storage/data-plane/pom.xml index de02bb38fb1be..ef4ccc0aaa710 100644 --- a/storage/data-plane/pom.xml +++ b/storage/data-plane/pom.xml @@ -9,7 +9,7 @@ com.azure azure-data-sdk-parent - 1.0.0 + 1.1.0 ../../pom.data.xml diff --git a/swagger_to_sdk_config.json b/swagger_to_sdk_config.json index d2bc472803309..1b0a2eeef2adc 100644 --- a/swagger_to_sdk_config.json +++ b/swagger_to_sdk_config.json @@ -1,11 +1,18 @@ { + "$schema": "https://openapistoragetest.blob.core.windows.net/sdkautomation/test/schemas/swagger_to_sdk_config.schema.json", "meta": { "autorest_options": { "java": "", "verbose": "", "sdkrel:azure-libraries-for-java-folder": ".", "multiapi": "", - "use": "@microsoft.azure/autorest.java@2.1.85" + "use": "@microsoft.azure/autorest.java", + "regenerate-manager": "", + "fluent": "" + }, + "advanced_options": { + "create_sdk_pull_requests": true, + "sdk_generation_pull_request_base": "main_branch" }, "version": "0.2.0" }